diff --git a/src/doors/clans-devkit/ARMY.HLP b/src/doors/clans-devkit/ARMY.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..da683385adcbeae5391e3e3757207802fc44c3bb
--- /dev/null
+++ b/src/doors/clans-devkit/ARMY.HLP
@@ -0,0 +1,79 @@
+^Footmen
+|0B Footmen
+
+|0C Footmen are your main source of troops.  Because of their low cost, you
+ will usually have more of these than the other kinds of troops.
+
+ Speed:     Average
+ Offense:   Average
+ Defense:   Low
+ Vitality:  High
+
+|0B Each footman costs 15 gold to train.
+^END
+
+^Axemen
+|0B Axemen
+
+|0C Axemen are a strong type of troop but are very slow.
+
+ Speed:     Low
+ Offense:   High
+ Defense:   Below Average
+ Vitality:  Above Average
+
+|0B Each Axeman costs 30 gold to train.
+^END
+
+^Knights
+|0B Knights
+
+|0C Knights are the quickest troops but are the poorest defensively.
+
+ Speed:     High
+ Offense:   Very High
+ Defense:   Very Low
+ Vitality:  Above Average
+
+|0B Each Knight costs 60 gold to train.
+^END
+
+^Army Rating
+|0CArmy Rating can be thought of as the potential of your army.  100%
+means they are able to do as much damage as possible while 50% means
+they can only do half their regular damage.  Each attack will cause the
+army rating to decrease.  Using a larger army for an attack will cause
+the army rating to decrease substantially.  Therefore, it is advised
+that you keep your attacking armies small.
+
+|0B* Each day, the army rating increases from 5 to 10%.  More Gyms built will
+ increase this value.
+^END
+
+
+^Speed
+|0B Speed
+
+|0C The speed of the army dictates how quickly they can deliver attacks and how
+ quickly they can dodge blows.  With two armies of equal strength, the quicker
+ one will always win.
+^END
+
+^Offense
+|0B Offense
+
+|0C The offense of the army is how well it can attack the opponent.
+^END
+
+^Defense
+|0B Defense
+
+|0C The defense of the army is how well it can defend against the opponent.
+^END
+
+^Vitality
+|0B Vitality
+
+|0C The vitality of the army dictates how much energy an army has before being
+ defeated.
+^END
diff --git a/src/doors/clans-devkit/BUILD.HLP b/src/doors/clans-devkit/BUILD.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..f4272818216b06d2e3ec09b580ef035260bb27b5
--- /dev/null
+++ b/src/doors/clans-devkit/BUILD.HLP
@@ -0,0 +1,2 @@
+^dude
+^END
diff --git a/src/doors/clans-devkit/BULLETIN.HLP b/src/doors/clans-devkit/BULLETIN.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..a44e84c66cbe026f16c0198736e11add5541192c
--- /dev/null
+++ b/src/doors/clans-devkit/BULLETIN.HLP
@@ -0,0 +1,458 @@
+^New in v0.93
+What's new in v0.93
+-------------------
+* Remember:  School comes first.  And right now, I'm really busy with it...
+  (I'm carrying a full course load --> 6 courses --> 3 weekly assignments,
+  right now I've done 3 midterms with 3 more on the way. --> lots of stress
+  --> lots of fatigue --> little time to program)
+- fixed problem with game updating world.dat incorrectly
+- nodefile should now be opened using _fsopen (SHARE.EXE used)
+- fixed army rating truncating caused by too many gyms
+- changed a couple prices of books and raised a couple of books up a level
+  (so they require wizard shops of higher levels)
+- created LOCKOUT.TXT file to lock out users
+- fixed negative gold bug in empire wars
+- you can no longer attack your own alliance
+
+What's new in v0.91b2
+---------------------
+- Fixed up QUESTS.INI so it doesn't have temporary test quest "Stupid Quest" :)
+- found bug in code where memory overlap occurred after combat -- LIKELY (90%
+  chance) where the "garbage items" problem was coming from!  Fixed!!
+  -- actually, looked at code more and founds many instances of strings in
+     the language file which COULD have exceeded the string length used in
+     some functions had certain %s and %d's become too long (C programmers
+     should know what I'm talking about) -- awful, Awful, AWFUL!
+- fixed bug where as soon as you hit F to fight to death it'll make your clan
+  run away.  Has this EVER happened to anybody?  Only noticed it after a
+  compiled recently...  email me if it has.
+- fight to death no longer asks "Fight to death?" -- immediately does it now
+- minor code changes:
+        - properly released mem if no monster with correct level found
+        - ChooseDefaultAction() uses [41] for *szOptions[] now -- was [20]
+- removed /U (Upgrade) from command line help
+- fixed bug where /Tx would screw up
+- game will now fix it so if item is screwed up and owned by a garbage user,
+  it'll be set to no one in the maintenance
+- owners of garbage items will have the offending items released from use
+  as well
+- users and alliances no longer allowed to use ? as the first character in
+  their names.  If a user has this in their name as the first character already
+  before the upgrade, it will be changed to a ! in the daily maintenance
+- fixed bug of church and praying event files in new installs
+- fixed bug with negative vitality in armies
+- data changes:
+       - barbarian gets +1 str
+       - made incapacitate spells slightly weaker
+       - conscription can only go as high as 20% now
+- `ab colour codes now allow "a" to go from 0 to F (background)
+- scorefile now displays clan symbols with COLOUR!
+
+
+What's new in v0.91b1
+---------------------
+*** Read UPGRADE.DOC PLEASE! ***
+* Japan was amazing.  Check out the details on my web page. :) -- maybe soon
+- FINALLY added feature which automatically distributes WORLD.NDX files
+  -- all the LC needs to do is type the following after creating a new
+  WORLD.NDX file:
+
+        CLANS /NewNDX
+
+  The file will be sent through CLANS's packet system.  It's a neat way of
+  getting a message across too (just put some info in the "Ascii" section of
+  the WORLD.NDX before sending it out).
+- fixed bug in ECOMP.EXE which would cause it to hang on event files which
+  had lines longer than 100 chars
+- fixed problem with EComp.EXE which would prevent it from displaying pound (#)
+  characters that appeared after a quotation mark (")
+- fixed minor wording bug in army help that had "Offense" as title for
+  "Defense" help
+- fixed bug which would hang system if scorefile was not indicated in CLANS.CFG
+- "cleaned up" initialization procedures -- more efficient and less prone to
+  errors now
+- because of the previous fixup (see above), you can now use an external
+  language file instead of my own.  If you want the strings file, email me
+  and I'll give it to you.  I didn't include it here because it would just
+  add more space to the archive.  You'll need the language compiler too.  I
+  may release the two together, actually...  ... then again, i'll probably
+  release the language file in v1.00 since there may still be a few new
+  strings to add...
+- fixed bug in choosing which quest you want to do -- would screw up on
+  certain occasions
+- added a few new ANSIs (anime-like 'cause I've been drawing quite a bit
+  lately -- based on Shirow Masamune's work!)
+- fixed bug where if you had over a certain amount of cash, it would not let
+  you develop *any* land
+- rewrote some NPC code to allow them to be added to PAK files.
+  - because of the new code, the /U upgrade feature for the Clans is no longer
+    needed
+- got rid of schemes.txt (now inside .pak file)
+- made game update packet file names in maintenance so that even if a packet
+  existed one day, the next day it would not be appended to (prevents "dead"
+  packets from continually being appended to)
+- I added a pretty cool secret in the game but it's not finished yet.  Here's
+  a hint:  What character in the Prisoner would change from week to week?  Or
+  else what does the Japanese word "ni" mean in English?
+  (The really cool part is it's "coded" entirely in the event file language.
+  It's sort of a mini text adventure game.)
+- if user is online and using node #1, a CLANS /I, /O, or /FM will no longer
+  cause their respective functions to be run (this is how it SHOULD have worked
+  before but it didn't)
+- players who are voted for and then delete themselves will no longer be listed
+  in voting booth -- you know what I mean...
+- smithy is shown as level 5 now when at its max and not level 6
+- resetting now removes the disband.dat file
+
+        -- for the next version:
+                - wandering NPCs (from village to village)
+                - a way to use external event files as "buildings" and a way
+                  for it to be used so that all boards in a league are forced
+                  to use the same ones
+- fixed bug which would not remove the colour codes from a string like "|12|16"
+  properly
+
+
+What's new in v0.90b2
+---------------------
+- made game give less experience for the killing blow
+- fixed big problem with packets which would cause them to reset a village's
+  data (to all 0's)
+- incorrect village empire war results fixed
+- fixed bug where village empire attacks per day was not recorded if attacking
+  another village
+- fixed MAJOR bug which occured when the user file was larger than 64k.  It
+  would cause new users to corrupt the user file.  Fixed other parts of the
+  program where the 64k limit was as well so it may solve other problems
+  encountered.
+- game no longer allows +3000 land for empires
+- fixed bulletin files (see CLANS.CFG to configure them) so the display is
+  cleaner
+- added a bit of help on Protection for people who didn't quite understand
+  what it did in the newbie help
+- made it so long fights force the user to run away if fight to death is
+  chosen to prevent endless battles
+- fixed problem where alliances were not displayed properly (if none were
+  found, the user would be displayed a blank line instead of "No Alliances"
+- fixed bug where alliances were not all freed up from memory when reset was
+  done
+- recoded part of the fighting routines (no change in formulae, but more
+  efficient and likely less buggy -- i.e. FightToDeath)
+- WORLD.NDX Asciis are no longer left-justified
+- changed some structure energy-values
+- pawn shop item listings now pauses after 60 items are shown
+
+What's new in v0.90WB
+---------------------
+* note: the only way to fix the fight-to-death bug where the fight goes on
+  endlessly is to reset your game -- the problem persists since the item
+  stats are too out of whack (because of the market in the older versions).
+  A reset will fix it so users' items don't have such high stats and will
+  make the fights shorter
+- shops don't show up when building in empire
+- hero's armor should now be useable
+- upgrade (/U) option will no longer give an error if no WORLD.NDX is found
+  for local games
+- See SPECIAL.DOC for a special deal on registering my doors.
+- Online credit card registration is now available!  See PLASTIC.DOC for info
+  on how to register using your credit card.
+- changed string so it says followers are "recruited" not "taken" away
+- some new races and classes have been added...
+- fixed memory bug caused in (V)iew Clan Stats/(A)lliances when in the
+  alliances menu (what I would regard as a major bug)
+- healing doesn't heal huge amounts any more (just because the user is at a
+  high level)
+
+What's new in v0.89b5
+---------------------
+- fixed bug where game would give an "Out of memory" error for packets of 0
+  length
+- max number of BBSes in a league reduced to 100 (was causing mem errors at
+  255)
+- finally figured out why game was sending to 0:0/0 addresses and creating
+  junk packets like CL00?000.??? -- HUGE problem fixed!
+- increased cost of upgrading some stuff
+- removed /Debug option
+- spells are de-hilited if you don't have enough SP to cast 'em
+- removed Interest Rate from village stats
+- items no longer give "bonus" stats if they weren't intended to have them
+  (if i set an item with +0 STR originally, it ain't gettin' any more when
+  you buy it from the shop)
+- spells are successful a bit more
+- made it easier to win empire wars
+- user stats was showing the wrong number of XP required...
+- fixed "Out of Memory" error caused when attacking an empire with no buildings
+  erected
+- fixed bug where what you destroyed was not shown
+- choosing extent of army attack is gone, let's see how people like it....
+- super items harder to get
+- level ups require more XP -- it was way out of hand in previous versions
+- enemy will now attack member with lowest energy twice as often as previous
+  versions.
+- members not in the alliance are only ones listed when inviting them
+- score listings now say "Dead" if clan has no living members
+- made "smart input" have wider spaces for topic listings
+- alliances are now maintained properly (worker energy replenished daily)
+- game no longer replenishes skill points after clan combat (was a bug)
+- upgrading (CLANS /U) should no longer remove members 5 and 6 if they are
+  permanent members
+- main menu used to say (B) Bank, now it's gone
+- made monsters tougher
+- game gives less gold now. :)
+- removed memory leak caused by score generation (IBBS)
+- fixed another memory leak caused when creating a new chatfile
+- fixed memory leak caused by IBBS processing
+- forgot to mention, IBBS.LOG is kept but fairly useless unless your name is
+  Allen.
+- decreased the stack size back to 8k..
+
+
+
+What's new in v0.89b4
+---------------------
+- added pirate class, more on the way, give me some class ideas and i'll put
+  them in
+- got rid of random event with salesman in mines
+- being ruler should now give only 25 points per day
+- if xp < 0, it will be set to what it should be at maintenance
+- instead of saying what class/race a character is when equipping something,
+  it'll say what he's already using
+- who you're voting for now displayed
+- removed (/) option in wizard's shop
+- fixed memory leak introduced by random item finds in the mines
+- increased the stack size again
+- when looking at another clan's stats, game should pause on each member now
+- reduced cost of resurrections
+- fixed bug with trading
+- made Pirate and Useless Old Man not "seeable" each day (decreased
+  OddsOfSeeing value from 100%)
+- game gives more gold
+- removed stupid and useless "Trust No One" event
+- reduced items taken after combat to only 2 (one guy on my board
+  was stealing all my stuff!)
+
+What's new in v0.89
+-------------------
+* THIS IS NOT A WIDE BETA, do not distribute through networks and such but
+  if you are in a league, be sure to have EVERYONE upgrade to this version
+* YOU MUST RESET YOUR CURRENT GAME TO USE THIS VERSION!  If you're in a league,
+  the whole league must be reset and everyone in the league must use this
+  version.
+
+  If you are the league coordinator in a league, have all nodes upgrade
+  to this version and do a CLANS /RESET and choose "Join a league".
+  This step MUST be done!  (The LC does not choose "Join a league".)  You
+  will then run CLANS /RESET and choose leaguewide reset. If the
+  individual nodes do not do a CLANS /RESET, problems will arise.  You
+  have been warned.
+
+- nicer looking item statistics screen
+- items are even more behaved in terms of stats
+- fixed bug where game would crash if traveling to another village which had
+  no info in VILLINFO.TXT
+- fixed problem with reading .HLP files (which are within CLANS.PAK)
+  - it would freeze on some files -- never happened in previous version but
+    problem was always there (ok, maybe it happened on some people's systems)
+- user clan member names can only be 12 chars long now (although monster names
+  can still be up to 19 chars long)
+- added Scrolls and Books
+- clans.ini should be fully useable now (except language file is always
+  strings.xl, can't change this even though it's in there)
+- item energy scrapped
+- items can now be taken from another clan after combat.  A maximum of 4
+  items can be taken. (configurable later?)
+- upgrading of market brings in some new items now.
+- "View Combat Sta" -> "View Combat Stats" in combat
+  - then later taken out ;) (see below)
+- added a pawn shop to buy/sell used goods
+- overhaul of event files and quote files (for 3rd time)
+  * they are now compiled.  Get CDEV004.ZIP (Clan Dev Kit v0.04) and compile
+    any event files you made before (if you made any) using ECOMP.EXE
+  * A lot faster when chatting with NPCs and a lot faster when going on
+    quests, random events etc.
+  * also found bugs with old method of reading in event files so this may
+    fix those problems as well
+- items only use memory when they need to, unlike before where it was always
+  loaded...  this should free up more memory
+- INTL flag is now always used for mail packets (IBBS)
+- maintenance should now be run right away when /I or /O is used
+- random treasure chests encountered in the mines... they contain items..
+- 10 to 13 training points given per level-up
+  - however, training halls require 10 tpoints per attribute minus level of
+    training hall (so level 5 training halls only require 5 tpoints per
+    attribute!)
+- old alliance system abolished. :)  It was replaced with something similar
+  to the clan halls (but without passwords).  Clan halls are gone too.
+- Elimination mode now sent through IBBS properly
+- backing up a line in message entering is now allowed!
+- disbanded clans cannot play until the next day (prevents cheating)
+- cost fluctuations occur each day instead of each time you buy an item
+- smithy sometimes makes super items. these are denoted with a + after the
+  name; they have better stats but same requirements
+- costs 25% of item cost to view its stats
+- Village info overhauled:
+  - removed useless "Population" stat (for those interested, it was simply
+    used as a bonus for followers received after fighting)
+  - town guards removed
+  - businesses, farms, mines, removed -- the empires take its place
+  - removed rebel menu, most of the stuff you do there is possible through
+    alliances
+  - crime variable removed
+  - approval removed -- replaced with clan voting
+  - added system of gov't: democracy (allow clan voting) or dictatorship (no
+    voting).  In the future, more features may be added corresponding to the
+    type of government chosen.
+- no more bank, all gold is kept in the "empire" and can be stolen from other
+  empires (increased competition)
+- gold can no longer be stolen from an enemy clan in a regular fight
+- fixed problem where game would not detect duplicate clan name when
+  the first user entered the game
+- you can write messages from one village to another!!  This is very nice and
+  I was surprised at how easy it was to do...
+- fixed bug where writing message and aborting would not free up memory used...
+- it now will say if the ruler lowered/raised the taxes and what they were
+  before in the daily news
+- you can no longer toggle the InterBBS flag in the clans.cfg file and do the
+  daily maintenance and switch back...
+- if WORLD.NDX file (or WORLD.id where id= league id) found in inbound
+  directory, it will be used as the new WORLD.NDX file for the game.
+- minor change made to AI in combat, spells are used by enemy slightly more
+  often
+- added new command to scripts, "Input", can be used to replace Option command
+- more options in reset
+- you can no longer release a perm. member, get an NPC and keep him.  I
+  don't think anybody knew this was possible (it's a bug) but it's fixed
+  anyway.
+- protection is ALWAYS set now
+- clan voting replaced the old approval system, with clan voting, each clan
+  can choose who they think should be the leader and at the end of the day,
+  the clan with the most votes gets to rule.  However, the ruler can switch
+  to a dictatorship gov't so voting isn't allowed.  But they can be ousted
+  through an empire attack..
+- reg is $20CAN b/c that approximately equals $15US.
+- maintenance is skipped if user online (done automatically later)
+- if a reset was not properly received by a BBS, you can now resend it using
+  the /SendReset X command where X is the BBSID of the BBS which you wish
+  to send the reset to.
+- strings.xl now can contain up to 2000 strings (even the structure is
+  allocated memory now)
+- a clan from another village is now shown as "Visiting" instead of "Here"
+- item equipping is more intuitive.  If a member of the clan is equipping a
+  new item and he is already equipped, the game will ask whether you wish to
+  unequip the old item first.
+- Quests known and done are not carried over when traveling to another village
+  now.  This way, you will know different sets of quests for each village.
+- undead raised by higher up characters have more HP than those below them
+- quests are displayed better now.  The first one is always (A) and the second
+  is always (B), etc.
+- fixed problem where all NPCs would appear each day for some reason.  No,
+  they are not ALL supposed to appear each day.  They are supposed to appear
+  randomly day to day.
+- you can no longer "trade" your troops so that you go over the limit of
+  troops for the buildings you have (sneaky cheat)
+- made a few cosmetic changes here and there
+- new feature: conscription -- needed for new empire system
+- added "skip" feature in combat to pass a move (so a certain member can be
+  given the killing blow xp)
+- removed View Combat Stats from combat (did nothing)
+- game now pauses after 20 lines when showing the top scores
+- added ugly vanilla status line (use /UglyStatus) to see if BBSes which see
+  negative time have a better time with it
+- level of church now determines how many resurrectons it will allow to each
+  clan each day
+- new clans cannot trade until after the first day they play (prevents
+  cheating)
+- fixed a huge bug which was likely causing all the memory problems many have
+  encountered.
+- removed "AnnoyLord" option in clans.cfg (calm down, it did nothing!! <grin>)
+- you can now use Telegard style colour codes (`).  Use `XY where X is the
+  background colour, Y is the foreground colour.  Both are in hexadecimal.
+  `4F for white on red...
+- Clan Symbols can be up to 20 chars long and have colour codes in them.
+- less followers are given after battle
+- followers are no longer given for regular clan vs. clan fights
+- which monsters appear and how many has changed slightly
+- gold rewarded is calculated differently
+- items cost less
+- fixed HUGE bug where a user would delete himself and the game was not
+  deleting trades properly
+- temporary members can no longer be released through the training hall
+^END
+
+^Revolution Nine
+ |02Revolution Nine is the home BBS of Ashrella, VHunt, and The Clans.
+
+ |15( |074 o 3 |15) |094 3 3  7 3 0 4
+
+ |10Call it now!
+^END
+
+^Ashrella
+%N%T
+`00`07    `0D苒`5D膊卑鞍`05哌哌哌哌哌哌卟哌哌哌哌哌哌哌哌哌哌哌哌哌違58癭05圻哌哌違58癭05圻哌哌哌圹`58癭05圻`08躟07
+`08    `0D踐5D膊北氨`07 `04躟4C癭04圻`48癭07 `0C躟4C卑`04圻`48氨`07 `0C轥4C脖`04苘`48盽04� `0C轥4C盽04違4C卑`04� `0C轥4C脖癭48癭04� 轥4C癭48癭04�   轥4C癭48癭04�    躟4C癭04圻`48癭07 `58癭05踐58癭05圹`58癭08踐07
+`08    `5D膊卑癭05� `04踐4C癭48癭04苘`48癭04� `0C違04違48癭04圮  `4C脖`04咿`4C癭48癭07  `4C癭04踐48癭4C癭48癭04� `4C脖癭04�   `4C脖`04�    `4C脖`04�    踐4C癭48癭04苘`48癭04輅05捋踐58癭08違58辈`07
+    `0D踐5D舶氨`07 `4C脖癭04� `4C癭04圯   躟4C鞍`04輅0C轥4C卑`07 `4C卑`04� `0C轥4C卑`04違4C癭04� `0C轥4C盽04圻   `0C轥4C卑`07    `0C轥4C卑`07    `4C脖癭04� `4C癭04圯`05轥58癭05踐58氨膊`07
+`08    `5D膊盽05圯`0C轥4C脖`04� `0C轥4C卑`07 `0C躟4C膊卑`04� `4C脖`07 `0C轥4C脖`07  `4C脖癭0C轥4C卑`04輅4C脖癭04圹� `4C鄄卑`04圮 `4C鄄卑`04圮`0C轥4C脖`04� `0C轥4C卑`07 `05苒`58癭08躟58瞏08圻`07
+`08    `0D違05躟5D鞍`05苘苘躟5D癭05苘苘苘苘苘苘苘苘苘曹苘苘苘苘苘苘� 苘苘苘苘苘苘苘苘`58癭05苘 躟58鞍辈`08圮違07
+
+`08    `0EAre you sick of the same old pathetic rehashes of other RPG doors?  `03Are`07
+`03    you tired of trying a new game only to find it is just another throwaway`07
+`03    which is hardly worth your time?  Well, it's time to play Ashrella then!`07
+`03    Unlike other games,  Ashrella is beautifully crafted  and  has  a  large`07
+`03    array of options built in.    In fact, if you wanted, you could download`07
+`03    the game and create your own additions easily!   Not only that, its long`07
+`03    adventure is breathtaking.    Not only will you traverse the calm Indigo`07
+`03    Valley,  but you will eventually fly up in the sky with a dragon beneath`07
+`03    you.   After playing Ashrella, you'll know what other RPGs lack:  Style.`07
+
+`09    `0D苘躟5D盽05苘苘`5D癭05苘苘苘懿苘苘苘苘苒苘苘苘 苘苘曹苘苘苘苘苘苘苘� 苘苘 苘苘苘苘躟58盽05躟07
+`05    `0D違5D瞏05躟5D脖癭05圻`5D盽05圹踐5D癭05圹圹圹`5D癭05圹圹槽`5D盽05圹圻圹圹圹圹圹`5D癭05咣`58癭05圹圹苒圹圹`58癭05圹圹踐58盽05苒圹`58盽05違58氨瞏05違07
+
+^PAUSE
+%C|14Ashrella
+
+|03After you finish playing The Clans, play Ashrella + VHunt!
+        http://www.ualberta.ca/~ussher/txds.htm
+%N
+^END
+
+
+^VHunt
+`00`07 `0C苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘`07
+`0C `4C舶違04踐4C`04哌哌哌`4C卟边弑哌`04圻哌哌咣`4C脖癭04圹`4C卑`04圻哌哌咣`4C安哌違04圹圻哌哌哌哌咣`4C哌策哌`04哌哌踐4C策边 `07
+`0C `4C癭54脖瞏04圹    `01� `54瞏5D鷃07 `09�  `01� `54瞏07   `09懿 `54脖`07  `01�   `54瞏07  `09� `01� `54瞏04踐07      `04� `01�  � `54瞏04�    違54脖`04�  `09�  `04哌踐54瞏04踐54瞏07
+ `54北`05圹`54盽04� `01� �  `05踐5D輅07  `01  `54瞏07 `09�  � `54卑`07 `01�  � `54盽07 `09鷃01苘� `54脖`07 `01� `09�  `54瞏07 `01� �  `54膊`07 `09�  `01� `54盽07 `01�  � `54卑氨膊`07
+ `54癭05踐5D違54癭07 `19哕`01哕 `05踐5D輅07 `19癭07 `01�  `54盽07 `01哌苒 `05哌 `19癭01� � `54癭07 `01咣`19癭01� `54舶`07  `01哕`19癭07 `54盽07 `01�  � `54辈`07 `01�    `54盽07 `01脖苒 `54癭05圹`54氨瞏07
+`04 `05圹`5D圹`05圹 `01哕`19懿`07 `5D轥05� `01圮�  `54癭07 `01踐19違09躟01� `05踐54癭07 `01踐19甙`01� `05� `01圻踐09� `05踐54盽07 `19盽01躟19癭01� `54癭07 `19癭01躟19癭01� `54卑`07 `19癭07 `01懿 `54癭07 `01圻躟19癭07 `05踐5D躟05踐54盽07
+`04 `05踐5D圹輅05圹 `19佰脖`07 `5D掭`07 `19氨脖`07 `05� `19盽01踐19苓`07 `5D鷃05� `19鼙`01踐19違07 `05� `19氨`09躟01� `05圹 `01躟19安盽07 `05� `19辈`01哕 `5D鷃05� `19盽01躟19癭01� `05� `19氨`09苓 `05圹`55 `5D草`05踐07
+`05 `5D槽咣`05圹 `01違19槽瞏07 `5D掭`07 `19槽鄄`07 `5D㤘07 `19鄄鄄`07 `5D轥05� `19瞏09哕`19瞏07 `05� `19瞏09踐19瞏09� `5D盽05� `19辈盽09� `05� `19瞏09躟19瞏09� `5D轥05� `19脖瞏09� `05� `19辈辈`07 `5D圹圯`07
+`0D `5D圹鄄圮`05圮 `09違19踐07 `5D掭`07 `19踐09圻 `05躟5D轥07 `19瞏09圹� `5D轥05� `09苒`19瞏09� `5D鷃07 `09違19瞏09圹 `5D猖`07 `19瞏09圹� `05� `09圹圹 `5D轥05� `09圻苘 `5D鷃07 `09咣`19瞏09� `05哌`5D捋圹`07
+ `5D郾圹圹圮`05圮� 哌  苘`5D懿輅05苘苘苘`5D轥05� `09哌哌 `5D轥05圮� `09� `0D哌 `09哌� `05苒苘苘苘`5D掭`07 `09哌哌 `5D轥05圮 `09哌 `05躟5D懿圹瞏07
+ `5D槽圹鄄圹鄄圮苘苘苒圹圹圹圹郾苘苘苘懿圹苘苘苘苘苘苘圹圹鄄圹圮苘苘懿圮苘苘圹圹盽0D踐07
+`0D `06� `0FV  I  R  T  U  A  L    H  U  N  T  `09哪哪  `0FV  I  R  T  U  A  L    H  U  N  T `06躟07
+`06 踐07                                                                            `06踐07
+`06 � `0EVirtual Hunt is here!  A brand new door game until any other.  Played in   `06踐07
+`06 � `0Ereal time, this game offers action and strategy.  Walk around in a virtual `06踐07
+`06 � `0Eworld and hunt out several artificially intelligent computer players.  Or  `06踐07
+`06 � `0Etry to complete a quest in real time.  Tired of RPGs or war games?  Play   `06踐07
+`06 � `0EVirtual Hunt today!`07                                                        `06踐07
+`06 圮苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苘苒`07
+        http://www.ualberta.ca/~ussher/vhunt.htm
+^END
+
+^Coming Soon
+|14Here are some features which may or may not appear in The Clans.  They
+are being considered, however:|06
+
+ * Roaming NPCs.  NPCs that travel from village to village (in a league)
+ * Village Scenarios.  Sysop will choose from a list of village scenarios
+   such as a port town, prairie village, etc.  Each type of village will
+   have some unique races and classes and other options.  This will help
+   vary villages from BBS to BBS in leagues.
+ * If a user is online and someone tries to play, the waiting party may
+   play a really cheap game and also be able to send a message to the
+   person that is in the game playing.
+ * New races, classes, and equipment.
+^END
+
diff --git a/src/doors/clans-devkit/CHURCH.EVT b/src/doors/clans-devkit/CHURCH.EVT
new file mode 100644
index 0000000000000000000000000000000000000000..02626e80cf0da8ef0865e1e2abd08fdf71b40929
--- /dev/null
+++ b/src/doors/clans-devkit/CHURCH.EVT
@@ -0,0 +1,44 @@
+# events that occur when you go to mass
+
+# different church things happen:
+#
+# singing makes you rejoice
+# the sermon touches you
+# the collection plate is passed to you, how much do you give? -- gain something
+#   -- steal from it -- lose fights -- says in news
+# old man talks to you, tells you of a quest? -- monster down in a well
+
+Event Nothing
+Text "|10Sadly, the mass you attend fails to do anything to you or your clan.
+End
+
+Event Followers
+Text
+Text "|07Several villagers notice your presence in the mass and decide to join your
+Text "following!
+Text
+Text "|03(You gain 20 new followers!)
+GiveFollowers 20
+End
+
+Event GainGold
+Text
+Text "|07The priest notices you and decides to donate 100 gold to your cause as he
+Text "feels you have been doing great things for the village.
+GiveGold 100
+End
+
+Event GainFights
+Text
+Text "|07The priest delivered such a powerful speech that you feel energized and
+Text "ready to fight some more.  |03(You gain two monster fights.)
+GiveFight 2
+End
+
+Event Feelbad
+Text
+Text "|07The priest delivers a sermon which makes your clan feel terrible.  You feel
+Text "remorseful.  |12You lose 20 points.
+GivePoints -20
+End
+
diff --git a/src/doors/clans-devkit/CITIZEN.HLP b/src/doors/clans-devkit/CITIZEN.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..91428590be8d97f3906c084f62718f0ad0fbcc43
--- /dev/null
+++ b/src/doors/clans-devkit/CITIZEN.HLP
@@ -0,0 +1,25 @@
+^Deposit into Vault
+
+ |0CThis allows you to deposit gold into the village vault.  This gold can be
+ used by the ruler to add onto the town.
+
+^END
+
+^Voting Booth
+ |0CThe voting booth allows you to vote for the clan which you think will rule
+ best.  At the end of the day, a new ruler is chosen from the top votes.  Of
+ course, if the town is under dictatorial rule, voting is disabled and the
+ current ruler will continue to reign unless ousted through an empire war.
+^END
+
+^Write to Ruler
+
+ |0CUse this option to write a message to the current ruler.
+^END
+
+^Public Discussions
+
+ |0CThis is a an area where all users can discuss with one another the town's
+ dealings.
+^END
+
diff --git a/src/doors/clans-devkit/CLANS.HLP b/src/doors/clans-devkit/CLANS.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..9c966954b80e28dedb3b253e022f2cb519f59ea7
--- /dev/null
+++ b/src/doors/clans-devkit/CLANS.HLP
@@ -0,0 +1,137 @@
+^Instructions
+%N%T
+ |0BObjectives of The Clans
+
+ |0CBasically, the object is to destroy the competition.  There's no "goal"
+ as in other games so you can continue playing as much as you want.  The
+ leaders will change, the alliances will change, and your clan will see
+ several new members, but the object will always be to become the top clan
+ in the game.  If your sysop has hooked up the game to an InterBBS league,
+ then the object may be to strengthen your village and attack other villages
+ in the league.  There are also quests to be completed!  The main ways of
+ achieving success are these:
+
+ * Defeat monsters in the dungeons to collect gold and followers.
+ * Complete quests.
+ * Increase the size of your empire.
+ * Annihilate enemy clans in empire wars and loot their land and gold.
+ * Create alliances with other clans.
+ * Become ruler of the village.
+
+ |15Good luck on your journey!
+%N
+^END
+
+^Newbies
+ |0BWelcome, new player!|0C
+
+ You will find clans very self-explanatory and easy to play as help is
+ displayed for most new options you will encounter.  Remember that this
+ game is played on many levels and never stop strategizing!
+^END
+
+^Colours
+ |0CUse pipe codes (|) for colours.  Simply type the pipe code and then a two
+ digit value representing the number:  |xx (where xx is the two digit value).
+ Example | %B15 for |15white|0C.  TG ` codes can be used as well.  Use `xy
+ where x is the background colour (0 to 7) and y is the foreground colour
+ (between 0 and F hexadecimal).
+^END
+
+
+^Welcome
+%C%N
+`00`0B `05圻哌哌哌圮圹圻圹圹圹圹圹圹苒圻圹圹圹圮圹`5D癭05圹`5E盽05圹圮 `03苘`0B
+`03 `05� `0D�   � 苘� �  苘 苘� 苘苘� 苘� `5D癭05咣`5E癭05圹圻圹圹哌圹 `03轥3B瞏03踐0B     `06苘苘苘`0B
+`06 `05� `0D�   � 圮  �  �  � � � � � 圮`0B                 `05� `03圹`3B瞏03�  `06轥6E脖`06圹圹圹輅0B           `03躟0B
+`03 `05� `0D圮圮� 圮� 圮 圮 圮� �   � 圮躟0B                `05� `03圹`3B盽03圯`06轥6E氨`06圹圹圹圹`0B       `03苘`3B盽03踐3B癭0B
+ `05� 躟0B                                            `05� `03捋踐3B癭03輅06捱 `07苘 `06哌咣`68癭0B    `03苒`3B氨瞏03圹踐0B
+`03 `5E癭05圹 `07Welcome to `0EThe Clans`07.  The object of this  `05圯`03捋踐3B癭03� `06輅07圹圹圹 `06圹�  `03捋`3B瞏03圹圹圹`0B
+`03 `05圹� `07game is to build up a powerful  苘�  clan, `05圯 `03圹踐3B癭0B `06輅07咣圹圻 `06圹`68癭0B  `03踐3B瞏03圹圹圹踐0B
+`03 `05圹� `07create an empire and destroy    咣圻 躟0B     `05圹� `03哌 `06轥6E癭06� `07� � `06捋`68氨`06� `03咣圹圹圹`0B
+`03 `05咣`5E癭0B `07all competition.  Be sure to look `02苒`2A癭02� `07at  `05圹� `02哕`2A癭02圮 `07苒圹� `02� 苘�  `03圹葸`0B
+`03 `5D盽05圹 `07the help database for info on`0B      `02� `07苘`0B     `07苘圮 `02圹哕苘 苘苒圹� `7F盽07� `03踐0B
+`03 `05圹� `07on specific parts of the game.`0B      `07違7F癭07圹� 躟7F盽07圹`7F癭07�  `2A盽02圹踐28癭02踐2A氨`02圹苘 `07踐7F氨`0B `03輅0B
+`03 `05圹苘苘苘苘� 苘苘苘苘 苘� 苘苘苘苘苘苘 苘� `07圹坜圹圻    `02咣圻 苓圹踐28盽02� `07圹`7F盽07輅0B
+`07 `05苒圻踐5D盽05圹`5E盽05圹圹圹踐5E癭05咣`5E癭05圹`5D癭05圹圹咣`5E氨`05苒圹圻圹圹� `07咣圹� `05�    `03� `02苘圹圮苘� `03躟07捋圹`03捃躟0B
+                                              `07違0B       `3B盽03圮 `02圹`2A癭02圹圻 `03轥3B盽0B `07圹� `03圹踐0B
+                                                      `3B癭03圯`07轥02捋圹踐28癭02輅07踐03轥3B癭03輅07捋`7F癭07輅03圹圯`0B
+                                                     `03捋� `07違02躟2A癭02圹圹苘 `03� `07圹`7F盽07輅03圹圹`0B
+                                                     `03捋 `07輅02哌捋圯`28癭02違07苘� 圹� `03捋圹`0B
+                                                      `03輅07轥7F盽07圹 `02圹 `07苒圹� 捋� `03圹圯`0B
+                                                      `03輅07踐7F瞏07圹� `02� `7F盽07圹踐78盽07� `02懿輅03圹踐0B
+                                                       `07踐7F盽07圹`78氨`0B `07踐7F癭07圹踐78癭07� 苘� `03圮`0B
+
+^PAUSE
+
+
+
+
+
+
+
+  |0CThe main objective in The Clans is to destroy the opposition.  You do
+  this not only by improving your clan by fighting, gaining gold and
+  experience but also through your empire.  Increase the size of your
+  empire and form alliances as well!
+
+  |0BIf this game is in an InterBBS league, |0Cyou may wish to play the game as
+  "whole" BBS.  This means having the all players who play The Clans on this
+  BBS unite (by choosing similar Clan Symbols usually) and travel onto other
+  BBSes with the intent of destroying everything in sight.  Another way to
+  play is to simply attack other villages through village empire wars.
+
+  |15Good luck!  And remember: destroy everything.
+
+
+
+|08[End of Intro]
+
+%N
+^PAUSE
+^END
+
+^Clan Symbol
+ |0BClan Symbol|0C
+
+ This symbol is not required and really does nothing on its own.  However, you
+ may find it useful as a way of showing your alliances with other clans.  For
+ instance, if you and 3 other clans are all allied one another, you may wish
+ to pick a common symbol for each of the clans in the alliance.  This way,
+ other clans will immediately know which clans are associated with each other.
+
+ The symbol can be almost any string of up to 20 characters.  You may use
+ pipe (|) codes or TG-style ` codes for colours.  Examples:
+
+  `01[`19KiLL`01]`07   `08\`04/`0C^`01\`08/`07  `04[`0CVGA`07i`04]   `02[`0AKoR`02]
+
+^END
+
+^Individual Colours
+ |0C01 |01Blue    |0C05 |05Magenta     |0C09 |09Blue    |0C13 |13Magenta
+ |0C02 |02Green   |0C06 |06Brown       |0C10 |10Green   |0C14 |14Yellow
+ |0C03 |03Cyan    |0C07 |07Grey        |0C11 |11Cyan    |0C15 |15White
+ |0C04 |04Red     |0C08 |08Dark Grey   |0C12 |12Red
+^END
+
+
+^Beta Note
+%C
+|0CBugs, comments, suggestions?
+
+|0Bemail:               |14tigertigr@yahoo.ca
+|0Bwebpage:             |14http://theclans.sourceforge.net
+|0Bsupport bbs:         |14rev.nine   (defunct)
+
+|0CSee the bulletins for features coming soon!  Here are some features coming
+very, very soon:
+
+        |0B* |0Cinter-village wars (IBBS games)
+        |0B* |0Ca village army
+        |0B* |0Cinterbbs scores
+        |0B* |0Cvillage council
+        |0B* |0Cvillage schemes (port town, farming town, etc.)
+        |0B* |0Cland (for businesses, farms, etc.) for individual clans
+
+^PAUSE
+^END
diff --git a/src/doors/clans-devkit/CLANS.PAK b/src/doors/clans-devkit/CLANS.PAK
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/src/doors/clans-devkit/CLASSES.TXT b/src/doors/clans-devkit/CLASSES.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..993a7ad858888367fa1260da519c7cce87b18476
--- /dev/null
+++ b/src/doors/clans-devkit/CLASSES.TXT
@@ -0,0 +1,156 @@
+# Stats, an explanation (for myself):
+#
+# for stats, 0 is average, 3 is excellent, -3 is poor, 5 is amazing
+#
+
+Name            Barbarian
+Agility         2
+Dexterity       2
+Strength        5
+Wisdom          -1
+ArmorStr        1
+Charisma        -1
+MaxHP           10
+MaxMP           -3
+Gold            100
+
+Name            Warrior
+Agility         4
+Dexterity       3
+Strength        3
+Wisdom          1
+ArmorStr        0
+Charisma        0
+MaxHP           8
+MaxMP           6
+Gold            50
+Spell           20
+Spell           11
+Spell           18
+
+Name            Martial Artist
+Agility         6
+Dexterity       5
+Strength        1
+Wisdom          1
+ArmorStr        0
+Charisma        2
+MaxHP           12
+MaxMP           7
+Gold            60
+Spell           8
+Spell           9
+Spell           10
+Spell           21
+
+Name            Knight
+Agility         4
+Dexterity       3
+Strength        4
+Wisdom          2
+ArmorStr        1
+Charisma        4
+MaxHP           13
+MaxMP           6
+Gold            500
+Spell           14
+Spell           22
+
+Name            Assassin
+Agility         4
+Dexterity       6
+Strength        1
+Wisdom          2
+ArmorStr        0
+Charisma        1
+MaxHP           8
+MaxMP           9
+Gold            300
+Spell           16
+Spell           5
+Spell           23
+
+Name            Healer
+Agility         3
+Dexterity       2
+Strength        0
+Wisdom          3
+ArmorStr        0
+Charisma        2
+MaxHP           7
+MaxMP           12
+Gold            50
+Spell           1
+Spell           2
+Spell           4
+
+Name            Sorcerer
+Agility         2
+Dexterity       0
+Strength        -1
+Wisdom          4
+ArmorStr        0
+Charisma        0
+MaxHP           10
+MaxMP           9
+Gold            100
+Spell           8
+Spell           12
+Spell           13
+Spell           25
+
+Name            Necromancer
+Agility         2
+Dexterity       1
+Strength        -1
+Wisdom          5
+ArmorStr        0
+Charisma        0
+MaxHP           11
+MaxMP           10
+Gold            100
+Spell           8
+Spell           6
+Spell           7
+Spell           19
+
+Name            Wizard
+Agility         2
+Dexterity       -1
+Strength        -1
+Wisdom          5
+ArmorStr        0
+Charisma        1
+MaxHP           7
+MaxMP           13
+Gold            20
+Spell           13
+Spell           15
+Spell           8
+Spell           2
+Spell           4
+Spell           7
+
+Name            Pirate
+Agility         7
+Dexterity       3
+Strength        2
+Wisdom          1
+ArmorStr        0
+Charisma        4
+MaxHP           5
+MaxMP           0
+Gold            750
+
+Name            Samurai
+Agility         5
+Dexterity       4
+Strength        2
+Wisdom          1
+ArmorStr        1
+Charisma        2
+MaxHP           10
+MaxMP           5
+Gold            250
+Spell           8
+Spell           9
diff --git a/src/doors/clans-devkit/COMBAT.HLP b/src/doors/clans-devkit/COMBAT.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..81d204a3b2910b7e66ea2897a183c2125cd5ec7c
--- /dev/null
+++ b/src/doors/clans-devkit/COMBAT.HLP
@@ -0,0 +1,28 @@
+^Attack
+|0C This causes the current member of your clan to attack the first living enemy.
+^END
+
+^Attack Specific
+|0C This will allow you to choose which enemy you would like to attack with
+ the current member of your clan.  This is extremely useful since not
+ all enemies are of equal strength!  It wise to attack the weak first to
+ get them out of the way and then go for the stronger ones.
+
+ You may also type digit from 1 to 9 first instead of typing |0BS|0C.
+^END
+
+^Experience Rewarded
+|0C The amount of experience each of your characters receive depends
+ largely on how well they do in combat.  Each successful attack garners
+ at least 1 experience point (XP) which are given in the [] symbols.
+ There are XP for other moves as well such as healing a member of your
+ clan successfully.  If your player does nothing in battle, he will not
+ receive any experience so be sure to spread the amount of damage done
+ by your players.
+^END
+
+^Skip Move
+|0C Use this option if you wish to pass on the character's move.  The character
+ will do nothing but this feature allows you to choose who will get the
+ killing blow (and gain more experience).
+^END
diff --git a/src/doors/clans-devkit/EMPIRE.HLP b/src/doors/clans-devkit/EMPIRE.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..f5ae3b85f5083a1d8e7824a51ae0004258f3af33
--- /dev/null
+++ b/src/doors/clans-devkit/EMPIRE.HLP
@@ -0,0 +1,7 @@
+^Spy Help
+|0C Use a spy to gain information on your enemy's empires.  If your spy is
+ "caught", the enemy will be notified of your spying attempt.  You may spy
+ up to 10 times a day.
+^END
+
+
diff --git a/src/doors/clans-devkit/EVA.TXT b/src/doors/clans-devkit/EVA.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..c59474b152edc2f37f4f113aac6153e32d6f869a
--- /dev/null
+++ b/src/doors/clans-devkit/EVA.TXT
@@ -0,0 +1,613 @@
+# -----------------------------------------------------------------------------
+Event Event1
+Text "%C
+Text "|02You are wandering along when you come upon a fisherman!  You see a pool of
+Text "muddy water and what looks like a senile old man with a fishing rod.  He turns
+Text "and smiles.
+Text
+Text " (|05L|02)eave him be
+Text " (|05A|02)ttack Him
+Text " (|05C|02)hat with him
+Text
+Prompt "What do you wish to do? [|12LAC|02]: |13
+Option L STOP
+Option A Event1.Attack
+Option C Event1.Chat
+End
+
+        Result Event1.Attack
+        Text
+        Text "|02You catch the fisherman unawares and you can see that he is not a fighter.
+        pause
+        AddEnemy /m/NPC 1
+        Fight Event1.Win Event1.Lose NEXTLINE
+
+        # user ran, so do this
+        Text
+        Text "|02The fisherman, still shocked by your attack, stands perfectly still
+        Text "as you walk away.
+        End
+
+        Result Event1.Chat
+        Chat _Fisherman
+        End
+
+        Result Event1.Win
+        Text "|02You look at the dead body of the poor fisherman and wonder to yourself why
+        Text "you felt the need to murder such a peaceful fellow.
+        End
+
+        Result Event1.Lose
+        Text "|02You feel humiliated that your clan lost to such a weak fighter.  You become
+        Text "unconscious.
+        End
+
+
+
+# -----------------------------------------------------------------------------
+Event OldMan
+Text "%C
+Text "|02You see an unsuspecting old man walking quietly on his own.  He is
+Text "carrying what looks to be a large sack of gold.  What do you wish to do?
+Text
+Text " (|05R|02)ob him
+Text " (|05T|02)alk to him
+Text " (|05L|02)eave
+Text
+Prompt "[|12RTL|02]: |13
+Option R OldMan.R
+Option T NextLine
+Option L Stop
+Chat _OldMan
+End
+
+        Result OldMan.R
+        Text
+        Text "|02You grab his sack of gold and run off with it in hand.
+        pause
+        Text
+        Text "|02You open the sack and find |10250 gold pieces|02!  |12For doing a dirty deed,
+        Text "you lose 20 points!
+        GiveGold 250
+        GivePoints -20
+        End
+
+# -----------------------------------------------------------------------------
+Event Gold
+Text "%C
+Text "|02You find a sack of gold containing |10500 gold|02!
+GiveGold 500
+End
+
+# -----------------------------------------------------------------------------
+Event BeatUp1
+# you find some guys beating up somebody else (DO NOT say old man)
+#
+# help him?
+
+Text "%C
+Text "|02You see two men beating up another man up ahead.  What do you do?
+Text
+Text " (|05H|02) Help the man
+Text " (|05L|02) Leave
+Text
+Prompt "[|12HL|02]: |13
+Option L STOP
+Option H NextLine
+Text
+Text "|02You run to help the man.  All three turn and attack!
+pause
+AddEnemy /m/Eva 19
+AddEnemy /m/Eva 19
+AddEnemy /m/Eva 20
+Fight NextLine STOP STOP
+Text
+Text "|02You defeat all three and realize that it was all a trick to try and rob you.
+End
+
+Event BeatUp2
+# you find some guys beating up an OLD man
+Text "%C
+Text "|02You see two men beating up an old man up ahead.  What do you do?
+Text
+Text " (|05H|02) Help the old man
+Text " (|05L|02) Leave
+Text
+Prompt "[|12HL|02]: |13
+Option L STOP
+Option H NextLine
+Text
+Text "|02You run to help the old man.
+pause
+AddEnemy /m/Eva 20
+AddEnemy /m/Eva 20
+Fight NextLine STOP STOP
+Text
+Text "|02After the battle, the old man thanks you.  His kindness makes you feel good
+Text "inside.  |03(You gain 10 points.)
+GivePoints 10
+End
+
+
+
+# -----------------------------------------------------------------------------
+Event GhostHorses
+Text "%C
+Text "|02You hear the sound of galloping horses coming from up ahead!  You listen
+Text "intently on the noise and focus on the darkness ahead.  Soon, a faint light
+Text "can be seen, but you cannot make out what it is.  What will you do?
+Text
+Text " (|05R|02)eady yourself for battle
+Text " (|05D|02)o nothing and stand still
+Text " (|05L|02)eave this area now!
+Text
+Prompt "[|12RDL|02]: |13
+Option R GhostHorses.Ready
+Option D GhostHorses.Nothing
+Option L NextLine
+Text
+Text "|02Your clan flees as quickly as possible to avoid any confrontation!
+End
+
+        Result GhostHorses.Ready
+        Text
+        Text "|02You wait with weapons drawn for the beings to come closer.  Soon, they are
+        Text "visible.  You see a few knights on horseback.  However, they are spirits and
+        Text "not of the living!
+        pause
+        Text
+        Text "The knights jump off their horses.  The horses vanish quickly as the knights
+        Text "near.  They draw their swords and the battle begins!
+        pause
+        Jump GhostHorses.Fight
+        End
+
+        Result GhostHorses.Fight
+        AddEnemy /m/Eva 11
+        AddEnemy /m/Eva 12
+        {R60}AddEnemy /m/Eva 11
+        {R40}AddEnemy /m/Eva 12
+        {R20}AddEnemy /m/Eva 11
+        {R10}AddEnemy /m/Eva 12
+        Fight NextLine STOP NoRun
+        Text
+        Text "|02The knights vanish after being defeated.  Soon, the mines are as they were
+        Text "before.
+        End
+
+        Result GhostHorses.Nothing
+        Text
+        Text "|02Trusting your instincts, the clan stands perfectly still and waits for
+        Text "whatever is making the galloping noises to come closer . . .
+        pause
+        Text
+        Text "You wait patiently.
+        pause
+        Text
+        Text "It nears . . .
+        pause
+        Text
+        Text "You see a group of ghost knights on horseback!  Their white glow lightens up
+        Text "the dark mine.  What do you wish to do?
+        Text
+        Text " (|05C|02)ontinue doing nothing
+        Text " (|05A|02)ttempt to attack them
+        Text " (|05R|02)un away
+        Text
+        Prompt "[|12CAR|02]: |13
+        Option C GhostHorses.Nothing2
+        Option A GhostHorses.Attack
+        Option R GhostHorses.Run
+        End
+
+        Result GhostHorses.Attack
+        Text
+        Text "|02Feeling a desire to fight, you command the clan to attack.  The knights
+        Text "notice you immediately.  They force their horses to stop.  Soon, they have
+        Text "drawn their weapons and are nearing you.  The two parties attack each
+        Text "other . . .
+        pause
+        Jump GhostHorses.Fight
+        End
+
+        Result GhostHorses.Nothing2
+        Text
+        Text "|02The clan continues to stand perfectly still.  Doing so seems to make you
+        Text "somewhat invisible to the spirits as they pass right through you without
+        Text "hesitation.  You breathe a sigh of relief after they have passed.  For
+        Text "outsmarting the knights, each |10clansman gains 6 experience.
+        GiveXP 6
+        End
+
+        Result GhostHorses.Run
+        Text
+        Text "|02You tell the rest of your clan to run and soon you are blazing down the
+        Text "mine.  After a 20 feet of running, you realize that running is futile since
+        Text "the knights have horses.
+        pause
+        Text
+        Text "You turn and fight.
+        pause
+        Jump GhostHorses.Fight
+        End
+
+# -----------------------------------------------------------------------------
+Event BedOfRoses
+Text "%C
+Text "|10Bed of Roses|02
+Text "
+Text "You are surprised to an area of the dungeon where a flowers are
+Text "growing.
+Text
+Text " (|05P|02) Pick flowers
+Text " (|05L|02) Leave
+Text
+Prompt "What do you wish to do? [|12PL|02]: |13
+Option P BedOfRoses.Pick
+Option L NEXTLINE
+Text "|02You |10leave |02the flowers alone and they |10leave |02you alone.
+Text "%P
+End
+
+        Result BedOfRoses.Pick
+        Text
+        Text "|02You bend down to pick a flower but as soon as you grab ahold of one, you hear
+        Text "a man screaming.  |10You turn to see a crazed man with a pair of shears heading
+        Text "your way!
+        pause
+        AddEnemy /m/Eva 3
+        Fight BedOfRoses.Win STOP STOP
+        End
+
+        Result BedOfRoses.Win
+        Text
+        Text "|02You watch as the mad gardener stumbles and falls into his bed of flowers.
+        Text "Soon, the flowers turn a shade of blood red . . .
+        pause
+        End
+
+# -----------------------------------------------------------------------------
+Event Cemetery
+Text "%C
+Text "|02Within the mines, you notice a strange sight.  A cemetery has been built within
+Text "the mine itself.  You are even more shocked to see that the cemetery
+Text "stretches down many corridors and many of the dead are resting here.
+Text
+Text "You are angered to see a man who seems to be desecrating the graves.  He is
+Text "digging up bodies and piling them into a wheelbarrow.
+Text
+Prompt "Do you wish to attack him? [|12Y/N|02]: |13
+Option N NEXTLINE
+Option Y Cemetery.Attack
+Prompt "|02Do you wish to watch him for a while? [|12Y/N|02]: |13
+Option N STOP
+Option Y NEXTLINE
+Text
+Text "|02You watch for a minute or so and it doesn't seem that the man notices you.
+Text "Then, all of a sudden, the man turns and sees you.  A smile crosses his face.
+Text "Before you know it, several ghouls have surrounded you!
+pause
+AddEnemy /m/Eva 0
+AddEnemy /m/Eva 0
+AddEnemy /m/Eva 0
+AddEnemy /m/Eva 0
+AddEnemy /m/Eva 1
+AddEnemy /m/Eva 1
+AddEnemy /m/Eva 1
+AddEnemy /m/Eva 1
+Fight NEXTLINE Cemetery.Lose Cemetery.Ran
+Text
+Text "|02After defeating the madman's minions, you focus on him . . .
+pause
+AddEnemy /m/Eva 2
+Fight NEXTLINE Cemetery.Lose Cemetery.Ran
+Jump Cemetery.End
+End
+
+        Result Cemetery.Attack
+        AddEnemy /m/Eva 2
+        Fight Cemetery.End Cemetery.Lose Cemetery.Ran
+        End
+
+        Result Cemetery.Ran
+        Text "|02The clan runs feverishly away to safety . . .
+        End
+
+        Result Cemetery.End
+        Text "|02You feel glad that you did something that was good.  Each member of
+        Text "the clan gains |105 |02experience.
+        GiveXP 5
+        End
+
+        Result Cemetery.Lose
+        Text "|06The last thing you feel before becoming unconscious is being dragged
+        Text "across the mine floor . . .
+        End
+
+# -----------------------------------------------------------------------------
+Event LoneWolf
+Text "%C
+Text "|02You encounter a lone wolf sniffing around some carcuses.  They look to be of
+Text "old miners that were among the living yesterday.
+Text
+Text " (|05A|02) Attack the Wolf
+Text " (|05P|02) Pet the Wolf
+Text " (|05L|02) Leave
+Text
+Prompt "What do you do? [|12APL|02]: |13
+Option A LoneWolf.Attack
+Option P LoneWolf.Pet
+Option L STOP
+End
+
+        Result LoneWolf.Pet
+        Text
+        Text "|02You pet the wolf and it seems to be gentle.  It has a strange magical
+        Text "aura as well since each member of the clan feels his skill points being
+        Text "replenished . . .
+        Heal SP
+        End
+
+        Result LoneWolf.Attack
+        Text
+        Text "|02As you approach with weapons ready, the wolf begins to howl . . .
+        pause
+        Text
+        Text "|10Soon its master appears.  |02Its master is a tall, thin man wearing
+        Text "a tunic with hood drawn over his head.  You cannot see his face at all.
+        Text "He readies his staff for the attack . . .
+        pause
+        AddEnemy /m/Eva 6
+        AddEnemy /m/Eva 7
+        Fight NextLine STOP STOP
+        Text
+        Text "|02You look over the two dead beings and continue on your way with a feeling of
+        Text "remorse overhanging you . . .
+        End
+
+# --------
+
+Event Sack
+Text "%C
+Text "|02You are walking when suddenly you trip on an object and fall down onto the
+Text "the ground.  You turn around to see a small sack.  It seems to be moving.
+pause
+Text
+Text "You look at a label on the sack.  It says "DO NOT OPEN."  You can hear a
+Text "muffled voice coming from inside the sack.
+Text
+Text " (|05O|02)pen the sack
+Text " (|05L|02)eave
+Text
+Prompt "What do you do? [|12OL|02]: |13
+Option O Sack.Open
+Option L NextLine
+Text
+Text "|02You heed the words on the sack and continue on your way . . .
+pause
+End
+
+        Result Sack.Open
+        Text
+        Text "|02You open the sack to reveal a little gnome ... gagged at the mouth.
+        pause
+        Text
+        Text "You undo the gag.
+        pause
+        Text
+        Text "|10"Thank you, friend.  A few drunk orcs saw me and tied me up like this for
+        Text "some reason.  As a reward, I'll take you to some gold that they found!"
+        pause
+        Text
+        Text "|02Something about the little guy seems suspicious.  Do you wish to let him
+        Prompt "take you to the gold? [|12Y/N|02]: |13
+        Option N NextLine
+        Option Y Sack.GetGold
+        Text
+        Text "|02You tell him you have no time for his little games and continue on . . .
+        pause
+        End
+
+        Result Sack.GetGold
+        Text
+        Text "|02The little gnome takes you through several twists and turns in the mines and
+        Text "eventually to a small dark room.
+        pause
+        Text
+        Text "As soon as a torch is lit, you see |10several orcs |02surrounding you and the
+        Text "little gnome gone.
+        pause
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        AddEnemy /m/Eva 4
+        Fight NextLine STOP STOP
+        Text
+        Text "|02After killing off the orcs, you see the little gnome in the corner.
+        Text "|10"I did not know they would be back so soon!  I swear!" |02he pleads.
+        Text "|10"I can still show you the gold, however."|02
+        Text
+        Text " (|05A|02)ttack him
+        Text " (|05G|02) Let him show you the gold
+        Text " (|05L|02)eave
+        Text
+        Prompt "What do you wish to do? [|12AGL|02]: |13
+        Option A Sack.AttackHim
+        Option L STOP
+        Option G NextLine
+        Text
+        Text "|02You follow him once more but this time he does lead you to some gold, albeit
+        Text "very little.  You pick a few gold coins.  The total you find is only 700 gold
+        Text "pieces.  You curse the gnome before heading off on another path . . .
+        GiveGold 700
+        pause
+        End
+
+        Result Sack.AttackHim
+        AddEnemy /m/Eva 5
+        Fight NextLine STOP STOP
+        Text
+        Text "|02You search the gnomes pockets and find |10250 more gold pieces!
+        GiveGold 250
+        pause
+        End
+
+# -----------------------------------------------------------------------------
+Event GoldTrail
+Text "%C
+Text "|02A shimmer of light catches your eye.  You turn to see some gold coins
+Text "totalling |1040 |02gold pieces.  You grab them quickly and look ahead to find
+Text "even more coins trailing ahead.
+GiveGold 40
+Text
+Prompt "Do you wish to follow the trail of gold? [|12Y/N|02]: |13
+Option Y GoldTrail.2
+Option N NextLine
+Text
+Text "|02You leave the rest of the gold for others to take . . .
+End
+        Result GoldTrail.2
+        # 30% chance of encountering thieves
+        {R30}Jump GoldTrail.Fight
+        Text
+        Text "|02You find |1050 |02more gold pieces on the trail.
+        GiveGold 50
+        Prompt "Do you wish to continue following the trail of gold? [|12Y/N|02]: |13
+        Option Y GoldTrail.2
+        Option N NextLine
+        Text
+        Text "|02You leave the rest of the gold for others to take . . .
+        End
+
+        Result GoldTrail.Fight
+        Text
+        Text "|02You pick up a few more gold pieces and look up to see several thieves
+        Text "with leaking sacks.  They look angered and poised to fight.  You ready your
+        Text "weapons . . .
+        pause
+        # make it random amount of thieves each time
+        AddEnemy /m/Eva 8
+        AddEnemy /m/Eva 8
+        AddEnemy /m/Eva 9
+        {R60}AddEnemy /m/Eva 8
+        {R50}AddEnemy /m/Eva 8
+        {R40}AddEnemy /m/Eva 9
+        {R30}AddEnemy /m/Eva 9
+        {R20}AddEnemy /m/Eva 10
+        {R10}AddEnemy /m/Eva 10
+        Fight NextLine STOP STOP
+        Text
+        Text "|02After defeating the thieves, you pick up their sacks and find |10500 gold
+        Text "pieces!
+        pause
+        GiveGold 500
+        End
+
+$
+# -----------------------------------------------------------------------------
+Event GoldenGoblet
+End
+
+# -----------------------------------------------------------------------------
+Event CrazyMan
+End
+
+
+# -----------------------------------------------------------------------------
+Event Alcove
+End
+
+# -----------------------------------------------------------------------------
+Event SmallMan
+End
+
+Event Howling
+End
+
+# -----------------------------------------------------------------------------
+Event Random
+Text "%C
+Text "|02You are walking along when you suddenly trip on something.
+pause
+Text
+Text "You look down and see a small boy carrying a heavy sack.
+Text
+Text " "(|05W|02)atch where you're going you little brat!"
+Text " "(|05E|02)xcuse me, but could you watch where *I* am going next time!?"
+Text " "(|05H|02)ey, what do you have in that sack young man?"
+Text "  (|05I|02)gnore him and walk away.
+Text
+Prompt "What do you say? [|12WEHI|02]: |13
+Option W Random/W
+Option E Random/E
+Option H Random/H
+Option I STOP
+End
+
+        Result Random/W
+        Text
+        Text "|10For your information I'm not a little brat!  I am the heir to the throne in
+        Text "of another kingdom! |02he says with pride.
+        Text
+        Text " "(|05T|02)hen what in Nuul are you doing in the mines!?"
+        Text " "(|05E|02)xcuse me your majesty!" (sarcastically)
+        Text " "(|05E|02)xcuse me your majesty!" (literally)
+        Text "  (|05I|02)gnore him and walk away
+        Text
+        Prompt "
+        End
+
+
+Event Salesman3
+Text "%C
+Text "|02You encounter a man in the mines.  He offers a |10Lion's Shield |02for |10700|02
+Prompt "gold.  Buy it? [|12Y/N|02]: |13
+Option Y Salesman3.Y
+Option N STOP
+End
+
+        Result Salesman3.Y
+        Text
+        {!$700}Text "|02Unfortunately, you couldn't afford it.
+        {$700}Text "|02He takes your gold and gives you the merchandise.
+        {$700}GiveItem Lion's Shield
+        {$700}TakeGold 700
+        End
+
+Event Salesman2
+Text "%C
+Text "|02You encounter a man in the mines.  He offers a |10Silver Mace |02for |101300|02
+Prompt "gold.  Buy it? [|12Y/N|02]: |13
+Option Y Salesman2.Y
+Option N STOP
+End
+
+        Result Salesman2.Y
+        Text
+        {!$1300}Text "|02Unfortunately, you couldn't afford it.
+        {$1300}Text "|02He takes your gold and gives you the merchandise.
+        {$1300}GiveItem Silver Mace
+        {$1300}TakeGold 1300
+        End
+
+Event Salesman1
+Text "%C
+Text "|02You encounter a man in the mines.  He offers |10Platemail Armor |02for |10900|02
+Prompt "gold.  Buy it? [|12Y/N|02]: |13
+Option Y Salesman1.Y
+Option N STOP
+End
+
+        Result Salesman1.Y
+        Text
+        {!$900}Text "|02Unfortunately, you couldn't afford it.
+        {$900}Text "|02He takes your gold and gives you the merchandise.
+        {$900}GiveItem Platemail Armor
+        {$900}TakeGold 900
+        End
+
diff --git a/src/doors/clans-devkit/EVENTMON.TXT b/src/doors/clans-devkit/EVENTMON.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..cf54cb3e37fe06c16531850b419079e97774e92b
--- /dev/null
+++ b/src/doors/clans-devkit/EVENTMON.TXT
@@ -0,0 +1,380 @@
+# Event monsters that you encounter
+
+# 0
+Name            Ghoul
+HP              12
+Difficulty      3
+Agility         7
+Dexterity       10
+Strength        8
+Wisdom          9
+Charisma        2
+Armorstr        0
+Undead
+
+Name            Ghoul
+HP              15
+Difficulty      1
+Agility         9
+Dexterity       4
+Strength        7
+Wisdom          9
+Charisma        2
+Armorstr        0
+Undead
+
+Name            Mad Scientist
+HP              20
+Difficulty      1
+Agility         10
+Dexterity       6
+Strength        9
+Wisdom          9
+Charisma        0
+Armorstr        0
+
+# 3
+Name            Mad Gardener
+HP              30
+Difficulty      1
+Agility         7
+Dexterity       3
+Strength        13
+Wisdom          9
+Armorstr        1
+
+# 4
+Name            Orc
+HP              10
+Difficulty      1
+Agility         8
+Dexterity       3
+Strength        8
+Wisdom          9
+Armorstr        0
+
+# 5
+Name            Small Gnome
+HP              15
+Difficulty      1
+Agility         6
+Dexterity       6
+Strength        11
+Wisdom          9
+Armorstr        0
+
+# 6
+Name            Wolf Master
+HP              20
+Difficulty      1
+Agility         10
+Dexterity       9
+Strength        11
+Wisdom          9
+Armorstr        0
+
+# 7
+Name            Wolf
+HP              15
+Difficulty      1
+Agility         8
+Dexterity       3
+Strength        9
+Wisdom          2
+Armorstr        0
+
+# 8-10, thieves
+Name            Thief
+HP              18
+Difficulty      1
+Agility         9
+Dexterity       6
+Strength        11
+Wisdom          2
+Armorstr        0
+
+# 9
+Name            Thief
+HP              21
+Difficulty      1
+Agility         10
+Dexterity       4
+Strength        13
+Wisdom          2
+Armorstr        1
+
+# 10
+Name            Thief
+HP              21
+Difficulty      1
+Agility         10
+Dexterity       4
+Strength        14
+Wisdom          2
+Armorstr        0
+
+# 11 & 12 knights
+Name            Spirit Knight
+HP              17
+Difficulty      1
+Agility         12
+Dexterity       8
+Strength        11
+Wisdom          2
+Armorstr        0
+Undead
+
+Name            Spirit Knight
+HP              22
+Difficulty      1
+Agility         12
+Dexterity       9
+Strength        12
+Wisdom          2
+Armorstr        0
+Undead
+
+# 13,14,15 orcs
+Name            Orc
+HP              12
+Difficulty      1
+Agility         6
+Dexterity       9
+Strength        7
+Wisdom          2
+Armorstr        0
+
+Name            Orc
+HP              15
+Difficulty      1
+Agility         7
+Dexterity       9
+Strength        8
+Wisdom          2
+Armorstr        0
+
+Name            Orc
+HP              15
+Difficulty      1
+Agility         6
+Dexterity       10
+Strength        9
+#Wisdom          4
+Wisdom          15
+Armorstr        0
+Spell           8
+
+# 16,17 orcs
+Name            Orc
+HP              14
+Difficulty      1
+Agility         6
+Dexterity       9
+Strength        10
+Wisdom          2
+Armorstr        0
+
+Name            Orc
+HP              19
+Difficulty      1
+Agility         9
+Dexterity       9
+Strength        9
+Wisdom          2
+Armorstr        0
+
+# 18, orc guards
+Name            Orc Guard
+HP              15
+Difficulty      1
+Agility         10
+Dexterity       9
+Strength        10
+Wisdom          2
+Armorstr        0
+
+# 19
+Name            Man
+HP              25
+Difficulty      1
+Agility         12
+Dexterity       9
+Strength        12
+Wisdom          2
+Armorstr        0
+
+# 20 man
+Name            Man
+HP              20
+Difficulty      1
+Agility         12
+Dexterity       11
+Strength        10
+Wisdom          2
+Armorstr        1
+
+# 21 hellhound
+Name            Hellhound
+HP              14
+Difficulty      2
+Agility         10
+Dexterity       11
+Strength        10
+Wisdom          4
+Armorstr        1
+Undead
+
+# 22 hellhound
+Name            Hellhound
+HP              16
+Difficulty      2
+Agility         10
+Dexterity       11
+Strength        13
+Wisdom          4
+Armorstr        1
+Undead
+
+# 23 beast
+Name            Beast
+HP              60
+Difficulty      5
+Agility         16
+Dexterity       14
+Strength        21
+Wisdom          10
+Armorstr        2
+Spell           8
+Spell           11
+
+# 24 gardener
+Name            gardener
+HP              20
+Difficulty      2
+Agility         11
+Dexterity       10
+Strength        14
+Wisdom          10
+Armorstr        1
+
+# 25 guard
+Name            guard
+HP              20
+Difficulty      2
+Agility         8
+Dexterity       12
+Strength        21
+Wisdom          2
+Armorstr        1
+
+
+# 26 guard
+Name            guard
+HP              25
+Difficulty      2
+Agility         10
+Dexterity       10
+Strength        13
+Wisdom          5
+Armorstr        1
+
+
+# 27 businessman
+Name            Businessman
+HP              45
+Difficulty      4
+Agility         10
+Dexterity       11
+Strength        15
+Wisdom          10
+Armorstr        1
+
+# 28 thief
+Name            Thief
+HP              19
+Difficulty      2
+Agility         9
+Dexterity       8
+Strength        12
+Wisdom          5
+Armorstr        0
+Spell           5
+
+# 29 thief
+Name            Thief
+HP              13
+Difficulty      1
+Agility         9
+Dexterity       10
+Strength        12
+Wisdom          5
+
+# 30 Large thief
+Name            Large Thief
+HP              43
+Difficulty      5
+Agility         10
+Dexterity       12
+Strength        16
+Wisdom          5
+
+# 31 wyverns
+Name            Wyvern
+HP              27
+Difficulty      5
+Agility         12
+Dexterity       14
+Strength        17
+Wisdom          5
+
+# 32 hellhounds
+Name            Hellhound
+HP              23
+Difficulty      4
+Agility         11
+Dexterity       12
+Strength        12
+Wisdom          5
+ArmorStr        1
+Undead
+
+# 33
+Name            Green Slyme
+HP              35
+Difficulty      4
+Agility         8
+Dexterity       7
+Strength        15
+Wisdom          5
+ArmorStr        0
+
+# 34
+Name            Skeletal Fiend
+HP              22
+Difficulty      3
+Agility         9
+Dexterity       8
+Strength        13
+Wisdom          2
+ArmorStr        0
+Undead
+
+# 35
+Name            Golden Dragon
+HP              42
+Difficulty      3
+Agility         10
+Dexterity       9
+Strength        16
+Wisdom          2
+ArmorStr        1
+Spell           17
+
+# 36
+Name            Ghoul
+HP              27
+Difficulty      3
+Agility         8
+Dexterity       6
+Strength        15
+Undead
diff --git a/src/doors/clans-devkit/FORT.HLP b/src/doors/clans-devkit/FORT.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..20614f60f08017d489fdd2253d7ed1402990a3c4
--- /dev/null
+++ b/src/doors/clans-devkit/FORT.HLP
@@ -0,0 +1,84 @@
+^Footmen
+|0B Footmen
+
+|0C Footmen are your main source of troops.  They will attack any type of
+ enemy they find.
+^END
+
+^Archers
+|0B Archers
+
+|0C Archers are slightly more specialized than footmen.  About 50% of the time,
+ they will attack enemy archers (if there are any) and 30% of the time they
+ will attack footmen.  They will occasionally attack knights and catapults
+ as well.
+^END
+
+^Catapults
+|0B Catapults
+
+|0C Catapults are hard to use and therefore their level of attack varies.
+ They will often hit a large group of enemy troops but much of the time they
+ will miss.  They are excellent on fort attacks, however.  They are of no
+ use when defending.
+
+|10 It takes 4 followers for each catapult.
+^END
+
+^Knights
+|0B Knights
+
+|0C These troops are the strongest of the pack.  They will attack knights and
+ catapults about 50% of the time while the rest of the time they will attack
+ anyone randomly.  These are great defenses against catapults!!
+^END
+
+^Fort
+|0CYour fort is the homebase of your clan and its troops.  You require a
+fort to manage troops and to attack other clans.  If the current game is set
+to Elimination Mode and your fort is destroyed while your clan is stationed
+in this village, you will be ELIMINATED FROM THE GAME.  Therefore, it is
+important to repair your fort but also try to destroy the competition and
+to wipe them out.
+^END
+
+^Troops
+|0CTroops are needed to attack other clans' forts and to defend your own fort.
+If you wish to rule the village, you must also have troops to defend it
+with.  If you wish to overtake the current ruler, you will need troops to
+attack the ruler's army with.
+^END
+
+^Alliances
+|0CAlliance serve to improve your numbers.  If you are allied with another
+nation and then are attacked, the other nation will donate 10% of their
+troops to you for the battle.  On the other hand, if your allies are
+attacked, you will be forced to donate 10% of your troops to help their cause.
+It is a very good idea to ally with many other clans so that you can have a
+strong army.
+^END
+
+^Attacking
+|0CThe purpose of attacking other players' forts is not only to gain points and
+status but also to gain gold.  The more that an enemy is attacked and
+destroyed, the more gold that is obtained.  Of course, be sure to arm yourself
+well as other clans will be attacking your fort as well!
+^END
+
+^Reserve Troops
+|0CThe purpose of reserving troops is to protect them from attack and also to
+keep them from traveling with the clan.  If you travel to another village,
+only your readied troops (and not the reserved ones) will come along.  This
+is also the case with fort attacks.
+^END
+
+^Army Rating
+|0CArmy Rating can be thought of as the potential of your army.  Of course,
+100% means they are able to do as much damage as possible while 50% means
+they can only do half their regular damage.  Each attack will cause the
+army rating to decrease.  Using a larger army for an attack will cause the
+army rating to decrease substantially.  Therefore, it is advised that you
+keep your attacking armies small.
+
+|0B* Each day, the army rating increases from 5 to 10%.
+^END
diff --git a/src/doors/clans-devkit/GENALL.BAT b/src/doors/clans-devkit/GENALL.BAT
new file mode 100755
index 0000000000000000000000000000000000000000..4eb4fd67dc4453671f95ea75558c86ba58fc50fa
--- /dev/null
+++ b/src/doors/clans-devkit/GENALL.BAT
@@ -0,0 +1,13 @@
+langcomp strings.txt > TMP.FIL
+mcomp eventmon.txt event.mon >> TMP.FIL
+mcomp monsters.txt output.mon >> TMP.FIL
+mspells spells.txt spells.dat >> TMP.FIL
+mitems items.txt items.dat >> TMP.FIL
+mclass >>TMP.FIL
+makenpc npcs.txt clans.npc >>TMP.FIL
+ecomp pray.evt pray.e >>TMP.FIL
+ecomp eva.txt eva.e >> TMP.FIL
+ecomp quests.evt quests.e >> TMP.FIL
+ecomp church.evt church.e >> TMP.FIL
+ecomp secret.evt secret.e >> TMP.FIL
+makepak clans.pak pak.lst >> TMP.FIL
diff --git a/src/doors/clans-devkit/ITEMS.HLP b/src/doors/clans-devkit/ITEMS.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..f7380e834f00c6a0f1face82cd9933c13a06ca0b
--- /dev/null
+++ b/src/doors/clans-devkit/ITEMS.HLP
@@ -0,0 +1,183 @@
+^Shortsword
+|0B The Shortsword|0C
+
+ This is a good overall sword.  If the user is of reasonable strength, he may
+ use this sword.  However, it is not recommended for magic-users.
+^END
+
+^Broadsword
+|0B The Broadsword|0C
+
+ This is a heavier sword for mighty warriors.  Those with a fairly high
+ strength and dexterity will use this to its fullest.  Those with poor
+ strength should be cautious of using this heavy, but strong sword.
+^END
+
+^Axe
+|0B The Axe|0C
+
+ This is the heaviest of the weapons available and used only by very
+ strong warriors.  This weapon requires a high strength since it is quite
+ heavy!  This is also the most powerful weapon in terms of damage delivered
+ per blow.  It will also last the longest.
+^END
+
+^Mace
+|0B The Mace|0C
+
+ This is a small weapon which does not require a very high strength to use.
+ However, the user must have fairly good dexterity or may have difficulty
+ aiming with it!  It can be used by almost anyone.
+^END
+
+^Dagger
+|0B The Dagger|0C
+
+ This weapon can be used by any character.  It can deliver average strength
+ and has low requirements.  If a character has no weapon, equip him with this
+ if unsure of which weapon to use!
+^END
+
+^Staff
+|0B The Staff|0C
+
+  This is an excellent choice of weapon for players with high dexterity.  It
+  delivers excellent damage when put in the right hands.  However, those with
+  low dexterity should probably stay away from this weapon.  In the wrong
+  hands, it will do more harm than good.
+^END
+
+^Wand
+|0B The Wand|0C
+
+ The wand is a must for spellcasters as it gives them the ability to
+ regenerate mana a lot quicker.
+^END
+
+^Battle Axe
+|0B The Battle Axe|0C
+
+ The Axe is a heavy weapon, but the Battle Axe is even heavier.  However,
+ it delivers a larger blow than the Axe.
+^END
+
+^Morning Star
+|0B The Morning Star|0C
+
+ A spiked ball on a chain, the Morning Star is a lethal weapon useable by
+ agile characters.
+^END
+
+^Scythe
+|0B The Scythe|0C
+
+ Not truly a weapon, the scythe is still dangerous in the right hands.
+^END
+
+^Boomerang
+|0B The Boomerang|0C
+
+ The boomerang is a strange weapon.  Thrown at a foe, this bladed weapon
+ returns to its owner.
+^END
+
+
+
+^Cloth Robe
+|0B Cloth Robe|0C
+
+ This is a below average form of armor which can be used by anyone.  If a
+ character cannot wear armor, have him wear this instead.
+^END
+
+^Leather Armor
+|0B Leather Armor|0C
+
+ This is somewhat good armor and is a step up from the cloth robe but is not
+ the best.  It requires high strength and dexterity to use.
+^END
+
+^Chainmail Armor
+|0B Chainmail Armor|0C
+
+ This is very good armor which is recommended for characters of high strength
+ and dexterity.  Characters with low values in these stats should not wear
+ this armor as it is quite heavy and will deter their fighting abilities.
+^END
+
+^Platemail Armor
+|0B Platemail Armor|0C
+
+ This is the best armor currently available.  It requires quite high strength
+ to wear since it is very heavy and a high dexterity is required as it is
+ somewhat rigid.  A character who CAN wear this armor SHOULD wear it.
+^END
+
+^Wooden Armor
+|0B Wooden Armor|0C
+
+ Told it couldn't be done, the smithy went to design a fairly lightweight
+ piece of armor.  This is it.
+^END
+
+^Cloth Tunic
+|0B Cloth Tunic|0C
+
+ Made from the finest and strongest of fabrics, this tunic functions as good
+ armor for weaker characters.
+^END
+
+^Wooden Shield
+|0B Wooden Shield|0C
+
+ This is a fairly good shield.  Those with average strength or low strength
+ should not bother using this or any other shield as it will only hinder
+ combat.
+^END
+
+^Iron Shield
+|0B Iron Shield|0C
+
+ This is a heavier shield than the wooden shield and lasts much longer and
+ can block more attacks as well.  Of course, it requires more strength to
+ use.
+^END
+
+^Platinum Shield
+|0B Platinum Shield|0C
+
+ This is a light shield but is also the strongest.  This requires slightly
+ more strength to use than the wooden shield but protects about the same
+ level as the iron shield.  This is more expensive simply because of the lower
+ requirements and longer lifespan.
+^END
+
+^Crystal Shield
+|0B Crystal Shield|0C
+
+ Made entirely of a mysterious crystaline substance, this shield is
+ surprisingly light and strong.
+^END
+
+^Laconia
+
+|0C Laconia is a very strong metal which is common throughout the land.  It is
+ heavy, however.  Consequently, equipment forged using this metal tend to
+ be heavier but also stronger.
+^END
+
+^Polymetral
+
+|0C Polymetral is a light-weight metal which is just as common as laconia in this
+ world.  Because of its light weight, weapons which are normally unuseable by
+ some characters can be wielded if made with polymetral.  However, it is a
+ fairly weak metal and weapons made with it tend to become damaged more quickly
+ than laconia.
+^END
+
+^Item Help
+
+ Items are not usually better if they are more expensive.  Each item is
+ unique and has different stats.  You must choose the right one for your
+ clansmen. The most expensive equipment does not mean the best.
+^END
diff --git a/src/doors/clans-devkit/ITEMS.TXT b/src/doors/clans-devkit/ITEMS.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..7dfe418e3098017b1c26eaa5a7caa112fbb9a9d1
--- /dev/null
+++ b/src/doors/clans-devkit/ITEMS.TXT
@@ -0,0 +1,556 @@
+# Item file for The Clans
+
+# -----------------------------------------------------------------------------
+# Weapons
+# -----------------------------------------------------------------------------
+
+# --------------------------------------------------- Level 0 weapon
+Name            Shortsword
+Type            Weapon
+Cost            650
+Strength        +5
+Agility         -1
+Requirements
+Strength        6
+Agility         4
+Dexterity       6
+DiffMaterials
+Energy          200
+Village         ALL
+RandLevel       6
+
+Name            Broadsword
+Type            Weapon
+Cost            750
+Strength        +6
+Agility         -2
+Dexterity       +1
+Charisma        +1
+Requirements
+Strength        10
+Dexterity       +6
+Energy          300
+Village         All
+RandLevel       6
+
+Name            Axe
+Type            Weapon
+Cost            500
+Strength        +7
+Dexterity       -1
+Agility         -2
+Charisma        +1
+Requirements
+Strength        13
+Energy          400
+Village         All
+RandLevel       6
+
+Name            Mace
+Type            Weapon
+Cost            450
+Strength        +4
+Dexterity       +1
+Requirements
+Strength        4
+Agility         3
+Dexterity       5
+Energy          160
+Village         All
+RandLevel       6
+
+Name            Dagger
+Type            Weapon
+Cost            200
+Strength        +3
+Dexterity       +1
+Requirements
+Dexterity       3
+Energy          180
+Village         All
+RandLevel       6
+
+Name            Staff
+Type            Weapon
+Cost            125
+Energy          120
+Strength        +5
+Agility         -1
+Dexterity       +1
+Requirements
+Agility         6
+Dexterity       9
+Village         All
+RandLevel       6
+
+Name            Wand
+Type            Weapon
+Cost            250
+Energy          500
+Strength        +1
+Dexterity       +1
+Wisdom          +4
+Requirements
+Wisdom          11
+Village         All
+RandLevel       6
+
+# --------------------------------------------------- Level 1 weapon
+
+Name            Battle Axe
+Level           1
+Type            Weapon
+Cost            750
+Strength        +8
+Agility         -1
+Dexterity       -3
+Charisma        +1
+Requirements
+Strength        13
+Village         ALL
+RandLevel       5
+
+# --------------------------------------------------- Level 2 weapon
+Name            Morning Star
+Level           2
+Type            Weapon
+Cost            800
+Strength        +5
+Dexterity       +2
+Requirements
+Strength        6
+Agility         8
+Dexterity       7
+Village         All
+RandLevel       4
+
+# --------------------------------------------------- Level 3 weapon
+Name            Scythe
+Level           3
+Type            Weapon
+Cost            650
+Strength        +3
+Dexterity       +3
+Requirements
+Strength        2
+Agility         4
+Dexterity       3
+Village         All
+RandLevel       3
+
+# --------------------------------------------------- Level 4 weapon
+Name            Boomerang
+Level           4
+Type            Weapon
+Cost            1100
+Strength        +5
+Dexterity       +4
+Requirements
+Strength        2
+Agility         6
+Dexterity       7
+Village         All
+RandLevel       2
+
+# --------------------------------------------------- special weapons
+
+Name            Falcon's Sword
+Special
+Type            Weapon
+Cost            2500
+Strength        +8
+Agility         -3
+Dexterity       +1
+Charisma        +3
+Requirements
+Strength        12
+Dexterity       10
+Village         All
+RandLevel       1
+
+Name            Bloody Club
+Special
+Type            Weapon
+Cost            100
+Energy          120
+Strength        +6
+Agility         -1
+Dexterity       -1
+Requirements
+Agility         7
+Dexterity       9
+Strength        8
+Village         All
+RandLevel       2
+
+Name            Death Axe
+Special
+Type            Weapon
+Cost            1500
+Strength        +8
+Agility         -3
+Dexterity       -1
+Requirements
+Agility         8
+Dexterity       8
+Strength        13
+Village         All
+RandLevel       1
+
+Name            Spirit Blade
+Special
+Type            Weapon
+Cost            2000
+Strength        +8
+Agility         -1
+Dexterity       -1
+Requirements
+Agility         11
+Dexterity       5
+Strength        10
+Village         All
+RandLevel       1
+
+Name            Wizard's Staff
+Special
+Type            Weapon
+Cost            1000
+Strength        +2
+Wisdom          +6
+Dexterity       +2
+Agility         +1
+Requirements
+Wisdom          11
+Village         All
+RandLevel       6
+
+
+# --------------------------------------------------- individual village weaps.
+
+
+# -----------------------------------------------------------------------------
+# Armor
+# -----------------------------------------------------------------------------
+
+# --------------------------------------------------- Level 0 armor
+Name            Cloth Robe
+Type            Armor
+Cost            105
+ArmorStr        +1
+Energy          240
+Village         All
+RandLevel       6
+
+Name            Leather Armor
+Type            Armor
+Cost            250
+ArmorStr        +2
+Agility         -1
+Dexterity       -1
+Requirements
+Strength        9
+Dexterity       7
+Energy          340
+Village         All
+RandLevel       6
+
+Name            Chainmail Armor
+Type            Armor
+Cost            400
+ArmorStr        +3
+Agility         -2
+Dexterity       -1
+Requirements
+Strength        12
+Dexterity       8
+Energy          830
+Village         All
+RandLevel       6
+
+Name            Platemail Armor
+Type            Armor
+Cost            550
+ArmorStr        +4
+Agility         -3
+Dexterity       -2
+Charisma        +1
+Requirements
+Strength        14
+Dexterity       9
+Energy          1020
+Village         All
+RandLevel       6
+
+# --------------------------------------------------- Level 1 armor
+Name            Wooden Armor
+Level           1
+Type            Armor
+Cost            250
+ArmorStr        +3
+Agility         -1
+Dexterity       -1
+Requirements
+Strength        9
+Dexterity       6
+Village         All
+RandLevel       6
+
+# --------------------------------------------------- Level 2 armor
+Name            Cloth Tunic
+Level           2
+Type            Armor
+Cost            250
+ArmorStr        +2
+Requirements
+Dexterity       5
+Village         All
+RandLevel       5
+
+# --------------------------------------------------- special armor
+Name            Kai Tunic
+Special
+Type            Armor
+Cost            750
+ArmorStr        +3
+Requirements
+Agility         9
+Dexterity       8
+Village         All
+RandLevel       3
+
+Name            Hero's Armor
+Special
+Type            Armor
+Cost            2250
+ArmorStr        +4
+Agility         -2
+Dexterity       -1
+Charisma        +2
+Requirements
+Strength        12
+Dexterity       10
+Village         All
+RandLevel       2
+
+Name            Rags
+Type            Armor
+Special
+Cost            50
+ArmorStr        +1
+Village         All
+RandLevel       5
+
+
+# Shields
+# --------------------------------------------------- level 0 shields
+
+Name            Wooden Shield
+Type            Shield
+Cost            150
+ArmorStr        +1
+Requirements
+Strength        10
+Energy          120
+RandLevel       6
+
+Name            Iron Shield
+Type            Shield
+Cost            250
+ArmorStr        +2
+Dexterity       -1
+Energy          160
+Requirements
+Strength        13
+RandLevel       6
+
+Name            Platinum Shield
+Type            Shield
+Cost            450
+Charisma        +1
+ArmorStr        +2
+Energy          200
+Requirements
+Strength        11
+RandLevel       6
+
+# --------------------------------------------------- level 1 shields
+Name            Crystal Shield
+Level           1
+Type            Shield
+Cost            650
+Charisma        +3
+ArmorStr        +3
+Requirements
+Strength        12
+Agility         8
+RandLevel       5
+
+# --------------------------------------------------- special shields
+Name            Hero's Shield
+Special
+Type            Shield
+Cost            2500
+Charisma        +5
+ArmorStr        +4
+Requirements
+Strength        13
+Agility         10
+RandLevel       2
+
+
+
+# special items --------------------------------------------------------------
+Name            Silver Mace
+Type            Weapon
+Special
+Cost            650
+Strength        +6
+Dexterity       +1
+Requirements
+Strength        3
+Agility         3
+Dexterity       5
+Energy          79
+RandLevel       3
+
+Name            Lion's Shield
+Special
+Type            Shield
+Cost            700
+ArmorStr        +2
+Requirements
+Strength        7
+Energy          80
+RandLevel       2
+
+Name            Battle Axe
+Special
+Type            Weapon
+Cost            500
+Strength        +9
+Dexterity       -1
+Agility         -2
+Charisma        +1
+Requirements
+Strength        15
+Energy          400
+RandLevel       2
+
+# -----------------------------------------------------------------------------
+# Scrolls
+# -----------------------------------------------------------------------------
+
+# --------------------------------------------------- Level 0 scrolls
+Name            Flame Scroll
+Type            Scroll
+Cost            1000
+Uses            3
+Spell           8
+RandLevel       8
+
+Name            Summon Scroll
+Type            Scroll
+Cost            1200
+Uses            4
+Spell           6
+RandLevel       5
+
+Name            Banish Scroll
+Type            Scroll
+Cost            2500
+Uses            5
+Spell           7
+RandLevel       4
+
+Name            Summon Khaos
+Level           2
+Type            Scroll
+Cost            8500
+Uses            1
+Spell           26
+RandLevel       4
+
+Name            Summon Dragon
+Level           3
+Type            Scroll
+Cost            6500
+Uses            1
+Spell           27
+RandLevel       3
+
+Name            Ice Blast
+Level           4
+Type            Scroll
+Cost            4500
+Uses            2
+Spell           28
+RandLevel       4
+
+
+# -----------------------------------------------------------------------------
+# Books
+# -----------------------------------------------------------------------------
+
+# --------------------------------------------------- Level 0 books
+Name            Book of Stamina
+Type            Book
+Cost            13500
+HPAdd           +5
+Village         ALL
+RandLevel       2
+
+Name            Book of Mana
+Type            Book
+Cost            10000
+SPAdd           +2
+Village         ALL
+RandLevel       2
+
+Name            Book of Healing
+Type            Book
+Cost            15000
+Spell           2
+Village         ALL
+RandLevel       2
+Requirements
+Wisdom          10
+
+
+Name            Book of Flames
+Type            Book
+Cost            9500
+Spell           8
+Village         ALL
+RandLevel       10
+Requirements
+Wisdom          10
+
+Name            Book of the Dead I
+Level           2
+Type            Book
+Cost            15000
+Spell           6
+Village         ALL
+RandLevel       1
+Requirements
+Wisdom          10
+
+Name            Book of the Dead II
+Level           3
+Type            Book
+Cost            10000
+Spell           7
+Village         ALL
+RandLevel       2
+Requirements
+Wisdom          10
+
+Name            Book of Destruction
+Level           4
+Type            Book
+Cost            25000
+Spell           12
+Village         ALL
+RandLevel       2
+Requirements
+Wisdom          10
diff --git a/src/doors/clans-devkit/LIST.ASC b/src/doors/clans-devkit/LIST.ASC
new file mode 100644
index 0000000000000000000000000000000000000000..88cfdfb65eb343d0e2f5b6c01e443bb7533de371
--- /dev/null
+++ b/src/doors/clans-devkit/LIST.ASC
@@ -0,0 +1,22 @@
+%C|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
+  |14Top Players
+|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
+  |13No.6         |12   321,239,486,352 XP   |09Level XXIII  |11Kingdom of Peasants
+  |13O.J. Simpson |12    45,523,074,630 XP   |09Level XXII   |11Kingdom of Lies
+  |13Joe Blow     |12    23,636,534,605 XP   |09Level XXI    |11Kingdom of Blowholes
+  |13Evil Doer    |12     6,666,666,666 XP   |09Level XX     |11Kingdom of Satan
+  |13The Clap     |12     3,079,023,054 XP   |09Level XIX    |11Kingdom of Satan
+  |13Widowmaker   |12     1,075,598,743 XP   |09Level XVII   |11Kingdom of Widows
+  |13Layman       |12        94,078,746 XP   |09Level XV     |11Kingdom of Lay-Me
+  |13The Doctor   |12        45,065,045 XP   |09Level XIIV   |11Kingdom of Hospital
+  |13Dude         |12               548 XP   |09Level II     |11Kingdom of Dudes
+  |13I Suck       |12                23 XP   |09Level I      |11Kingdom of Dudes
+%P  |13John Doe     |12                13 XP   |09Level I      |11Kingdom of John
+  |13Frank        |12                 2 XP   |09Level I      |11Kingdom of John
+  |13Tom          |12                 2 XP   |09Level I      |11Kingdom of Shmoes
+  |13Dick         |12                 1 XP   |09Level I      |11Kingdom of Shmoes
+  |13Harry        |12                 0 XP   |09Level I      |11Kingdom of Shmoes
+  |13This Game Sux|12                 0 XP   |09Level I      |11Kingdom of Sux
+  |13Newbie       |12                 0 XP   |09Level I      |11Kingdom of Newbies
+  |13I Hate Doors |12                 0 XP   |09Level I      |11Kingdom of IDoors
+  |13Napolean     |12                 0 XP   |09Level I      |11Kingdom of France
diff --git a/src/doors/clans-devkit/MENUS.HLP b/src/doors/clans-devkit/MENUS.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..a0c5b8f20a60b31954de00cc7d0b81860a1d239f
--- /dev/null
+++ b/src/doors/clans-devkit/MENUS.HLP
@@ -0,0 +1,407 @@
+Menus
+
+^Mine Menu
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A Level |0B%M |0Aof Mine.  |0B%F |0Afights remaining.
+
+|0A (|0BL|0A) |0CLook for Creatures     |0A (|0BW|0A) |0CWho's here?
+|0A (|0BC|0A) |0CChange Mine Level      |0A (|0BF|0A) |0CFight another clan
+|0A (|0BG|0A) |0CGo on A Quest          |0A (|0B/|0A) |0CChat with Villagers in area
+|0A (|0BV|0A) |0CView Your Stats        |0A (|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Main Menu1
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BE|0A) |0CEnter the Mines    |0A(|0BU|0A) |0CThe Church      |038888888888888888888888888888888888
+|0A (|0BV|0A) |0CView Your Stats    |0A(|0BW|0A) |0CWorld Travel    |03888888 |07s s s |0388888 |07s s s |03888888888
+|0A (|0BM|0A) |0CThe Market         |0A(|0BP|0A) |0CEmpire          |03888888 |07$$$$$ |03""""" |07$$$$$ |03""""Y8888
+|0A (|0BC|0A) |0CCommunications     |0A(|0BT|0A) |0CTown Hall       |03888888 |07$$^$$$$$$$$$$$^$$ |02dSSb.|03`Y88
+|0A (|0BA|0A) |0CAlliances          |0A(|0BH|0A) |0CTraining Hall   |038888P' |07$$$$$$$|06d$b|07$$$$$$$ |02$$$$$b. |03`
+|0A (|0B/|0A) |0CChat w/Villagers   |0A(|0BN|0A) |0CNewbie Help     |0388'|02.sS |07$$$$$$$|06$$$|07$$$$$$$ |02$$$$$$$$b
+|0A (|0B!|0A) |0CDisband Clan       |0A(|0BQ|0A) |0CQuit            |02sssSSbsaaaaaa,aa.aaasaasdSSSSSSSSS
+|0A  |0B |0A  |0C                   |0A |0B |0A  |0C                |02SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Main Menu2
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BE|0A) |0CEnter the Mines    |0A(|0BU|0A) |0CThe Church      |072SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS2|04
+|0A (|0BV|0A) |0CView Your Stats    |0A(|0BW|0A) |0CWorld Travel    |07SSSSSSSSSSSP"'|04.ssss.|07`"YSSSSSSSSSSS
+|0A (|0BM|0A) |0CThe Market         |0A(|0BP|0A) |0CEmpire          |07SSSSSSSSSS'|04.sSSSSSSSSs.|07`SSSSSSSSSS
+|0A (|0BC|0A) |0CCommunications     |0A(|0BT|0A) |0CTown Hall       |07SSSSSSSSSS |04SSSSSSSSSSSS |07SSSSSSSSSS
+|0A (|0BA|0A) |0CAlliances          |0A(|0BH|0A) |0CTraining Hall   |07SSSSSSSSSS |04SSSSSSSSSSSS |07SSSSSSSSSS
+|0A (|0B/|0A) |0CChat w/Villagers   |0A(|0BN|0A) |0CNewbie Help     |07SSSSSSSSSSb|04`齋SSSSSSS�'|07dSSSSSSSSSS
+|0A (|0B!|0A) |0CDisband Clan       |0A(|0BQ|0A) |0CQuit            |07SSSSSSSSSSSSb.|04`'|07.dSSSSSSSSSSSS
+|0A  |0B |0A  |0C                   |0A |0B |0A  |0C                |072SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS2
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Main Menu3
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BE|0A) |0CEnter the Mines    |0A(|0BU|0A) |0CThe Church      |12s.  |07""SSSSSSSSSSSSSSSSSbsa, |04`"YSSS
+|0A (|0BV|0A) |0CView Your Stats    |0A(|0BW|0A) |0CWorld Travel    |12SSSbs   |07`""SSSSSSSSSSSSSSSSSbsa,|04`"
+|0A (|0BM|0A) |0CThe Market         |0A(|0BP|0A) |0CEmpire          |12SSSSSSbs|07     SSSSSP' |04,|07`""SSSSSSb
+|0A (|0BC|0A) |0CCommunications     |0A(|0BT|0A) |0CTown Hall       |12SSSSSSSSb|07     SSSSb, |04YSSbsa |07,  '�'
+|0A (|0BA|0A) |0CAlliances          |0A(|0BH|0A) |0CTraining Hall   |12SP"'   |07___ssssSSSSSSb.|04`YYY |07aSSs,|04`S
+|0A (|0B/|0A) |0CChat w/Villagers   |0A(|0BN|0A) |0CNewbie Help     |12S  |07aSSSSSSSSSSSSSSSSSSb,.|04`,s.|07`SSb
+|0A (|0B!|0A) |0CDisband Clan       |0A(|0BQ|0A) |0CQuit            |12Sb. |07`YSSP""SSb,  `齓SSSSSSsa,dSSSS
+|0A  |0B |0A  |0C                   |0A |0B |0A  |0C                |12SSSba.    |07dSS'Yb.   `"YSSSSSSSSSSS
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Main Menu4
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BE|0A) |0CEnter the Mines    |0A(|0BU|0A) |0CThe Church      |04SSSSSSSS |07SSSSSSSSSSSSSSSS |04SSSSSSSS
+|0A (|0BV|0A) |0CView Your Stats    |0A(|0BW|0A) |0CWorld Travel    |04SSSSSSSS |07SSSS"'|04,ss.|07`"SSSS |04SSSSSSSS
+|0A (|0BM|0A) |0CThe Market         |0A(|0BP|0A) |0CEmpire          |04SSSSSSSS |07SY"' |04ASSSSA |07`"YS |04SSSSSSSS
+|0A (|0BC|0A) |0CCommunications     |0A(|0BT|0A) |0CTown Hall       |04SSSSSSSS |07S |04nAnSSSSSSnAn |07S |04SSSSSSSS
+|0A (|0BA|0A) |0CAlliances          |0A(|0BH|0A) |0CTraining Hall   |04SSSSSSSS |07S.|04`YSSSSSSSSY'|07,S |04SSSSSSSS
+|0A (|0B/|0A) |0CChat w/Villagers   |0A(|0BN|0A) |0CNewbie Help     |04SSSSSSSS |07SS |04zvSSSSSSvs |07SS |04SSSSSSSS
+|0A (|0B!|0A) |0CDisband Clan       |0A(|0BQ|0A) |0CQuit            |04SSSSSSSS |07SSbaaa |04SS |07aaadSS |04SSSSSSSS
+|0A  |0B |0A  |0C                   |0A |0B |0A  |0C                |04SSSSSSSS |07SSSSSSSssSSSSSSS |04SSSSSSSS
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Main Menu5
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BE|0A) |0CEnter the Mines    |0A(|0BU|0A) |0CThe Church      |02SSSSb |15SS |08SSSSSS |07(|06__|07) |03SSSSSSSSSSSSS
+|0A (|0BV|0A) |0CView Your Stats    |0A(|0BW|0A) |0CWorld Travel    |02SSSSSb |15SS |08SSSSY  |1288  |03`"""`SSSSSSSS
+|0A (|0BM|0A) |0CThe Market         |0A(|0BP|0A) |0CEmpire          |02SSSSSSb |15SS |08`"" |07,sSSs|068ASA8 |03SSSSSSSS
+|0A (|0BC|0A) |0CCommunications     |0A(|0BT|0A) |0CTown Hall       |02SSSSSSS, |12SS|07SssS;SSSS|061SXS1 |03SSSSSSSS
+|0A (|0BA|0A) |0CAlliances          |0A(|0BH|0A) |0CTraining Hall   |02SSSSSSSbas.|07`""' YSSS|06`YSP' |03SSSSSSSS
+|0A (|0B/|0A) |0CChat w/Villagers   |0A(|0BN|0A) |0CNewbie Help     |02SSSSSSSSSSb |07sSSSSSSS; |03,ssSSSSSSSSS
+|0A (|0B!|0A) |0CDisband Clan       |0A(|0BQ|0A) |0CQuit            |02SSSSSSSSSSS |07YSS'~`YSS; |03SSSSSSSSSSS
+|0A  |0B |0A  |0C                   |0A |0B |0A  |0C                |02SSSSSSSSSSS |07`SS   `SSS |03YSSSSSSSSSS
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Mines
+|08                                             s
+                                         |08 ,d$$$b.            |07,A,
+                                      |08.ad$$$$$$$$b,       |07,sd$$$bs
+                 |08,A           |07,dAb, |08sd$$$$$$$$$$$$$Ss  |07,sd$$$$$$$$bs
+|07           a   |08,d$$b,     |07,s$$$$$$$b, |08`Y$$$$$$$$$$P'|07,sd$$$$$$$$$$$$$b,
+         ,d$b |08,$$$$$$b |07,d$$$$$$$$$$$$$ba, |08`$$$P'|07,d$$$$$$$$$$$$$$$$$$
+       ,d$$$$b |08�$$$$P |07a$$$$$$$$$$$$$$$$$$$$ba.  ,d$$$$$$$$$$$$$$$$$$$$b,
+     .d$$$$$$$b, |08Y$P |07$$$$$$$$$$$$$$$$$$$$$$$$$$s$$$$$$$$'$$$$$$$$$$$$$$$
+    d$$$$$$$$$$$b.,sd$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  `$$$$$$$$$$$$$$b
+   d$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'|04` '|07$$$$$$$$$$$$$$$$a,
+ ,s$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$'    `$$$$$$$$$$$$$$$$$b
+^END
+
+
+^Title 0
+|13              |09____|05
+ |13$$$$$$$$$$|05$$ |01$$$$|13 |08$|13 |03d|13 |08$P'|11$|13 |08`'|01$$ $|03$|01b |08`$$$|13 |01$$,|13 |01`$$b|13 |11,|13 |08`$|13 |03$ |13 |11$|05
+|13 $$$$|05$$$$$$$$|13 |01$$$$|13  |03$$b.|08`|11d$$b.|01 $,|13 |01`$|03$|01,|13 |08`'|13  |01`$|13 |08`|01 `Y|13 |11d.|13 |03 ,$$|13 |11$|05
+|13 $$|05$$$|13$|05$$$|08$|05$|08$|13 |01$$$$|13 |03$$$$$|11 |08,|11`$$$|01  $|13  |03$|01$$b|13 |11$$$|13 |03 ,$$|13 |01'|11,$$$|13 |03$'|13 |11$$|05
+|13 $|05$$$$$$|08$|05$$$|08$|13 |01$$$$|13 |08b,|13 |03`$$, |11$$|08,|13 |15a |13 |03d$$P'|13 |11$|03'|13  |03d$P'|13   |11`P|13 |03$|13  |11$$$|05
+|13 |05`$$|13$|05$$$$$|08$$'|13 |01$$$$|13 |08P|11,$|13  |03$|13  |11$'|13 |15,$b|13 |03$$|13 |11,d|13 |03'|11 $$|03 $$ |15`$$bs.|13 |01`.|11 $$|05
+|13  |05`$$$$|08$$$P'|13  |01$$$$|13 |11,$$$|15 |08'|15 |11'|15 ,d$$$ |03$|13 |11,$$|15 ,$ |11$$|15 |03`bs.|15`$$$$b,. |01.|05
+ |01   |05`$|08$$$'|01   |13 |01$$$$|13 |11$$'|13 |15 ,sd$$$$$' |13 |11,$$$|15 $$$ |03$|15 |11$|13 |03`$b|13 |15`$$$$$b|05
+             |13 |01$$$$|13 |11`|13 |15,s$$$$$$$$$b |11$$$$|13 |15d$$$$  |11$$$|13 |03$$$|13 |15$$$$$$|05
+|11 ,|_ ||_   _ |13 |01$$$$|13 |15d$$$$$$$$$$$$$b |11$|03'|13 |15d$$$$$$b.|13 |03`|11$|13 |03`$|13 |15$$$$$$|05
+|11 ||  || | |-||13 |01$$$$|13 |15$$$$$$$$$$$$$$$b ,d$$$$$$$$$$b.  ,d$$$$$$|05
+|11 ||/ || | |_,|13 |01$$$$|13 |15$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$|05
+|01    |09_______|01   $$$$    |09 ______    __   _____       _______|05
+|01 ,d$$$$$$$$b, $$$$ ,d$$$$$$$$$b. $$b,$$$$$$$b. ,d$$$$$$$$$b.|05
+|01d$$$$$' ,$$$$ $$$$ $$$P'|09__|01,$$$$$ $$$d$$'`Y$$$$ $$$$P'  Y$$$$|05
+|01$$$$$'  Y$$$P $$$$ ~,sd$$$$$$$$$ $$$$$'  `$$$$ `$$$$$b,.|09__|05
+|01$$$$$   |09 ___|01  $$$$ d$$$$齘`$$$$$ $$$$P   $$$$$ |09__|01 ^齓$$$$$b|05
+|01$$$$$b d$$$$b $$$$ $$$$$b.s$$$$$ $$$$' |09_|01d$$$$$ $$$$b`$$$$$$$|05
+|01`Y$$$$$$$$$P' $$$$ `Y$$$$$$$N6$' $$$$b d$$$$$$ `Y$$$$$$$$$Y'|05
+|01哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪|05
+|07                 copyright 1997 allen ussher
+                         |08<|07paused|08>%Z
+^END
+
+^Title 1
+|07
+        |08軀07                                                          |04軀07  |04遼08哌|07
+             |08遼07                                                   |12軀07       |04軀07
+ |08哪哪 |04踻07 |08哪哪哪哪|07 |04遼12哕|08 哪膢07 苘苘� |08哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪 |04軀12|20軀04|16� |08哪哪哪 |04軀08 哪哪
+|07            |04軀12|20皘04|16圮苘|12軀14瞸07 |12軀07 |04踻07 圹圹� |04圮哕軀07 |04苘苒 |12|20皘07|16 |04苘|07    |04苘苘苒|12|20軀14|16遼12|20軀04|16苘|12|20遼04|16圻 軀07   |04苘踻12|20眧07|16
+        |12遼14軀07  苘苘苘苘苘�  圹圹�  苘苘苘苘苘|12|20眧07|16 苘苘苘苘苘�   苘苘苘苘苘軀04 |12|20皘04|16遼07
+           圹圹�   圹圹� 圹圹� 圹圹�  圹圹� 圹圹�  圹圹� 圹圹圮苘苘苘     |04軀07
+         |04迀07 圹圹�         圹圹�        圹圹� 圹圹�  圹圹� 苘苘�  圹圹踻04 輡07
+         |04迀07 圹圹�   苘苘� 圹圹� 苒圹圻咣圹圹 圹圹�  圹圹� 圹圹�  圹圹� |04踻07       |04�
+|07         |04踻07 圹圹�   圹圹� 圹圹� 圹圹�  圹圹� 圹圹�  圹圹� 咣圹�  圹圹� |14踻04圮|07   |04遼07
+        |04迀12|20眧07|16 |12|20眧07|16哌哌哌哌哌哌 圹圹� 哌哌哌哌哌哌 哌哌�  哌哌|12|20眧08|16遼07 |08軀07 哌哌哌哌� |12|20遼04|16遼07
+         |04遼07 |12|20皘04|16 哌哌哌遼12|20軀04|16踻12軀20軀07|16 圹圹� |12|20遼04|16苓遼12遼20瞸16遼04哌|12踻04苓|07 |04苓|12遼07 |04哌咣遼12|20眧07|16 |12|20皘07|16   |04遼07           |04遼07
+        |04遼07   |04 |07         |04遼14軀07 圹圹� |04踻12遼07   |12|20眧07|16    |04遼07          |04遼12|20皘04|16 |07      |12遼04遼12軀07        |08踻07
+ |08哪哪� |04踻08 哪哪哪哪哪哪膢07膢15膢07 哌哌� |08哪哪|04 |12|20皘04|16 |08哪哪哪哪哪哪哪哪哪哪哪哪哪哪|07 |04遼07  |08軀07 |08哪哪哪�
+       |12遼08            |07 |12遼08         Copyright 1997 Allen Ussher|07
+         |08哕|07  |04軀07   |04遼12遼07                 |04  |07
+
+                                    |08<|04pause|08>%Z
+%Z
+^END
+
+^Title 2
+`00`07
+
+        `0D躟5D盽05圻咣圮`07                                         `04苘苘苘躟07
+       `5D脖癭07    `05圹�   `0D�    `08the Clans`07                    `04苒圹圹圹圹圹躟07
+      `5D脖癭05�    `5D癭05圹`58癭07 `5D脖`07                              `04苒圹`4C盽04圹圹`4C盽04圹咣圹踐07
+      `5D�  `05踐07         `5D卑`07  `0D躟5D癭05咣�   `0D躟5D盽05咣�   `0D躟5D盽05咣躟07      `04圮`4C盽04圹咣圻圹踐4C癭04圹咣`48癭04輅07
+      `05圹`5D癭05�    苘苘 `5D癭05� 躟5D癭07   `05圹 `0D躟5D瞏07   `5D盽05� `0D躟5D瞏05�  哌    `04� 苘圻  違48癭04違4C癭07 `04� `07� `04踐48癭04踐07
+      `05咣踐58癭07    `5D卑`58癭05� 踐58癭07 `5D癭05�   踐58癭07 `5D盽05�   `5D癭58癭07 `05違5D卑`05圹躟07        `04哌 `07圻 苘  苒 `04苒踐48盽07
+       `05咣`58癭05�  躟5D癭58癭05�  `58氨`07 `05咣� 躟58氨`07 `5D癭58癭07   `5D癭58盽07    `05哌`5D癭58癭07      `04� 圯`07轥7F癭07踐7C癭07圹圹`78癭07� `04違48氨`07
+         `05哌哌哌   哌�   哌� � 哌   哌`07     `05躟58氨`07      `04躟4C癭04圮 `07咣踐74躟07圹`78鞍`07� `4C癭48盽04輅07
+      `0D哌`5D膊北鞍`05踐5D癭05圹圹`5D癭05圹圹`58癭05圹圹`5D癭05圹踐58癭05圹圹`58癭05踐58氨`05�    `04� 苓苒`4C盽48癭07  咣圻� `04苓圻`07
+                  `02苘躟07     `02躟07                          `04哌哌  `07� `04苓哌`07
+         `28躟02圹圮 躟28氨`02圹`07     `02躟28盽02圹躟07                  `01躟07        苘踐7F癭07苒苘   `01躟07
+        `42違02圻 `2E癭02�  咣`28癭02�   苒`28瞏02踐28辈癭02圹   苓哕躟07         躟01咣`19躟01苘`07哌 哌�  `01苘苘圮圹哌`07
+      `04苓  `02轥2E盽02�    � 苘苘苘哌哌哌圮  `2A盽02�  苒`07       轥7F癭07� `01踐19圮躟01圹苘圹`19苘`01圹哌� `07苒
+          `2E瞏02�   苘踐2A安盽02圹`2A盽02哌咣圮躟07     `02躟2A癭02圻`07        圹`78癭07� `01違19卑`01圮圹違19斑`01圹圹 `7F癭07圹`78癭07�
+       `02哕踐2E卑`02躟2A卑`02圻� � � 哕    哌咣圹哌`07           The Clans copyright 1996
+        `02� 哌哌圮`07                                      Allen Ussher
+
+                 `01鷃07        `09�   `03腵0B腵0F� `07p a u s e d `0F臽0B腵03� �    `09�    `01鷃07
+%Z
+^END
+
+^Clan Title
+
+|15  T   h   e       C   l   a   n   s |07%V
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐屯
+|07 |08哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪� � 哪哪哪|07             |08哪哪哪 哪哪哪哪 哪膢07
+|08 哪哪哪哪�   哪哪�    |14軀06苘苘� |14軀06苘軀14|22皘04|16� � |15苘苘苘|07苘軀15苘|07苘苘苘|15軀07� |08� |07苘 |08�  哪哪哪哪  膢07
+              |14軀06苘軀14遼06咣圮圹� 圻圹|08|22皘04皘06|16� |14|22眧07|16   遼08遼07哌哌|08哌|07哌遼08哌哌 |01苘苘軀07遼04苓|07�    |08哪哪膢07
+|08 哪哪哪哪�  |14苘|06苘苘 |14苘|06苘苘  圹臂|14|22皘06|16圮|04|22皘07|16 |04� |08|22瞸04|16苓 圮 |14|22瞸04|16遼12|20眧04|16�  �  |01哌|09|17脖|01|16圹� |07遼15|23卑|07|16圮         |08膢07
+|08 哪�  �    |14|22皘06|16� 咣圹遼14|22脖|06|16踻14|22皘06|16哕�  咣 圹踻04|22眧08眧04瞸07|16 |06踻08|22瞸07|16 |12|20皘07|16   |04苘  |06圮 �  |07� |01踻09|17舶|01|16�  |07軀15|23皘07|16圻     |08哪哪|07
+|08 哪�    �  |06遼14|22脖|06|16� 咣踻14|22皘06|16圻 |14|22皘06|16� 苒 迀14|22眧08皘04皘06|16圮�  |04苓|06哕|04� |06遼04� |06� �  |08哪  |01� |04苘苒� |07圻  |08哪哪哪  膢07
+|08 哪 哪 �   |06圻圮|04|14|22安|06|16�  |04䙡06捋圹|14|22眧07|16 |06圻圹苓哌遼07                 |12遼20皘04|16圹圹|12|20眧04|16遼07
+|04 |08�  哪哪哪� |14|22眧06|16圻� 哌哌 哌哕曹 圹|04|22眧08眧07|16  |08哪哪哪 哪   �   |07苘圹 |04咿踻12|20皘04|16苘|07
+       |04� 苘|07迀15哌舶遼07遼15遼07輡14|22皘06|16咣� |08|22皘06|16遼07            �   苘迀15|23皘07|16圻�    |04捋圮� |08哪哪哪哪哪哪|07
+     |04�   � 遼12|20皘07|16  |12|20皘15|16輡04軀15苘 苻|06苒圹  |08�   哪哪 哪 |15|23皘07|16� |12|20眧07|16 |15|23眧07|16圹哌     |05� |04� 咣 |05軀07       |08哪 哪膢07
+|08   |04�   哌 �  苘� |06� 苘苘軀08|22皘06|16�   |08哪哪哪哪�    膢07         |05苘槽圹圹� 苒踻07       |08� 哪膢07
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐屯
+|0A (|0BE|0A) |0CEnter Game        |0A (|0BV|0A) |0CVillage Stats  |0A (|0BG|0A) |0CGame Settings
+|0A (|0BS|0A) |0CSee Scores        |0A (|0BH|0A) |0CHelp           |0A (|0BL|0A) |0CLeague Scores
+|0A (|0BT|0A) |0CToday's News      |0A (|0BI|0A) |0CInstructions   |0A (|0BQ|0A) |0CQuit
+|0A (|0BY|0A) |0CYesterday's News  |0A (|0BB|0A) |0CBulletins
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐屯
+^END
+
+^Main Title
+          |04the |0B_______  |0A $$$$     |0B______    __   _____       _______|0A
+           ,d$$$$$$$$b, $$$$ ,d$$$$$$$$$b. $$b,$$$$$$$b. ,d$$$$$$$$$b.
+|07<><><><>|0A  d$$$$$' ,$$$$ $$$$ $$$P'|0B__|0A,$$$$$ $$$d$$'`Y$$$$ $$$$P'  Y$$$$ |07<><><><>
+|07><><><><|0A  $$$$$'  Y$$$P $$$$ ~,sd$$$$$$$$$ $$$$$'  `$$$$ `$$$$$b,.|0B__|0A   |07><><><><
+|07<><><><>|0A  $$$$$    |0B___|0A  $$$$ d$$$$齘`$$$$$ $$$$P   $$$$$ |0B__|0A ^齓$$$$$b  |07<><><><>
+|07><><><><|0A  $$$$$b d$$$$b $$$$ $$$$$b.s$$$$$ $$$$' |0B_|0Ad$$$$$ $$$$b`$$$$$$$ |07><><><><|0A
+          `Y$$$$$$$$$P' $$$$ `Y$$$$$$$N6$' $$$$b d$$$$$$ `Y$$$$$$$$$Y'
+^END
+
+^Travel Menu
+ |0BTravel Menu
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BS|0A) |0CSee Current Travel Info
+|0A (|0BO|0A) |0CView Other Villages in league
+|0A (|0BT|0A) |0CTravel to Another Village
+|0A (|0BV|0A) |0CView Your Stats
+|0A (|0BH|0A) |0CHelp on Villages and Travel
+|0A (|0BQ|0A) |0CQuit to Town
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Market Menu
+ |0BThe Market : Level %X
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BW|0A) |0CBuy Weapon             |07                                  |06  asa
+ |0A(|0BA|0A) |0CBuy Armor              |07  ,sssssssssssssssssssssssssssssss|06 dMMMbmmmmmmmm,
+ |0A(|0BS|0A) |0CBuy Shield             |07a$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$|06 MMMMMWWWWWWWWW
+ |0A(|0BP|0A) |0CPawn Shop              |07 `Y$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$|06 YMMMPWWWWWWWP'
+ |0A(|0BZ|0A) |0CWizard's Shop          |07                                  |06 `YMP'
+ |0A(|0BT|0A) |0CTrade with Other Clans
+ |0A(|0BV|0A) |0CView Your Stats
+ |0A(|0B/|0A) |0CChat w/Villagers
+ |0A(|0BQ|0A) |0CQuit to Town
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Mail Menu
+|0B Communications
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0BC|0A) |0CCheck Mail                             |01$$$b |09'"齘~~~^�"` |01d$$$
+|0A (|0BW|0A) |0CWrite Mail                             |01$$$$$ |07"黃$$$$$$$$$$$$$$$S�" |01$$$$$
+|0A (|0BP|0A) |0CWrite Public Mail                      |01$$$$$ |07$bs.`"黋$$$$$P�"',sd$ |01$$$$$
+|0A (|0BU|0A) |0CUpdate Lastread Pointer                |01$$$$$ |07$$$$$bs,.`"'.,sd$$$$$ |01$$$$$
+|0A (|0BV|0A) |0CView Your Stats                        |01$$$$$ |07$$$$$$$$$$s$$$$$$$$$$ |01$$$$$
+|0A (|0BG|0A) |0CGlobal Post                            |01$$$P' |07$$$$$$$$$$$$$$$$$$$$$ |01`Y$$$
+|0A (|0BQ|0A) |0CQuit to Town                           |01$P'|09,dsssssssssssssssssssssssb.|01`Y$
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Help Menu
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0B1|0A) |0CItems
+|0A (|0B2|0A) |0CRaces & Classes
+|0A (|0B3|0A) |0CGeneral
+|0A (|0B4|0A) |0CCombat
+|0A (|0B5|0A) |0CStrategies
+|0A (|0B6|0A) |0CNewbie Help
+|0A (|0B7|0A) |0CAttributes
+|0A (|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Church Menu
+
+|0A (|0BM|0A) |0CAttend Mass                            |0A  .s黕~^~^s.  .sS$$$$Ss.
+|0A (|0BP|0A) |0CPray                                   |0A d          bd$$$$$$$$$$b
+|0A (|0BB|0A) |0CAsk for Blessing                       |0A$            $$$$$$$$$$$$$
+|0A (|0BD|0A) |0CResurrect Dead Member                  |0A$            $$$$$$$$$$$$$
+|0A (|0BU|0A) |0CResurrect Unconscious Member           |0A b.        .dY$$$$$$$$$$Y
+|0A (|0BV|0A) |0CView Stats                             |0A  `黶.,.,s�'   黃$$$$S�
+|0A (|0B/|0A) |0CChat w/Villagers
+|0A (|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Training Hall
+
+|0A (|0BT|0A) |0CTrain a member
+|0A (|0BA|0A) |0CAdd a new member
+|0A (|0BL|0A) |0CRelease member
+|0A (|0B/|0A) |0CChat w/Villagers
+|0A (|0BV|0A) |0CView Stats
+|0A (|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+# make this an option in the future?!
+# |0A(|0BF|0A) |0CFine a Clan                 |0A(|0BI|0A) |0CInvestigate Clan
+^Town1
+ |0A(|0BE|0A) |0CEconomics Menu              |0A(|0BC|0A) |0CChange Colour Scheme
+ |0A(|0BL|0A) |0CChange Flag                 |0A(|0BS|0A) |0CStructures
+ |0A(|0BR|0A) |0CConscription Rate           |0A(|0BM|0A) |0CMake Announcement
+ |0A(|0BD|0A) |0CPublic Discussion           |0A(|0BP|0A) |0CVillage Empire
+ |0A(|0BH|0A) |0CRuling Help                 |0A(|0BV|0A) |0CView Clan Stats
+ |0A(|0B!|0A) |0CAbdicate                    |0A(|0BB|0A) |0CVoting Booth
+ |0A(|0B/|0A) |0CChat w/Villagers            |0A(|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Town2
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BW|0A) |0CWrite to Ruler                 |0A(|0BD|0A) |0CDeposit into Vault
+ |0A(|0BE|0A) |0CDonate to Village Empire       |0A(|0BB|0A) |0CVoting Booths
+ |0A(|0BP|0A) |0CPublic Discussions             |0A(|0B/|0A) |0CChat w/Villagers
+ |0A(|0BS|0A) |0CSee Village Empire Stats       |0A(|0BV|0A) |0CView Clan Stats
+ |0A(|0BH|0A) |0CHelp                           |0A(|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Eliminated
+
+ |02You have been eliminated from play by another clan!  You may wish to see
+ the daily news for information on who caused your destruction.
+
+ |10After you exit the door, you may enter it again and start over.
+
+%P
+^END
+
+^Item Help
+
+|0A(|0BL|0A)|0Cist items                -- list items in inventory
+|0A(|0BE|0A)|0Cquip an item             -- use an item
+|0A(|0BD|0A)|0Crop item                 -- remove item from inventory
+|0A(|0BS|0A)|0Ctop using item           -- stop using an equipped item
+e|0A(|0BX|0A)|0Camine item              -- see an item's statistics
+|0A(|0BR|0A)|0Cead book                 -- read a book
+
+^END
+
+^Take Item Help
+
+|0A(|0BL|0A)|0Cist items                -- list items in inventory
+|0A(|0BT|0A)|0Cake an item              -- use an item
+e|0A(|0BX|0A)|0Camine item              -- see an item's statistics
+
+^END
+
+
+^Pawn Menu
+ |0BPawn Shop : Level %1
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BB|0A) |0CBuy items              |0A(|0BS|0A) |0CSell items
+ |0A(|0BV|0A) |0CView Clan Stats        |0A(|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Empire Menu
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BB|0A) |0CBuild Structure        |0A(|0BM|0A) |0CManage Army
+ |0A(|0BA|0A) |0CAttack an Empire       |0A(|0BS|0A) |0CSpy on an Empire
+ |0A(|0BD|0A) |0CDonate to Empire       |0A(|0BL|0A) |0CDevelop Land
+ |0A(|0BH|0A) |0CHelp on Empires        |0A(|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+# |0A(|0BS|0A) |0CSee relations
+^Alliance
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BW|0A) |0CWrite to allies             |0A(|0BL|0A) |0CList alliance members
+ |0A(|0BI|0A) |0CInvite clan into alliance   |0A(|0BR|0A) |0CRemove clan from alliance
+ |0A(|0B!|0A) |0CRemove self from alliance   |0A(|0BS|0A) |0CSee member's stats
+ |0A(|0BC|0A) |0CChat Room                   |0A(|0BD|0A) |0CDonation Room
+ |0A(|0BP|0A) |0CManage Empire               |0A(|0B*|0A) |0CDestroy Alliance
+ |0A(|0BV|0A) |0CView Clan Stats             |0A(|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Disbanded
+|09You have disbanded your clan and cannot play again until tomorrow!
+%P
+^END
+
+^Voting Booth
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BC|0A) |0CChange Vote
+ |0A(|0BV|0A) |0CView Clan Stats
+ |0A(|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Wizard Menu
+ |0BWizard's Shop : Level %2
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+ |0A(|0BB|0A) |0CBuy Book               |0A(|0BS|0A) |0CBuy Scroll
+ |0A(|0BX|0A) |0CExamine Item           |0A(|0BV|0A) |0CView Your Stats
+ |0A(|0BQ|0A) |0CQuit to Town
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Donate To Empire1
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0B1|0A) |0CDonate Followers            |0A (|0B2|0A) |0CDonate Footmen
+|0A (|0B3|0A) |0CDonate Axemen               |0A (|0B4|0A) |0CDonate Knights
+|0A (|0B5|0A) |0CDonate Land                 |0A (|0BV|0A) |0CView Stats
+|0A (|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Donate To Empire2
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+|0A (|0B1|0A) |0CDonate Followers            |0A (|0B6|0A) |0CTake Followers
+|0A (|0B2|0A) |0CDonate Footmen              |0A (|0B7|0A) |0CTake Footmen
+|0A (|0B3|0A) |0CDonate Axemen               |0A (|0B8|0A) |0CTake Axemen
+|0A (|0B4|0A) |0CDonate Knights              |0A (|0B9|0A) |0CTake Knights
+|0A (|0B5|0A) |0CDonate Land                 |0A (|0B0|0A) |0CTake Land
+|0A (|0BA|0A) |0CDonate Gold                 |0A (|0BB|0A) |0CTake Gold
+|0A (|0BV|0A) |0CView Stats                  |0A (|0BQ|0A) |0CQuit
+|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯�
+^END
+
+^Special
+%C|13 Special Deals on Allen Ussher's Doors
+
+|07 I am having a door sale!  See the (B)ulletins for info in the pre-game
+ menu of The Clans.
+
+^PAUSE
+^END
diff --git a/src/doors/clans-devkit/MONSTERS.TXT b/src/doors/clans-devkit/MONSTERS.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..86bdcae01b6e46b295877f93d93af2a10d57d120
--- /dev/null
+++ b/src/doors/clans-devkit/MONSTERS.TXT
@@ -0,0 +1,1817 @@
+# 1 ---------------------------------------------------------------------------
+Name            Mangy dog
+HP              7
+Difficulty      1
+Agility         5
+Dexterity       8
+Strength        11
+Wisdom          1
+Armorstr        0
+
+Name            Cave Dweller
+HP              10
+Difficulty      1
+Agility         5
+Dexterity       7
+Strength        9
+Wisdom          3
+Armorstr        0
+
+Name            Witch
+HP              13
+SP              10
+Difficulty      1
+Strength        8
+Agility         8
+Dexterity       5
+Wisdom          10
+ArmorStr        0
+Spell           10
+
+Name            Giant Rat
+HP              14
+Difficulty      1
+Strength        8
+Agility         8
+Dexterity       9
+Wisdom          1
+ArmorStr        0
+
+Name            Ogre
+HP              13
+Difficulty      1
+Strength        10
+Agility         9
+Dexterity       8
+Wisdom          1
+ArmorStr        0
+
+Name            Zombie
+HP              9
+Difficulty      1
+Strength        11
+Agility         8
+Dexterity       8
+Wisdom          3
+ArmorStr        0
+Undead
+
+Name            Evil Wizard
+HP              15
+SP              20
+Difficulty      1
+Strength        9
+Agility         8
+Dexterity       9
+Wisdom          3
+Spell           1
+Spell           5
+Spell           8
+Spell           15
+ArmorStr        0
+
+Name            Troll
+HP              12
+Difficulty      1
+Strength        12
+Agility         6
+Dexterity       7
+Wisdom          2
+ArmorStr        0
+
+Name            Ratman
+HP              13
+Difficulty      1
+Strength        10
+Agility         6
+Dexterity       9
+Wisdom          2
+ArmorStr        0
+
+Name            Rockman
+HP              12
+Difficulty      1
+Strength        12
+Agility         10
+Dexterity       9
+Wisdom          3
+ArmorStr        0
+
+Name            Beast
+HP              14
+Difficulty      1
+Strength        10
+Agility         9
+Dexterity       7
+Wisdom          1
+ArmorStr        0
+
+Name            Grue
+HP              13
+Difficulty      1
+Strength        10
+Agility         9
+Dexterity       10
+Wisdom          3
+ArmorStr        0
+
+Name            Demon
+HP              14
+Difficulty      1
+Strength        11
+Agility         9
+Dexterity       8
+Wisdom          3
+ArmorStr        0
+
+
+# 2 ---------------------------------------------------------------------------
+Name            Bad Boy
+HP              14
+Difficulty      2
+Strength        10
+Agility         9
+Dexterity       7
+Wisdom          3
+ArmorStr        0
+
+Name            Evil Priest
+HP              15
+SP              13
+Difficulty      2
+Strength        11
+Agility         10
+Dexterity       9
+Wisdom          1
+ArmorStr        0
+Spell           6
+Spell           12
+
+Name            Thief
+HP              15
+SP              11
+Difficulty      2
+Strength        10
+Agility         9
+Dexterity       8
+Wisdom          3
+ArmorStr        0
+Spell           16
+
+Name            Drunken Fool
+HP              16
+Difficulty      2
+Strength        10
+Agility         9
+Dexterity       9
+Wisdom          3
+ArmorStr        0
+
+Name            Beggar
+HP              17
+Difficulty      2
+Strength        11
+Agility         8
+Dexterity       7
+Wisdom          2
+ArmorStr        0
+
+Name            Orc
+HP              19
+Difficulty      2
+Strength        10
+Agility         8
+Dexterity       7
+Wisdom          3
+ArmorStr        0
+
+Name            Warrior
+HP              17
+Difficulty      2
+Strength        11
+Agility         8
+Dexterity       9
+Wisdom          2
+ArmorStr        0
+
+Name            Dark Elf
+HP              17
+Difficulty      2
+Strength        16
+Agility         8
+Dexterity       7
+Wisdom          1
+ArmorStr        0
+
+Name            Goblin
+Difficulty      2
+HP              16
+Agility         7
+Strength        10
+Dexterity       9
+Wisdom          4
+Armorstr        1
+
+Name            Orc
+Difficulty      2
+HP              15
+Agility         8
+Strength        11
+Dexterity       7
+Wisdom          3
+Armorstr        0
+
+
+# 3 ---------------------------------------------------------------------------
+Name            Werewolf
+HP              18
+Difficulty      3
+Strength        12
+Agility         10
+Dexterity       9
+Wisdom          2
+ArmorStr        0
+
+Name            Spirit
+HP              21
+Difficulty      3
+Strength        12
+Agility         10
+Dexterity       11
+Wisdom          3
+ArmorStr        0
+
+Name            Serpent
+HP              20
+Difficulty      3
+Strength        14
+Agility         10
+Dexterity       8
+Wisdom          3
+ArmorStr        1
+
+Name            Bum
+HP              19
+Difficulty      3
+Strength        11
+Agility         10
+Dexterity       11
+Wisdom          1
+ArmorStr        0
+
+Name            Freak
+HP              21
+Difficulty      3
+Strength        13
+Agility         10
+Dexterity       10
+Wisdom          2
+ArmorStr        0
+
+Name            Assassin
+HP              22
+SP              ??
+Difficulty      3
+Strength        11
+Agility         9
+Dexterity       14
+Wisdom          3
+ArmorStr        0
+Spell           5
+Spell           16
+
+Name            Nosferatu
+HP              20
+SP              15
+Difficulty      3
+Strength        12
+Agility         9
+Dexterity       10
+Wisdom          12
+ArmorStr        1
+Spell           19
+Undead
+
+Name            Hellcat
+HP              22
+SP              ??
+Difficulty      3
+Strength        12
+Agility         10
+Dexterity       9
+Wisdom          3
+ArmorStr        0
+Undead
+
+Name            Ugly Hag
+HP              23
+Difficulty      3
+Strength        12
+Agility         9
+Dexterity       9
+Wisdom          2
+ArmorStr        0
+
+Name            Wolf
+HP              17
+Difficulty      3
+Agility         7
+Strength        11
+Wisdom          5
+Dexterity       7
+Armorstr        1
+
+Name            Death Knight
+Difficulty      3
+HP              25
+Agility         6
+Dexterity       5
+Strength        11
+Wisdom          9
+Armorstr        1
+Spell           12
+Spell           13
+SP              25
+
+
+
+# 4 ---------------------------------------------------------------------------
+Name            Shadowspawn
+HP              23
+Difficulty      4
+Strength        14
+Agility         10
+Dexterity       9
+Wisdom          5
+ArmorStr        1
+
+Name            Hound
+HP              22
+SP              ??
+Difficulty      4
+Strength        16
+Agility         11
+Dexterity       10
+Wisdom          6
+ArmorStr        1
+
+Name            Hobgoblin
+HP              25
+Difficulty      4
+Strength        13
+Agility         11
+Dexterity       10
+Wisdom          3
+ArmorStr        1
+
+Name            Lunatic
+HP              23
+Difficulty      4
+Strength        14
+Agility         12
+Dexterity       9
+Wisdom          1
+ArmorStr        1
+
+Name            Giant Spider
+HP              22
+Difficulty      4
+Strength        14
+Agility         11
+Dexterity       9
+Wisdom          2
+ArmorStr        1
+
+Name            Ghoul
+HP              24
+Difficulty      4
+Strength        14
+Agility         12
+Dexterity       9
+Wisdom          3
+ArmorStr        1
+Undead
+
+Name            Tarantula
+HP              25
+Difficulty      4
+Strength        14
+Agility         10
+Dexterity       8
+Wisdom          3
+ArmorStr        1
+
+Name            Manticore
+HP              27
+Difficulty      4
+Strength        15
+Agility         10
+Dexterity       9
+Wisdom          3
+ArmorStr        1
+
+Name            Wight
+HP              26
+SP              ??
+Difficulty      4
+Strength        15
+Agility         11
+Dexterity       10
+Wisdom          2
+ArmorStr        1
+Undead
+
+Name            Giant Ant
+Difficulty      4
+HP              25
+Agility         10
+Strength        16
+Wisdom          7
+Dexterity       8
+Armorstr        2
+
+Name            Wildman
+Difficulty      4
+HP              26
+Agility         12
+Strength        15
+Wisdom          8
+Dexterity       10
+Armorstr        1
+
+Name            Old Hag
+Difficulty      4
+HP              27
+Agility         10
+Strength        16
+Wisdom          8
+Dexterity       8
+Armorstr        2
+
+Name            Ninja
+HP              24
+SP              13
+Difficulty      4
+Agility         11
+Strength        14
+Wisdom          7
+Dexterity       11
+Armorstr        2
+Spell           8
+Spell           9
+
+Name            Wildman
+HP              24
+SP              15
+Difficulty      4
+Agility         12
+Strength        15
+Wisdom          5
+Dexterity       10
+Armorstr        1
+
+Name            Dark Elf
+HP              24
+SP              15
+Difficulty      4
+Agility         13
+Strength        16
+Wisdom          8
+Dexterity       9
+Armorstr        1
+Spell           15
+Spell           10
+Spell           8
+
+Name            Wing-Eye
+HP              23
+Difficulty      4
+Agility         10
+Strength        15
+Wisdom          6
+Dexterity       8
+Armorstr        0
+
+# 5 ---------------------------------------------------------------------------
+Name            Shadow Knight
+HP              22
+SP              10
+Difficulty      5
+Strength        16
+Agility         12
+Dexterity       11
+Wisdom          3
+ArmorStr        3
+Spell           11
+Spell           12
+
+Name            Giant Maggot
+HP              24
+Difficulty      5
+Strength        17
+Agility         11
+Dexterity       7
+Wisdom          4
+ArmorStr        4
+
+Name            Wraith
+HP              25
+SP              10
+Difficulty      5
+Strength        18
+Agility         13
+Dexterity       13
+Wisdom          2
+ArmorStr        3
+Spell           5
+Spell           3
+
+Name            Skeleton
+HP              27
+Difficulty      5
+Strength        18
+Agility         12
+Dexterity       10
+Wisdom          4
+ArmorStr        3
+Undead
+
+Name            Fire Imp
+HP              26
+Difficulty      5
+Strength        17
+Agility         13
+Dexterity       12
+Wisdom          4
+ArmorStr        3
+
+Name            Rock Grub
+HP              24
+Difficulty      5
+Strength        17
+Agility         12
+Dexterity       9
+Wisdom          3
+ArmorStr        2
+
+Name            Dark Soldier
+HP              26
+Difficulty      5
+Strength        18
+Agility         13
+Dexterity       10
+Wisdom          4
+ArmorStr        4
+
+Name            Lizardman
+HP              25
+Difficulty      5
+Strength        17
+Agility         13
+Dexterity       11
+Wisdom          3
+ArmorStr        2
+
+Name            Vampire
+HP              26
+SP              18
+Difficulty      5
+Strength        19
+Agility         13
+Dexterity       9
+Wisdom          14
+ArmorStr        3
+Spell           19
+
+Name            Boulder Beast
+HP              23
+Difficulty      5
+Strength        18
+Agility         14
+Dexterity       10
+Wisdom          3
+ArmorStr        3
+
+# 6 ---------------------------------------------------------------------------
+Name            Giant Centipede
+HP              17
+Difficulty      6
+Strength        19
+Agility         13
+Dexterity       12
+Wisdom          2
+ArmorStr        4
+
+Name            Chaos Lord
+HP              26
+Difficulty      6
+Strength        18
+Agility         14
+Dexterity       12
+Wisdom          4
+ArmorStr        3
+
+Name            Skeleton
+HP              27
+Difficulty      6
+Strength        19
+Agility         13
+Dexterity       10
+Wisdom          4
+ArmorStr        4
+Undead
+
+Name            Minotaur
+HP              28
+Difficulty      6
+Strength        19
+Agility         15
+Dexterity       10
+Wisdom          4
+ArmorStr        5
+
+Name            Green Slyme
+HP              27
+Difficulty      6
+Strength        19
+Agility         13
+Dexterity       9
+Wisdom          4
+ArmorStr        3
+
+Name            Blue Slyme
+HP              26
+Difficulty      6
+Strength        21
+Agility         13
+Dexterity       12
+Wisdom          2
+ArmorStr        4
+
+Name            Red Slyme
+HP              26
+Difficulty      6
+Strength        19
+Agility         14
+Dexterity       10
+Wisdom          3
+ArmorStr        3
+
+Name            Troglodyte
+HP              27
+Difficulty      6
+Strength        20
+Agility         15
+Dexterity       10
+Wisdom          3
+ArmorStr        4
+
+Name            Serpent
+HP              28
+Difficulty      6
+Strength        20
+Agility         13
+Dexterity       11
+Wisdom          4
+ArmorStr        4
+
+Name            Dark Mage
+HP              24
+SP              10
+Difficulty      6
+Strength        21
+Agility         13
+Dexterity       10
+Wisdom          10
+ArmorStr        2
+Spell           8
+Spell           13
+Spell           14
+
+# 7 ---------------------------------------------------------------------------
+Name            Ranger
+HP              29
+Difficulty      7
+Strength        19
+Agility         14
+Dexterity       11
+Wisdom          2
+ArmorStr        4
+
+Name            Shadow
+HP              31
+Difficulty      7
+Strength        20
+Agility         15
+Dexterity       10
+Wisdom          2
+ArmorStr        5
+
+Name            Shadow Wolf
+HP              27
+Difficulty      7
+Strength        20
+Agility         13
+Dexterity       12
+Wisdom          4
+ArmorStr        5
+
+Name            Shadow Knight
+HP              25
+Difficulty      7
+Strength        22
+Agility         14
+Dexterity       10
+Wisdom          4
+ArmorStr        4
+
+Name            Silver Knight
+HP              27
+Difficulty      7
+Strength        21
+Agility         13
+Dexterity       16
+Wisdom          3
+ArmorStr        6
+
+Name            Hell Hound
+HP              28
+Difficulty      7
+Strength        19
+Agility         9
+Dexterity       14
+Wisdom          2
+ArmorStr        5
+
+Name            Witch
+HP              26
+Difficulty      7
+Strength        18
+Agility         15
+Dexterity       11
+Wisdom          3
+ArmorStr        5
+
+Name            Wyvern
+HP              26
+Difficulty      7
+Strength        21
+Agility         16
+Dexterity       10
+Wisdom          4
+ArmorStr        4
+
+Name            Fimir
+HP              25
+Difficulty      7
+Strength        19
+Agility         15
+Dexterity       12
+Wisdom          3
+ArmorStr        5
+
+Name            Demon
+HP              27
+Difficulty      7
+Strength        21
+Agility         16
+Dexterity       11
+Wisdom          3
+ArmorStr        4
+
+# 8 ---------------------------------------------------------------------------
+Name            Orc
+HP              29
+Difficulty      8
+Strength        21
+Agility         14
+Dexterity       11
+Wisdom          4
+ArmorStr        5
+
+Name            Goblin
+HP              28
+Difficulty      8
+Strength        20
+Agility         15
+Dexterity       9
+Wisdom          4
+ArmorStr        3
+
+Name            Gargoyle
+HP              32
+Difficulty      8
+Strength        21
+Agility         14
+Dexterity       11
+Wisdom          4
+ArmorStr        6
+
+Name            Martial Artist
+HP              29
+SP              12
+Difficulty      8
+Strength        20
+Agility         14
+Dexterity       10
+Wisdom          3
+ArmorStr        4
+Spell           21
+Spell           9
+Spell           8
+
+Name            Small Dragon
+HP              30
+SP              15
+Difficulty      8
+Strength        23
+Agility         11
+Dexterity       10
+Wisdom          4
+ArmorStr        5
+Spell           24
+
+Name            Ogre
+HP              31
+Difficulty      8
+Strength        21
+Agility         15
+Dexterity       9
+Wisdom          2
+ArmorStr        5
+
+Name            Orc
+HP              30
+Difficulty      8
+Strength        22
+Agility         14
+Dexterity       11
+Wisdom          4
+ArmorStr        4
+
+Name            Ogre
+HP              29
+Difficulty      8
+Strength        21
+Agility         15
+Dexterity       11
+Wisdom          4
+ArmorStr        5
+
+Name            Dark Knight
+HP              30
+Difficulty      8
+Strength        22
+Agility         16
+Dexterity       11
+Wisdom          4
+ArmorStr        6
+
+Name            Wolf
+HP              31
+Difficulty      8
+Strength        20
+Agility         15
+Dexterity       11
+Wisdom          4
+ArmorStr        5
+
+# 9 ---------------------------------------------------------------------------
+Name            Minotaur
+HP              29
+SP              ??
+Difficulty      9
+Strength        22
+Agility         14
+Dexterity       10
+Wisdom          4
+ArmorStr        6
+
+Name            Blood Fiend
+HP              28
+Difficulty      9
+Strength        21
+Agility         16
+Dexterity       12
+Wisdom          3
+ArmorStr        4
+
+Name            Old Hag
+HP              32
+Difficulty      9
+Strength        22
+Agility         15
+Dexterity       10
+Wisdom          2
+ArmorStr        5
+
+Name            Lunatic
+HP              30
+SP              ??
+Difficulty      9
+Strength        23
+Agility         10
+Dexterity       12
+Wisdom          2
+ArmorStr        3
+
+Name            Ogre
+HP              31
+Difficulty      9
+Strength        24
+Agility         11
+Dexterity       13
+Wisdom          4
+ArmorStr        5
+Spell           18
+
+Name            Boulder Beast
+HP              30
+Difficulty      9
+Strength        23
+Agility         12
+Dexterity       12
+Wisdom          4
+ArmorStr        5
+
+Name            Dark Nun
+HP              32
+Difficulty      9
+Strength        25
+Agility         12
+Dexterity       12
+Wisdom          3
+ArmorStr        4
+
+Name            Large Spider
+HP              34
+Difficulty      9
+Strength        24
+Agility         12
+Dexterity       11
+Wisdom          3
+ArmorStr        3
+
+Name            Giant Ant
+HP              32
+Difficulty      9
+Strength        23
+Agility         11
+Dexterity       10
+Wisdom          2
+ArmorStr        4
+
+Name            Dark Knight
+HP              35
+Difficulty      9
+Strength        22
+Agility         12
+Dexterity       10
+Wisdom          3
+ArmorStr        5
+
+# 10 --------------------------------------------------------------------------
+Name            Spirit
+HP              34
+Difficulty      10
+Strength        24
+Agility         13
+Dexterity       12
+Wisdom          6
+ArmorStr        5
+
+Name            Gargoyle
+HP              34
+Difficulty      10
+Strength        24
+Agility         11
+Dexterity       12
+Wisdom          4
+ArmorStr        4
+
+Name            Demon
+HP              33
+Difficulty      10
+Strength        26
+Agility         10
+Dexterity       11
+Wisdom          5
+ArmorStr        5
+
+Name            Goblin
+HP              34
+Difficulty      10
+Strength        25
+Agility         10
+Dexterity       11
+Wisdom          5
+ArmorStr        6
+
+Name            LizardMan
+HP              35
+SP              ??
+Difficulty      10
+Strength        24
+Agility         12
+Dexterity       10
+Wisdom          4
+ArmorStr        6
+
+Name            Red Devil
+HP              32
+Difficulty      10
+Strength        19
+Agility         10
+Dexterity       12
+Wisdom          4
+ArmorStr        4
+
+Name            Satyr
+HP              34
+Difficulty      10
+Strength        23
+Agility         13
+Dexterity       12
+Wisdom          5
+ArmorStr        5
+
+Name            Ghoul
+HP              32
+Difficulty      10
+Strength        24
+Agility         11
+Dexterity       12
+Wisdom          5
+ArmorStr        3
+Undead
+
+Name            Vampire
+HP              34
+Difficulty      10
+Strength        25
+Agility         11
+Dexterity       11
+Wisdom          5
+ArmorStr        3
+Spell           19
+Undead
+
+Name            Centaur
+HP              32
+SP              10
+Difficulty      11
+Strength        26
+Agility         12
+Dexterity       12
+Wisdom          10
+ArmorStr        5
+Spell           4
+Spell           5
+
+# 11 --------------------------------------------------------------------------
+Name            Giant Millipede
+HP              36
+Difficulty      11
+Strength        26
+Agility         12
+Dexterity       11
+Wisdom          5
+ArmorStr        6
+
+Name            Werewolf
+HP              35
+Difficulty      11
+Strength        27
+Agility         11
+Dexterity       11
+Wisdom          3
+ArmorStr        5
+
+Name            Beast
+HP              42
+Difficulty      11
+Strength        28
+Agility         12
+Dexterity       12
+Wisdom          5
+ArmorStr        6
+
+# 12 --------------------------------------------------------------------------
+Name            Loomer
+HP              43
+SP              ??
+Difficulty      12
+Strength        29
+Agility         12
+Dexterity       11
+Wisdom          3
+ArmorStr        5
+
+Name            Black Goo
+HP              40
+SP              ??
+Difficulty      12
+Strength        28
+Agility         13
+Dexterity       12
+Wisdom          3
+ArmorStr        5
+
+Name            Golem
+HP              40
+Difficulty      12
+Strength        29
+Agility         14
+Dexterity       13
+Wisdom          4
+ArmorStr        6
+
+Name            Minotaur
+HP              40
+SP              ??
+Difficulty      12
+Strength        30
+Agility         12
+Dexterity       12
+Wisdom          6
+ArmorStr        7
+
+Name            Cyclops
+HP              43
+Difficulty      12
+Strength        27
+Agility         12
+Dexterity       12
+Wisdom          5
+ArmorStr        5
+
+Name            Evil Bard
+HP              41
+SP              ??
+Difficulty      12
+Strength        29
+Agility         11
+Dexterity       11
+Wisdom          5
+ArmorStr        6
+
+Name            Evil Farmer
+HP              41
+SP              ??
+Difficulty      12
+Strength        31
+Agility         12
+Dexterity       13
+Wisdom          3
+ArmorStr        5
+
+Name            Murderer
+HP              40
+SP              ??
+Difficulty      12
+Strength        32
+Agility         12
+Dexterity       13
+Wisdom          5
+ArmorStr        6
+
+Name            Giant
+HP              41
+Difficulty      13
+Strength        27
+Agility         13
+Dexterity       12
+Wisdom          4
+ArmorStr        5
+
+# 13 --------------------------------------------------------------------------
+Name            Sorcerer
+HP              42
+SP              17
+Difficulty      13
+Strength        28
+Agility         11
+Dexterity       13
+Wisdom          6
+ArmorStr        6
+Spell           6
+Spell           7
+Spell           8
+
+Name            Wyvern
+HP              43
+SP              ??
+Difficulty      13
+Strength        29
+Agility         12
+Dexterity       12
+Wisdom          5
+ArmorStr        7
+
+Name            Warrior
+HP              43
+SP              ??
+Difficulty      13
+Strength        33
+Agility         13
+Dexterity       12
+Wisdom          3
+ArmorStr        6
+
+Name            Black Moon Warrior
+HP              44
+SP              ??
+Difficulty      13
+Strength        30
+Agility         14
+Dexterity       12
+Wisdom          4
+ArmorStr        5
+
+Name            Goblin
+HP              43
+SP              ??
+Difficulty      13
+Strength        28
+Agility         12
+Dexterity       14
+Wisdom          4
+ArmorStr        6
+
+Name            Troll
+HP              41
+SP              ??
+Difficulty      13
+Strength        32
+Agility         11
+Dexterity       13
+Wisdom          6
+ArmorStr        4
+
+Name            Large Rat
+HP              42
+SP              ??
+Difficulty      13
+Strength        31
+Agility         12
+Dexterity       13
+Wisdom          4
+ArmorStr        5
+
+# 14 --------------------------------------------------------------------------
+Name            Large Spider
+HP              46
+SP              ??
+Difficulty      14
+Strength        33
+Agility         13
+Dexterity       12
+Wisdom          5
+ArmorStr        6
+
+Name            Large Millipede
+HP              48
+SP              ??
+Difficulty      14
+Strength        34
+Agility         13
+Dexterity       12
+Wisdom          6
+ArmorStr        5
+
+Name            Dark Elf
+HP              45
+Difficulty      14
+Strength        33
+Agility         14
+Dexterity       13
+Wisdom          4
+ArmorStr        4
+
+Name            Spiked Demon
+HP              46
+SP              ??
+Difficulty      14
+Strength        31
+Agility         13
+Dexterity       12
+Wisdom          4
+ArmorStr        6
+
+Name            Skeleton
+HP              45
+SP              ??
+Difficulty      14
+Strength        34
+Agility         12
+Dexterity       12
+Wisdom          4
+ArmorStr        7
+Undead
+
+Name            Bats
+HP              44
+SP              ??
+Difficulty      14
+Strength        32
+Agility         12
+Dexterity       12
+Wisdom          5
+ArmorStr        6
+
+Name            Caveman
+HP              45
+SP              ??
+Difficulty      14
+Strength        33
+Agility         14
+Dexterity       12
+Wisdom          4
+ArmorStr        8
+
+# 15 --------------------------------------------------------------------------
+Name            Mummy
+HP              44
+Difficulty      15
+Strength        33
+Agility         12
+Dexterity       12
+Wisdom          6
+Undead
+ArmorStr        6
+
+Name            Serpent
+HP              46
+SP              ??
+Difficulty      15
+Strength        34
+Agility         13
+Dexterity       14
+Wisdom          6
+ArmorStr        7
+
+Name            Rabid Dog
+HP              44
+SP              ??
+Difficulty      15
+Strength        36
+Agility         14
+Dexterity       14
+Wisdom          5
+ArmorStr        6
+
+Name            Ugly Man
+HP              46
+SP              ??
+Difficulty      15
+Strength        35
+Agility         12
+Dexterity       13
+Wisdom          8
+ArmorStr        5
+
+Name            Critter
+HP              47
+SP              ??
+Difficulty      15
+Strength        34
+Agility         13
+Dexterity       12
+Wisdom          6
+ArmorStr        6
+
+Name            Blue Jelly
+HP              47
+SP              ??
+Difficulty      15
+Strength        37
+Agility         12
+Dexterity       14
+Wisdom          5
+ArmorStr        5
+
+Name            Fire Elemental
+HP              44
+SP              ??
+Difficulty      15
+Strength        38
+Agility         15
+Dexterity       13
+Wisdom          7
+ArmorStr        7
+
+Name            Sprite
+HP              47
+SP              ??
+Difficulty      15
+Strength        36
+Agility         14
+Dexterity       14
+Wisdom          5
+ArmorStr        6
+
+# 16 --------------------------------------------------------------------------
+Name            Slyme
+HP              47
+Difficulty      16
+Strength        39
+Agility         12
+Dexterity       12
+Wisdom          6
+ArmorStr        5
+
+Name            Giant Maggot
+HP              51
+Difficulty      16
+Strength        38
+Agility         12
+Dexterity       15
+Wisdom          6
+ArmorStr        6
+
+Name            Undead Warrior
+HP              52
+Difficulty      16
+Strength        39
+Agility         15
+Dexterity       16
+Wisdom          5
+ArmorStr        7
+Undead
+
+Name            Death Soldier
+HP              43
+Difficulty      16
+Strength        40
+Agility         13
+Dexterity       14
+Wisdom          5
+ArmorStr        6
+
+Name            Undertaker
+HP              47
+Difficulty      16
+Strength        36
+Agility         13
+Dexterity       13
+Wisdom          5
+ArmorStr        7
+
+Name            Wild Man
+HP              45
+SP              ??
+Difficulty      16
+Strength        38
+Agility         14
+Dexterity       14
+Wisdom          6
+ArmorStr        5
+
+Name            Dark Monk
+HP              47
+SP              10
+Difficulty      16
+Strength        41
+Agility         13
+Dexterity       14
+Wisdom          6
+ArmorStr        7
+Spell           5
+
+Name            Thief
+HP              48
+Difficulty      16
+Strength        38
+Agility         12
+Dexterity       15
+Wisdom          6
+ArmorStr        8
+
+Name            Small Dragon
+HP              48
+Difficulty      16
+Strength        39
+Agility         14
+Dexterity       13
+Wisdom          8
+ArmorStr        7
+
+# 17 --------------------------------------------------------------------------
+Name            Sorcerer
+HP              51
+SP              23
+Difficulty      17
+Strength        42
+Agility         14
+Dexterity       15
+Wisdom          6
+ArmorStr        5
+Spell           22
+Spell           19
+Spell           15
+Spell           8
+
+Name            Spirit
+HP              52
+Difficulty      17
+Strength        42
+Agility         13
+Dexterity       14
+Wisdom          6
+ArmorStr        8
+
+Name            Evil Bard
+HP              53
+Difficulty      17
+Strength        41
+Agility         13
+Dexterity       15
+Wisdom          7
+ArmorStr        7
+
+Name            Rock Beast
+HP              50
+Difficulty      17
+Strength        40
+Agility         15
+Dexterity       14
+Wisdom          7
+ArmorStr        8
+
+Name            Brakarak
+HP              52
+Difficulty      17
+Strength        33
+Agility         17
+Dexterity       17
+Wisdom          6
+ArmorStr        6
+
+Name            Emerald Wizard
+HP              50
+SP              20
+Difficulty      17
+Strength        43
+Agility         16
+Dexterity       15
+Wisdom          5
+ArmorStr        5
+Spell           4
+Spell           5
+Spell           7
+
+Name            Amundsen
+HP              49
+Difficulty      17
+Strength        42
+Agility         14
+Dexterity       14
+Wisdom          5
+ArmorStr        7
+
+Name            Dark Demon
+HP              48
+SP              13
+Difficulty      17
+Strength        45
+Agility         12
+Dexterity       13
+Wisdom          4
+ArmorStr        7
+Spell           1
+
+# 18 --------------------------------------------------------------------------
+Name            Diablo
+HP              50
+Difficulty      18
+Strength        44
+Agility         15
+Dexterity       13
+Wisdom          5
+ArmorStr        8
+
+Name            Dark Wizard
+HP              49
+SP              30
+Difficulty      18
+Strength        45
+Agility         15
+Dexterity       14
+Wisdom          5
+ArmorStr        7
+Spell           12
+Spell           10
+Spell           15
+
+Name            Slyme
+HP              47
+SP              ??
+Difficulty      18
+Strength        46
+Agility         14
+Dexterity       13
+Wisdom          7
+ArmorStr        6
+
+Name            Casba Dragon
+HP              49
+SP              ??
+Difficulty      18
+Strength        44
+Agility         13
+Dexterity       13
+Wisdom          6
+ArmorStr        8
+
+Name            Caveman
+HP              49
+Difficulty      18
+Strength        43
+Agility         14
+Dexterity       13
+Wisdom          6
+ArmorStr        7
+
+Name            Skeletal Fiend
+HP              52
+Difficulty      18
+Strength        41
+Agility         13
+Dexterity       14
+Wisdom          6
+ArmorStr        6
+Undead
+
+Name            Doom Ninja
+HP              45
+SP              25
+Difficulty      18
+Strength        42
+Agility         15
+Dexterity       15
+Wisdom          5
+ArmorStr        8
+Spell           8
+Spell           9
+Spell           10
+
+# 19 --------------------------------------------------------------------------
+Name            Doom Wolf
+HP              49
+Difficulty      19
+Strength        41
+Agility         16
+Dexterity       15
+Wisdom          5
+ArmorStr        7
+
+Name            Doom Knight
+HP              41
+Difficulty      19
+Strength        43
+Agility         14
+Dexterity       13
+Wisdom          4
+ArmorStr        8
+
+Name            Doom Wizard
+HP              48
+SP              22
+Difficulty      19
+Strength        46
+Agility         15
+Dexterity       14
+Wisdom          5
+ArmorStr        7
+Spell           19
+Spell           15
+Spell           12
+
+Name            Orc Knight
+HP              47
+Difficulty      19
+Strength        48
+Agility         14
+Dexterity       14
+Wisdom          8
+ArmorStr        9
+
+Name            Wild Dog
+HP              47
+SP              ??
+Difficulty      19
+Strength        45
+Agility         13
+Dexterity       15
+Wisdom          7
+ArmorStr        7
+
+Name            Fire Fiend
+HP              47
+Difficulty      19
+Strength        47
+Agility         14
+Dexterity       16
+Wisdom          4
+ArmorStr        6
+
+Name            Green Demon
+HP              48
+SP              ??
+Difficulty      19
+Strength        48
+Agility         15
+Dexterity       16
+Wisdom          6
+ArmorStr        8
+
+# 20 --------------------------------------------------------------------------
+Name            Orange Demon
+HP              42
+Difficulty      20
+Strength        51
+Agility         13
+Dexterity       15
+Wisdom          7
+ArmorStr        8
+
+Name            Violet Demon
+HP              48
+SP              ??
+Difficulty      20
+Strength        52
+Agility         15
+Dexterity       14
+Wisdom          7
+ArmorStr        8
+
+Name            Red Demon
+HP              41
+SP              ??
+Difficulty      20
+Strength        50
+Agility         14
+Dexterity       15
+Wisdom          8
+ArmorStr        8
+
+Name            Doom Wolf
+HP              48
+Difficulty      20
+Strength        49
+Agility         14
+Dexterity       15
+Wisdom          5
+ArmorStr        9
+
+Name            Doom Knight
+HP              52
+SP              12
+Difficulty      20
+Strength        51
+Agility         14
+Dexterity       15
+Wisdom          7
+ArmorStr        5
+Spell           9
+
+Name            Hell Hound
+HP              51
+Difficulty      20
+Strength        52
+Agility         15
+Dexterity       16
+Wisdom          7
+ArmorStr        8
+
+Name            Hell Knight
+HP              51
+SP              12
+Difficulty      20
+Strength        52
+Agility         14
+Dexterity       16
+Wisdom          10
+ArmorStr        7
+Spell           15
+
+Name            Red Dragon
+HP              52
+Difficulty      20
+Strength        53
+Agility         15
+Dexterity       15
+Wisdom          7
+ArmorStr        8
+
+Name            Green Dragon
+HP              53
+SP              21
+Difficulty      20
+Strength        54
+Agility         15
+Dexterity       14
+Wisdom          7
+ArmorStr        9
+Spell           17
+
diff --git a/src/doors/clans-devkit/Makefile b/src/doors/clans-devkit/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3a4cdb9c24075030e4ade654013d783f80edf348
--- /dev/null
+++ b/src/doors/clans-devkit/Makefile
@@ -0,0 +1,49 @@
+CC=	 gcc
+FLAGS=	 -O -Wall
+EXECFILE= 
+RM=	 rm -f
+
+
+all: chew$(EXEFILE) ecomp$(EXEFILE) install$(EXEFILE) langcomp$(EXEFILE) makenpc$(EXEFILE) makepak$(EXEFILE) mclass$(EXEFILE) mcomp$(EXEFILE) mitems$(EXEFILE) mspells$(EXEFILE)
+
+chew$(EXEFILE) : chew.c
+	$(CC) $(FLAGS) chew.c -o chew$(EXEFILE)
+
+ecomp$(EXEFILE) : ecomp.c
+	${CC} ${FLAGS} ecomp.c -o ecomp$(EXEFILE)
+
+install$(EXEFILE) : install.c
+	$(CC) $(FLAGS) install.c -o install$(EXEFILE) -lcurses
+
+langcomp$(EXEFILE) : langcomp.c
+	$(CC) $(FLAGS) langcomp.c -o langcomp$(EXEFILE)
+
+makenpc$(EXEFILE) : makenpc.c
+	$(CC) $(FLAGS) makenpc.c -o makenpc$(EXEFILE)
+
+makepak$(EXEFILE) : makepak.c
+	$(CC) $(FLAGS) makepak.c -o makepak$(EXEFILE)
+
+mclass$(EXEFILE) : mclass.c
+	$(CC) $(FLAGS) mclass.c -o mclass$(EXEFILE)
+
+mcomp$(EXEFILE) : mcomp.c
+	$(CC) $(FLAGS) mcomp.c -o mcomp$(EXEFILE)
+
+mitems$(EXEFILE) : mitems.c
+	$(CC) $(FLAGS) mitems.c -o mitems$(EXEFILE)
+
+mspells$(EXEFILE) : mspells.c
+	$(CC) $(FLAGS) mspells.c -o mspells$(EXEFILE)
+
+clean :
+	$(RM) chew$(EXEFILE)
+	$(RM) ecomp$(EXEFILE)
+	$(RM) install$(EXEFILE)
+	$(RM) langcomp$(EXEFILE)
+	$(RM) makenpc$(EXEFILE)
+	$(RM) makepak$(EXEFILE)
+	$(RM) mclass$(EXEFILE)
+	$(RM) mcomp$(EXEFILE)
+	$(RM) mitems$(EXEFILE)
+	$(RM) mspells$(EXEFILE)	
diff --git a/src/doors/clans-devkit/NEWBIE.HLP b/src/doors/clans-devkit/NEWBIE.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..7c9ea15cff086d08657f148ce25926dca629940d
--- /dev/null
+++ b/src/doors/clans-devkit/NEWBIE.HLP
@@ -0,0 +1,192 @@
+^Protection
+ |0BProtection
+
+ |0CProtection is used to protect new clans from empire attacks.  The clan
+ can still be attacked normally through clan combat and can also attack
+ other clans.
+^END
+
+^Clan Leader
+ |0BThe Clan Leader
+
+ |0CThe first clan member you choose is important.  He will be thought of as the
+ "Clan Leader" and have superior stats when compared with the other members.
+ This member can be thought of as "you".  When the game addresses your
+ character, it will assume this character.  Be sure to choose wisely for this
+ character!
+^END
+
+^Mine Help
+ |0BThe Mines
+
+ |0CThe mines allow you to fight and build up not only your clansmen's
+ experience and gold but also to gain followers who are impressed by your
+ success in battle.  These followers will later be used as troops.
+^END
+
+^Combat
+ |0BCombat|0C
+
+ Combat in The Clans is unique.  Unlike other games, you control not one
+ character but four.  In combat, you will "run through" each of the characters
+ and decide what he should do in terms of turns.  The character (on the
+ enemy's or your side) with the most agility goes first and the one with
+ the second most goes next and so on.
+
+ |0BExperience |0Cis gained through the actual combat and NOT afterwards.
+   Each move you make in combat will result in an experience point granted
+   to the character you are controlling.  Therefore, good "moves" will result
+   in more experience which is gained faster.
+
+ |0BFollowers |0Cwho witness your combat will join your following and can later
+   be used as troops to attack other clans in "clan wars."
+
+^PAUSE
+
+ |0BHealing |0Cis done automatically after combat where necessary.  However,
+   mana (MP) is not restored but is restored automatically as combat
+   progresses.
+
+ |0BDying |0Cis very real in combat!  If your player dies (gets less than -15
+   hitpoints) he will no longer be useable (unless resurrected).  Those with
+   less than 0 hitpoints are simply deemed unconscious and can be used the
+   next day.
+
+^PAUSE
+^END
+
+^Mine Level
+ |0BMine Levels|0C
+
+ This option allows you to change which level of the mine your clan will
+ venture into.  Moving onto higher levels causes your clan to gain more
+ experience points and move up faster in their training.  Higher levels
+ also give more followers as your combat winnings are more impressive with
+ the higher odds.  Naturally, higher levels offer more difficult enemies to
+ combat.
+ 
+^END
+
+^Market
+ |0BThe Market|0C
+
+ In the market, you can buy equipment for members of your clan.  NOTE:  Items
+ are not usually better if they are more expensive.  Each item is unique
+ and has different stats.  You must choose the right one for your clansmen.
+ The most expensive equipment does not mean the best.
+
+ * It costs you 25% of an item's cost to examine the item's stats and decide
+   whether you wish to buy it or not.
+^END
+
+^Communications
+ |0BCommunications|0C
+
+ In this menu, you are given the option of communicating with other clans.
+^END
+
+^World Travel
+ |0BWorld Travel|0C
+
+ This is the InterBBS portion of The Clans.  Unlike other games, InterBBS
+ actually allows your clan to "travel" to another BBS.  How it works is this:
+
+   1. You choose the BBS you wish to travel to.
+   2. The next day, you call that BBS and login and your clan will be
+      available for you to play on THAT BBS! Imagine being able to move
+      your powerful clan to other BBSes and being able to obliterate
+      enemies there!
+^END
+
+^Town Hall
+ |0BTown Hall|0C
+
+ Town Hall is where the ruling clan deals with the village's duties such as
+ setting the tax rate, erecting buildings, buying farms, etc.
+
+ Other clans which are not currently ruling may do things to offset the ruler's
+ position.  Public conversation on the state of the village can be discussed
+ here as well.
+^END
+
+^Level Raise
+ |0BLevel Raises|0C
+
+ A level raise will provide characters with a training point.  These training
+ points can be used to increase the character's individual attributes in the
+ Training Hall.
+
+^END
+
+^Church Menu
+ |0BThe Church|0C
+
+ The church has methods of ressurecting the dead and blessing your clansmen.
+ It is a good idea to visit this building each day once it has been built.
+^END
+
+^Training Hall Menu
+ |0BThe Training Hall|0C
+
+ The training hall is essential and should be built right away by the ruler.
+ In it, clansmen are trained using training points.  Their stats, such as
+ strength and agility, can be increased through training.
+
+^END
+
+^Pawn Shop
+ |0BPawn Shop
+
+ |0CThe Pawn Shop is the place to buy and sell used goods.  The prices at
+ this shop are always cheaper than at the regular shops.  Feel free to browse
+ the items in stock.  They will only last a couple days so buy it now if you
+ want it.
+
+^END
+
+^Empire Help
+ |0BEmpires
+
+ |0CEmpires in this game are used to store gold and to store your growing
+ army.  Empires can attack each other through empire wars.  In these wars,
+ gold and land can be stolen.  Empire wars are also needed to oust a tyrant
+ ruler from his throne.
+^END
+
+^Wizard
+ |0BWizard's Shop
+
+ |0CThe Wizard's Shop provides the village with magical goods.  The wizard
+ will also be glad to examine any magical items you have for a fee.
+^END
+
+^Development Help
+ |0CThere is much land in this realm to be had.  However, special workers
+ called "Developers" are required to develop the land into something useable
+ for construction.  The more Developer's Halls you have, the cheaper it will
+ be to develop land.
+^END
+
+^Alliances
+ |0CAlliances serve as a way for clans to join together and share items and
+ perhaps troops.  You can join up to 5 alliances and you may create your own
+ as well.
+^END
+
+^Voting Booth
+ |0CThe voting booth allows you to vote for the clan which you think will rule
+ best.  At the end of the day, a new ruler is chosen from the top votes.  Of
+ course, if the town is under dictatorial rule, voting is disabled and the
+ current ruler will continue to reign unless ousted through an empire war.
+^END
+
+^Default Action
+ |0CThe default action is the action done during combat by default when you
+ hit enter.  You can set it to either just a regular attack or a specific
+ spell.  This is extremely useful.  When the spell is "castable" by the
+ character (that is, he has enough skill points to cast it) and you hit
+ enter, that spell will be cast.  On the other hand, if you do not have
+ enough skill points and you hit enter, the player will simply attack since
+ he can't cast the spell (which was the default action you specified).
+
+^END
diff --git a/src/doors/clans-devkit/NPC-PC.TXT b/src/doors/clans-devkit/NPC-PC.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..5a5c1a12ccf343e9ced41ccef9554c89ac3143fe
--- /dev/null
+++ b/src/doors/clans-devkit/NPC-PC.TXT
@@ -0,0 +1,171 @@
+# 0
+Name            Knight
+HP              25
+Difficulty      3
+Agility         13
+Dexterity       10
+Strength        13
+Wisdom          9
+Charisma        15
+Armorstr        0
+
+# 1
+Name            Fisherman
+HP              22
+Difficulty      1
+Agility         9
+Dexterity       4
+Strength        7
+Wisdom          9
+Charisma        7
+Armorstr        0
+
+# 2
+Name            Villager
+HP              28
+Difficulty      1
+Agility         6
+Dexterity       5
+Strength        10
+Wisdom          9
+Charisma        13
+Armorstr        0
+
+# 3
+Name            Warrior
+Difficulty      1
+HP              28
+Agility         9
+Dexterity       7
+Strength        13
+Wisdom          9
+Charisma        5
+Armorstr        1
+
+# 4
+Name            Sorcerer
+Difficulty      1
+HP              18
+SP              28
+Agility         9
+Dexterity       7
+Strength        8
+Wisdom          9
+Charisma        5
+Armorstr        0
+Spell           6
+Spell           7
+
+# 5
+Name            Acolyte
+Difficulty      1
+HP              23
+SP              28
+Agility         5
+Dexterity       4
+Strength        6
+Wisdom          9
+Charisma        5
+Armorstr        0
+Spell           2
+
+# 6
+Name            Bum
+Difficulty      1
+HP              16
+Agility         5
+Dexterity       4
+Strength        6
+Wisdom          3
+Charisma        1
+Armorstr        0
+
+
+# 7
+Name            Paladin
+Difficulty      3
+HP              24
+Agility         12
+Dexterity       10
+Strength        13
+Wisdom          7
+Charisma        6
+Armorstr        0
+
+# 8
+Name            Paladin
+Difficulty      3
+HP              24
+Agility         12
+Dexterity       10
+Strength        13
+Wisdom          7
+Charisma        6
+Armorstr        0
+
+# 9
+Name            Knight
+Difficulty      1
+HP              18
+Agility         10
+Dexterity       8
+Strength        14
+Wisdom          7
+Charisma        6
+Armorstr        1
+
+# 10
+Name            Peasant
+Difficulty      1
+HP              14
+Agility         7
+Dexterity       9
+Strength        12
+Wisdom          7
+Charisma        3
+Armorstr        0
+
+# 11
+Name            Bartender
+Difficulty      1
+HP              16
+Agility         8
+Dexterity       6
+Strength        10
+Wisdom          4
+Charisma        5
+Armorstr        0
+
+# 12
+Name            Dungeoner
+Difficulty      1
+HP              20
+Agility         9
+Dexterity       10
+Strength        9
+Wisdom          6
+Charisma        2
+Armorstr        0
+
+# 13
+Name            Pirate
+Difficulty      2
+HP              15
+Agility         11
+Dexterity       12
+Strength        10
+Wisdom          4
+Charisma        4
+Armorstr        1
+
+# 14
+Name            Lone Wolf
+Difficulty      2
+HP              20
+Agility         14
+Dexterity       8
+Strength        15
+Wisdom          9
+Charisma        5
+Armorstr        2
+
diff --git a/src/doors/clans-devkit/NPCQUOTE.TXT b/src/doors/clans-devkit/NPCQUOTE.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..427177b725dd0f4a8749f2b6ba07554e7fc8d961
--- /dev/null
+++ b/src/doors/clans-devkit/NPCQUOTE.TXT
@@ -0,0 +1,1489 @@
+# -----------------------------------------------------------------------------
+# Knight
+# -----------------------------------------------------------------------------
+
+Topic           Knight.Past
+Text    "I was once the knight in a powerful kingdom.
+TellTopic       Knight.About.King
+End
+
+Topic           Knight.About.King
+Text    "I once served an excellent king, but he was killed.
+TellTopic       Knight.4
+#TellQuest Quest7
+End
+
+Topic           Knight.2
+Text "|02I enjoy adventuring and fighting evil with other |10clans|02.
+TellTopic       Knight.JoinClan
+End
+
+Topic           Knight.3
+Text "The sword was dubbed "The Heavenly Sword".  The king was least seen
+Text "using it in battle.  Only he knows its whereabouts!
+End
+
+Topic           Knight.4
+Text    "The king's name was King Claudius.  He wielded a fabulous sword.
+TellTopic       Knight.3
+End
+
+Topic           Knight.JoinClan
+Text "I can't join your clan.  I must search out other knights like me so that
+Text "we may overcome evil.
+End
+
+# -----------------------------------------------------------------------------
+# Fisherman
+# -----------------------------------------------------------------------------
+
+Topic           Fisherman.JoinClan
+Text "Oh, I cannot join your clan.  I am too busy fishing!
+End
+
+Topic           Fisherman.Catch?
+Text "Not yet, but I know I am going to catch one soon.  Very soon...
+End
+
+Topic           Fisherman.Kingdom
+Text "I once served under a very powerful king.  I was a general, but the kingdom
+Text "was destroyed by a very evil man.  They called him "The Dark One."  The
+Text "kingdom was very prosperous until The Dark One came.  I still have much of
+Text "the money I had back then, but I have no use for it now...
+TellTopic  Fisherman.EvilMan
+TellTopic  Fisherman.Money
+End
+
+Topic           Fisherman.EvilMan
+Text "I don't know much about him, but from what I've heard, he always wears black
+Text "and supposedly, his kingdom lies deep within this very mine!
+End
+
+Topic           Fisherman.Music
+# if he rescued Leonard, say thanks
+{Q5}Text "Thanks for rescuing Leonard!  He is back to his old self again and composing
+{Q5}Text "wonderful music!
+{!Q5} Prompt "Do you like music? [|12Y/N|02]: |13
+{!Q5} Option Y NextLine
+{!Q5} Option N Fisherman.!Music
+{!Q5} Text
+{!Q5} Text "|02That's great to hear!  I love music too.
+End
+
+Topic           Fisherman.!Music
+Text
+Text "|02That's a shame!  You should listen to music.  My favourite music was
+Text "made by a minstrel named Leonard, but he was taken hostage by some strange
+Text "creatures.  If only I could hear that music again.  He's hidden somewhere
+Text "in these mines, but I am too weak to fight!  If I were stronger, I'd
+Text "rescue him myself.
+Text
+Prompt "Do you wish to know where to find and rescue him? [|12Y/N|02]: |13
+Option N NextLine
+Option Y Fisherman.Music.R
+Text
+Text "|02I guess we'll never hear his sweet music again.
+End
+
+Topic           Fisherman.Music.R
+Text
+Text "|02Good luck!  I hope you rescue him so we can hear his wonderful music again!
+TellQuest Quest5
+End
+
+Topic Fisherman.Money
+Prompt "|02I have much gold in my small shack.  Would like some of my gold? [|12Y/N|02]: |13
+Option Y NextLine
+Option N Fisherman.NoGold
+GiveGold 250
+Text
+{D1}Text "|02I gave you all the money I have on hand.  Come back another time and I shall
+{D1}Text "give you more.
+{!D1}Text "|03(He gives you 250 gold pieces.)  |02It is useless to me.  Enjoy it.
+# set flag so people don't keep coming back getting money.
+SetFlag D1
+End
+
+        Topic Fisherman.NoGold
+        Text
+        Text "|02Good.  Money is the root of all evil!
+        End
+
+
+# -----------------------------------------------------------------------------
+# Village Idiot
+# -----------------------------------------------------------------------------
+
+Topic Vidiot.1
+Text "|02Duh . . .
+End
+
+Topic Vidiot.2
+Prompt "|02I'm fine.
+End
+
+Topic Vidiot.3
+Text "There is a lost knight in an abandoned old keep to the north of town!
+Text "He is supposedly held captive by a creature which roams the keep!
+Text "That's all I know about it though so don't bother asking me anything else.
+TellTopic Vidiot.4
+#TellQuest Quest8
+End
+
+Topic Vidiot.4
+Text "I told you I know nothing else!
+TellTopic Vidiot.5
+End
+
+Topic Vidiot.5
+Text "If you're expecting something cool to happen, don't get your hopes up.
+TellTopic Vidiot.6
+End
+
+Topic Vidiot.6
+Text "Maybe you'd like to become the village idiot, huh?
+End
+
+
+# -----------------------------------------------------------------------------
+# Prince Ussher
+# -----------------------------------------------------------------------------
+
+Topic Ussher.1
+{!D2}Text "Hello, I wrote this game.
+{!D2}Text "|03(Each clan member gains 5 experience for being in the prince's presence.)
+{!D2}GiveXP 5
+{D2}Text "Hello again.
+{!D2}Setflag D2
+End
+
+Topic Ussher.2
+Text "Do everything in your power to gain gold and experience quickly.
+End
+
+Topic Ussher.3
+Text "There are may be secrets but I'm not telling.
+End
+
+Topic Ussher.4
+Text "There are NO cheats in this game.  Cheaters suck.
+End
+
+Topic Ussher.5
+Prompt "You like the game so far? [|12Y/N|02]: |13
+Option Y Ussher.Yes
+Option N NextLine
+Text
+Text "|02Your opinion has no meaning whatsoever to me.  Blah! :P
+End
+
+Topic Ussher.Yes
+Text
+Text "|02Thanks, your opinion is quite important to me.
+# secretly give 5 points
+GiveXP 5
+End
+
+Topic Ussher.6
+Text "|02I've also made a door game called Ashrella which uses TXDS (a door creation
+Text "utility).  Another game I made is not an RPG but more of a action game which
+Text "something like internet MUDs.
+End
+
+Topic Ussher.7
+Text "|02Here's 10 gold pieces.  Don't spend it all at once <grin> . . .
+GiveGold 10
+End
+
+Topic Ussher.8
+Text "|02Saggitarius, but I don't see how it matters.
+End
+
+# -----------------------------------------------------------------------------
+# Lovely Lady
+# -----------------------------------------------------------------------------
+
+Topic Lady.1
+Text "Hello.  My name is Alys.
+End
+
+Topic Lady.2
+Text "I am a seamstress.
+TellTopic Lady.3
+End
+
+Topic Lady.3
+Text "I sew for a living.  Many of my friends are seamstresses too.
+TellTopic Lady.4
+End
+
+Topic Lady.4
+Text "Actually, almost all my female friends sew even if they aren't seamstresses.
+Prompt "We sew together and tell stories.  Do you wish to hear a story? [|12Y/N|02]: |13
+Option Y Lady.Story
+Option N NextLine
+Text
+Text "Well, maybe next time you'd like to hear the story...
+End
+
+Topic Lady.Story
+Text
+Text "|02This story is about a couple who loved each other dearly and some people say
+Text "it is actually true!
+Text
+Text "A long time ago, a man and woman were to be married.  One day they were
+Text "wandering along the snowy hillside  and didn't realize what was about to
+Text "happen.  They were caught unawares by the avalanche that was approaching from
+Text "above.  They took shelter in a cave but then the cave was closed off by piles
+Text "of snow.
+Text
+Text "They decided to search out the cave for another way out.  They were walking
+Text "quietly when suddenly the woman slipped and almost fell into a chasm!
+Text "The man grabbed her hand and held on as hard as he could.  But their grips
+Text "were loosening.  He couldn't hold on any more.  She finally slipped free of
+Text "his tight grasp and fell to her grave.  When the man was later rescued, his
+Text "face was pale.  That night he commited suicide.  They say her ghost still
+Text "wanders the cave in mourning.
+Text
+Text "Quite an interesting tale, isn't it?
+#TellQuest Quest10
+End
+
+# -----------------------------------------------------------------------------
+# Beggar 1
+# -----------------------------------------------------------------------------
+
+Topic Beggar1.0
+Text "Please, kind warrior, give me |10100 gold |02pieces.
+Text
+Prompt "Give the beggar 100 gold pieces? [|12Y/N|02]: |13
+Option Y Beggar1.Y
+Option N NextLine
+Text
+Text "|02Thanks for nothing!
+pause
+EndChat
+End
+
+Topic Beggar1.Y
+# see if gold on hand
+Text
+{!$100}Text "|03(You realize you do not have that much gold on hand!)
+{!$100}Text
+{!$100}Text "|02Thanks for nothing!
+{!$100}pause
+{!$100}EndChat
+TakeGold 100
+Text "|02Thank you kindly!  Ask me anything you want.
+End
+
+Topic Beggar1.1
+Text "Sorry.  I know nothing of "The Dark One"
+End
+
+Topic Beggar1.2
+Text "The flag of this land contains two suns: a black sun and a white one.
+Text "The black sun comes once a year and during that period, everybody stays
+Text "indoors until the black sun passes.
+TellTopic Beggar1.3
+End
+
+Topic Beggar1.3
+Text "The reason people go indoors is because during this dark period, creatures of
+Text "all sorts come out and anyone caught in the streets during this time will be
+Text "killed!  Luckily, in the past I was able to hide in a barn . . .
+End
+
+Topic Beggar1.4
+Text "I was once a warrior with great vitality like yourself but I was seriously
+Text "crippled in a battle and could do nothing afterwards.  I soon became poor
+Text "because I could do no work.  I hope you are successful in your endeavours!
+{!D3} Text
+{!D3} Text "|10The beggar's story motivates you to fight even more. You gain 1 monster battle.
+{!D3} GiveFight 1
+Setflag D3
+End
+
+Topic Beggar1.5
+Text "If I knew that, do you think I'd be a beggar?!?
+End
+
+# -----------------------------------------------------------------------------
+# Villager 1
+# -----------------------------------------------------------------------------
+
+Topic Villager1.0
+Text "I wish I could go on an adventure.  I'm pretty fit but have no experience!
+End
+
+Topic Villager1.1
+JoinClan
+End
+
+Topic Villager1.2
+Text "I value loyalty greatly and I have never stabbed anyone in the back.
+End
+
+Topic Villager1.3
+Text "I am a teacher by trade.
+End
+
+Topic Villager1.4
+Text "I am an excellent speaker.  It comes with the territory I suppose.
+End
+
+# -----------------------------------------------------------------------------
+# Villager 1
+# -----------------------------------------------------------------------------
+
+
+# -----------------------------------------------------------------------------
+# The Wise One -- answers only one question per day
+# -----------------------------------------------------------------------------
+
+Topic Wise.0
+{D4}Text "You've had your chance to ask a question today.  Please ask again another day.
+{D4}EndChat
+# otherwise, chat
+# make it so can't chat again later today
+SetFlag D4
+Text "Hello, there.  I am a very busy person answering questions from many, many
+Text "people.  Please, I ask that you only ask one question of me . . .
+End
+
+Topic Wise.1
+Text "Make sure you get a temporary member joining your clan each day.  Also
+Text "ensure you do not pick all warriors or all wizards for your clansmen.
+End
+
+Topic Wise.2
+Text "Many footmen can be used to strengthen your army.
+End
+
+Topic Wise.3
+Text "Ally with many other clans if you wish to strengthen your position.
+End
+
+Topic Wise.4
+Text "You wish to rule with confidence?  Have many allies who will attack those
+Text "who try to usurp your power.
+End
+
+Topic Wise.5
+Text "Always keep crime at a low!
+End
+
+Topic Wise.6
+Text "Build a church and upgrade it as soon as possible!
+End
+
+
+
+# -----------------------------------------------------------------------------
+# Minstrel
+# -----------------------------------------------------------------------------
+
+
+
+# -----------------------------------------------------------------------------
+# The Professor
+# -----------------------------------------------------------------------------
+
+Topic Prof.0
+Text "Hello.  They call me the professor because I love to solve problems and
+Text "have others try to solve them as well.  If you can answer one of my
+Text "puzzles, you will be rewarded.
+End
+
+Topic Prof.1
+Text "A king is trying identical twins for various crimes.  One of them lies while
+Text "the other sometimes lies and sometimes tells the truth.  Their names are
+Text "Shawn and John.  The king asks one of them if his name is Shawn.  The reply
+Text "is no.  After asking the second twin if his name was Shawn and getting a reply,
+Text "the king was immediately able to deduce which was which.
+Text
+Prompt "What was the reply of the second twin?  [|12"Yes" or "No"|02]: |13
+Option Y Prof.1.Y
+Option N Prof.1.1
+End
+
+        # answer first question
+        Topic Prof.1.Y
+        Setflag T1
+        Jump Prof.1.1
+        End
+
+        # answer second question
+        Topic Prof.1.Y.2
+        Setflag T2
+        Jump Prof.1.2
+        End
+
+
+        Topic Prof.1.1
+        Text
+        Prompt "|02What was the first twin Shawn?  [|12Yes/No|02]: |13
+        Option Y Prof.1.Y.2
+        Option N Prof.1.2
+        End
+
+        Topic Prof.1.2
+        Text "|02
+        {!T1|T2}Text "Your replies were incorrect!  Sorry, maybe next time you'll get it.
+        {T1&!T2}Text "Your replies were correct!  Congratulations.  Here are 200 gold pieces!
+        {T1&!T2}GiveGold 200
+        EndChat
+        End
+
+Topic Prof.2
+Text
+Text "I bought an article of clothing for 5 gold pieces, then sold it
+Text "for 6 gold pieces.  I then bought it back at 7 gold pieces and
+Text "sold it once more for 8 gold pieces.  How much gold did I make profit?
+Text
+Text " |02(|100|02) No gold was made, you broke even.
+Text " |02(|101|02) 1 gold piece
+Text " |02(|102|02) 2 gold pieces
+Text " |02(|103|02) 3 gold pieces
+Text
+Prompt "[|120123|02]: |13
+Option 0 Prof.2.Wrong
+Option 1 Prof.2.Wrong
+Option 2 Prof.2.2
+Option 3 Prof.2.Wrong
+End
+
+        Topic Prof.2.Wrong
+        Text
+        Text "|02Sorry, that is incorrect!
+        EndChat
+        End
+
+        Topic Prof.2.2
+        Text
+        Text "|10That's right!  |03(Each member of the clan gains 5 experience)
+        GiveXP 5
+        EndChat
+        End
+
+Topic Prof.3
+Text
+Text "|02Tell me, what comes next in this sequence?
+Text
+Text " O T T F F S S E
+Text
+Prompt "[|12OTFNSE|02]: |13
+Option O NextLine
+Option T NextLine
+Option F NextLine
+Option E NextLine
+Option N Prof.3.N
+Option S NextLine
+Text
+Text "|02Sorry, but that is incorrect.
+End
+
+        Topic Prof.3.N
+        Text
+        Text "|02That's correct!  Here is |10300 gold|02!
+        GiveGold 300
+        End
+
+# -----------------------------------------------------------------------------
+# The Jester
+# -----------------------------------------------------------------------------
+
+Topic Jester.0
+Text
+Text "|10Oh, thank you so much for rescuing me!  I am a jester of the old kingdom but
+Text "was kidnapped by the orcs.  They've tortured me often to try to get a good
+Text "joke out of me, but I've always been an awful jester.
+End
+
+Topic Jester.1
+Text "The orcs you just defeated aren't natives of this area.  They were sent here
+Text "by a greater force.  I believe I overheard them mention another group of orcs
+Text "in the area as well, but that group is a lot more powerful.
+TellTopic Jester.2
+End
+
+Topic Jester.2
+Text "The other orcs are also in these mines but are nowhere near this group.
+Text "The two groups were fighting for "power" of the village, I believe.
+Text "|03(He tells you where the other orcs are.)
+TellQuest Quest11
+End
+
+Topic Jester.3
+Text "|10A fair maiden walks into a bar -- Ouch!  |02I told you I am an awful
+Text "jester.  I can't make anybody laugh. <sob>
+End
+
+Topic Jester.4
+Text "Ah, you are obviously not from around here.  The Old Kingdom once stood
+Text "outside the village but it was destroyed and none of it remains.  The
+Text "one who destroyed is called The Dark One, but he has not been seen from
+Text "for 10 years, thank goodness.
+End
+
+# -----------------------------------------------------------------------------
+# The Warrior
+# -----------------------------------------------------------------------------
+
+Topic Warrior.1
+Text "I love a good adventure.
+TellTopic Warrior.2
+End
+
+Topic Warrior.2
+JoinClan
+End
+
+Topic Warrior.3
+Text "I try to be loyal, but sometimes I slip things out without knowing it
+End
+
+Topic Warrior.4
+Text "If you see The Wise One about, be sure to ask him a question!  He can give
+Text "great tips for new warriors.
+End
+
+# -----------------------------------------------------------------------------
+# Sorcerer
+# -----------------------------------------------------------------------------
+
+Topic Sorcerer.0
+Text "Hi.  I'm an apprentice sorcerer.  I know only a few spells so far, but
+Text "hey!  I'm still learning.
+End
+
+Topic Sorcerer.1
+JoinClan
+End
+
+Topic Sorcerer.2
+Text "What's that?
+End
+
+Topic Sorcerer.3
+Text "A great many have perished within these mines.
+End
+
+# -----------------------------------------------------------------------------
+# Acolyte
+# -----------------------------------------------------------------------------
+
+Topic Acolyte.1
+JoinClan
+End
+
+Topic Acolyte.2
+Prompt "Loyalty is a *very* important virtue, don't you agree? [|12Y/N|02]: |13
+Option Y NextLine
+Option N Acolyte.2.N
+Text
+Text "|10I should hope so!
+End
+
+        Topic Acolyte.2.N
+        Text
+        Text "|02What a terrible thing to think!
+        End
+
+Topic Acolyte.3
+Text "It is a good idea to pray each day.
+End
+
+Topic Acolyte.4
+Text "I'm awful at combat but I am a great healer.
+End
+
+Topic Acolyte.5
+Text "The Dark One is the epitome of all evil.  Seek him out and destroy him!
+End
+
+Topic Acolyte.6
+Text "Thank the gods the ruler finally decided to build this church!
+End
+
+Topic Acolyte.7
+Text "One of the Three Rules of Our Religion is |10"Thou shalt register your copy of
+Text "The Clans."  |02I don't understand the rule myself, but if the gods say it should
+Text "be so, then so be it!
+End
+
+# -----------------------------------------------------------------------------
+# Bum
+# -----------------------------------------------------------------------------
+
+Topic Bum1.0
+Text "Please, kind warrior, give me |10250 gold |02pieces.
+Text
+Prompt "Give the bum 250 gold pieces? [|12Y/N|02]: |13
+Option Y Bum1.Y
+Option N NextLine
+Text
+Text "|02Your lucky I'm such a nice person or I'd really make you feel bad right now!
+End
+
+Topic Bum1.Y
+# see if gold on hand
+Text
+{!$250}Text "|03(You realize you do not have that much gold on hand!)
+{!$250}Text
+{!$250}Text "|02Your lucky I'm such a nice person or I'd really make you feel bad right now!
+# else do this
+{$250}TakeGold 250
+{$250}Text "|02Thank you so much!
+{$250}Text "|03(Each clansman gains 10 experience.)
+End
+
+Topic Bum1.1
+Text "I once led a great life.  I was a bard of another realm, but I got lazy and
+Text "didn't write new songs so eventually people gave up on me.
+End
+
+Topic Bum1.2
+Text "I bum around mainly.
+End
+
+Topic Bum1.3
+Text "I don't like politics myself but a good tip is to gain many allies before
+Text "becoming the ruler.  You'll thank me later!
+End
+
+Topic Bum1.4
+Text "I ain't loyal to nobody, OK!?
+End
+
+Topic Bum1.5
+JoinClan
+End
+
+# -----------------------------------------------------------------------------
+# Peasant
+# -----------------------------------------------------------------------------
+
+Topic Peasant1.0
+Text "I can only answer a couple questions.  I am quite a busy peasant!
+End
+
+Topic Peasant1.1
+Text "My favourite quote would probably have to be |10"Yes, my lord."
+End
+
+Topic Peasant1.2
+Text "I don't have time for adventuring.  Didn't I tell you I'm quite busy?!
+End
+
+Topic Peasant1.3
+Text "I farm.  Right now I'm delivering some goods to a customer.
+End
+
+Topic Peasant1.4
+Text "I used to live in the realm of Exaggerus, but the leader vanished for some
+Text "reason.  People still live there even the town has run amok and almost
+Text "everyone is a common thief.
+End
+
+Topic Peasant1.5
+Text "If you want gold, attack someone empire!  I don't have any to spare!
+End
+
+Topic Peasant1.6
+Text "The bums here are awful.  They make this town seem worse than it is.
+End
+
+Topic Peasant1.7
+Text "There has been recently a string of murders.  I think I know who is causing
+Text "them!  An evil beast has been causing them, I believe.  He lives deep in the
+Text "forest.  |03(The peasant gives you directions.)
+Text
+Text "|10Please, end his wrath!
+TellQuest Quest2
+End
+
+# -----------------------------------------------------------------------------
+# Old man
+# -----------------------------------------------------------------------------
+
+Topic OldMan.0
+Text "I think adventures are great!  If I had enough strength and my youth, I'd
+Text "be fighting monsters like yourself!
+Text
+{!D5} Text "|03(The old man's words move you to fight further.  You gain
+{!D5} Text "1 monster fight.)
+{!D5} GiveFight 1
+Setflag D5
+End
+
+Topic OldMan.1
+Text "I carry my gold in this sack since I don't trust the banks.  They are all too
+Text "greedy!
+End
+
+Topic OldMan.2
+Text "Supposedly, there is some treasure within these mines.  It is heavily guarded
+Text "by spirits, though.  I'm to weak to go after it myself.  Perhaps you could
+Text "get it?  There is supposedly about 3000 gold pieces in the treasure!
+#TellQuest Quest12
+End
+
+# -----------------------------------------------------------------------------
+# The Psychic
+# -----------------------------------------------------------------------------
+
+Topic Psychic.0
+Text "Spirits are everywhere but not all of us can see them.
+End
+
+Topic Psychic.1
+Text "My job is to search out and destroy evil spirits.
+End
+
+Topic Psychic.2
+Text "The Spirit World exists alongside the Living World.  Once in a while, a
+Text "tear is created in the space-time continuum and beings are free to pass
+Text "from one world to the other.  Unfortunately, this has caused problems as
+Text "spirits can do great damage in this world.
+End
+
+
+Topic Psychic.3
+Text "Lelaz, a pupil of mine, opened up a tear in the spirit world and caused a
+Text "great number of evil beings to come into this world.  He was then possessed
+Text "by one of the demons who called himself Diablo.  He now resides within the
+Text "depths of these mines.  What a fool!
+#TellTopic Psychic.4
+#TellQuest Quest13
+End
+
+Topic Psychic.4
+Text "The only way to reach Diablo is to light 4 candles within the underground mine
+Text "system.  After the 4 candles are lit, a door will open and Diablo's domain
+Text "will be revealed.  Good luck!
+End
+
+# -----------------------------------------------------------------------------
+# Common Man
+# -----------------------------------------------------------------------------
+
+Topic Common.0
+Text "I am a historian.
+TellTopic Common.1
+End
+
+Topic Common.1
+Text "I enjoy research, especially those relating to The Five Great Evils.
+TellTopic Common.2
+End
+
+Topic Common.2
+Text "The Five Great Evils are the the five most vile creatures to have ever
+Text "existed.  They were placed on this world by the Lord of Darkness Nuul.
+Text "I believe The Dark One who ravished our land is one of these evils.
+End
+
+# -----------------------------------------------------------------------------
+# Guard
+# -----------------------------------------------------------------------------
+
+Topic Guard.0
+Text "I despise crime.  That is why I became a guard.
+End
+
+Topic Guard.1
+Prompt "Art thou valiant? [|12Y/N|02]: |13
+Option N NextLine
+Option Y Guard.1.Yes
+Text
+Text "|02As I thought!
+End
+
+        Topic Guard.1.Yes
+        Text
+        Text "|02Then thou should be a guard!
+        End
+
+Topic Guard.2
+Prompt "Art thou honest? [|12Y/N|02]: |13
+Option N NextLine
+Option Y Guard.2.Yes
+Text
+Text "|02As I expected!
+End
+
+        Topic Guard.2.Yes
+        Text
+        Text "|02Then thou should be a guard!
+        End
+
+Topic Guard.3
+Prompt "Art thou corrupt? [|12Y/N|02]: |13
+Option N NextLine
+Option Y Guard.3.Yes
+Text
+Text "|02I knew it!
+End
+
+        Topic Guard.3.Yes
+        Text
+        Text "|02Then thou should be a guard!
+        End
+
+Topic Guard.4
+Text "I don't get paid much.
+End
+
+# -----------------------------------------------------------------------------
+# Poet
+# -----------------------------------------------------------------------------
+
+Topic Poet.1
+Text "Hey, you may be a poet and you don't even know it!
+End
+
+Topic Poet.2
+Text "The wealth I receive is not from gold
+Text "Nor is it something to be bought or sold
+Text "And it is not something that requires a fee
+Text "Wealth, to me, is all the smiles that I see
+pause
+Text
+# stop if quest completed
+{Q19}Text "Thank you once again for finding my quill!
+{Q19}End
+Prompt "Can you please give me 300 gold? [|12Y/N|02]: |13
+Option Y NextLine
+Option N Poet.2.1
+{!$300}Text "|03(You realize you do not have that much gold on hand!)
+{!$300}Text
+{!$300}Text "|10For giving me hope of a better life and then shattering those hopes,
+{!$300}Text "I thank you . . .
+{!$300}pause
+{!$300}Text
+{!$300}Text "I was being sarcastic!
+{!$300}End
+TakeGold 300
+Text
+Text "|10Thank you so much!  |02Ever since I had my quill stolen, I haven't been
+Text "able to write decent poems.  The quill was stolen by some common thiefs.  It
+Text "was a gift that I received from my parents when I was a young lad.  It is
+Text "quite valuable in that it is from a rare golden bird from a place south
+Text "of these lands.  If you can find the time, please find it for me!
+Text
+#TellQuest Quest19
+End
+
+        Topic Poet.2.1
+        Text
+        Text "|10Lousy cheapskate!
+        End
+
+Topic Poet.3
+Text "Oh, I do hate politics.  I wish the rulers would be overthrown!
+End
+
+Topic Poet.4
+Text "I do love a good tune.  I wrote songs once with a bard ... that is, until he
+Text "went missing.
+End
+
+Topic Poet.5
+Text "
+Text "Fight the good fight,
+Text "because you know you're right
+Text "And they are so wrong
+Text "But it won't be too long
+Text "Before they are defeated
+Text "And they will ... er, I can't think of anything that rhymes with defeated
+Text "at the moment.  I'm terribly sorry.
+{!D7}Text
+{!D7}Text "|10The poet's somewhat average poem inspires the clan to fight some more.
+{!D7}Text "|03(You gain 1 monster fight.)
+{!D7}GiveFight 1
+Setflag D7
+End
+
+Topic Poet.6
+Text "My friends tell me this is true
+Text "To prove them right, I leave to you
+Text "The tip is this and learn it well
+Text "|10Equip your clan members with the best weapons suited for their abilities
+Text "to improve in the mines.
+Text "|02... or they shall go to hell.
+End
+
+# -----------------------------------------------------------------------------
+# Myau
+# -----------------------------------------------------------------------------
+
+Topic Myau.0
+Text "|03You see a small creature about the size of a rabbit.  It is a strange
+Text "creature which resembles a rabbit AND a cat.  Around its neck is a small
+Text "vial containing a green liquid.
+End
+
+Topic Myau.1
+Text "Meow.
+End
+
+Topic Myau.2
+Text "Raourrrr.
+End
+
+Topic Myau.3
+Text "Meooooow.
+End
+
+Topic Myau.4
+Text "Meeeeeeeeeooooooooooooooowwwwwwwwww.
+{!D8}Text
+{!D8}Text "|03(You gain 1 monster fight after hearing the beautiful sound of the
+{!D8}Text "creature.)
+{!D8}GiveFight 1
+SetFlag D8
+End
+
+Topic Myau.5
+Text "Purr.
+{!T2}Text
+{!T2}Text "|03(The creature rubs up against each clansmen's leg.  Each one feels
+{!T2}Text "better.  Each clan member's skill points increase.)
+{!T2}Heal SP
+SetFlag T2
+End
+
+# -----------------------------------------------------------------------------
+# Drunk Man
+# -----------------------------------------------------------------------------
+
+Topic Drunk.1
+Text "<buuuuuuurp>
+End
+
+Topic Drunk.2
+Text "Take the middle door!
+End
+
+Topic Drunk.3
+Text "Funny. <burp> There's no tavern in town and I still manage to get drunk.
+End
+
+Topic Drunk.4
+Prompt "Want some of my gold? [|12Y/N|02]: |13
+Option Y Drunk.4.Y
+Option N NextLine
+Text
+Text "|02What, not good enough for you?  ....  Or too busy feeling sorry for me?!
+End
+
+        Topic Drunk.4.Y
+        Text
+        {!T1}Text "|02You hold out your hand and the drunk drops |10100 |02gold coins in
+        {!T1}Text "your hand!
+        {!T1}GiveGold 100
+        {T1}Text "|02You hold your hand and the drunk drops NOTHING in it.
+        {T1}Text "|10I already gave you all my gold, dolt!
+        SetFlag T1
+        End
+
+
+# -----------------------------------------------------------------------------
+# Paladin
+# -----------------------------------------------------------------------------
+
+Topic Paladin.0
+Text "Hello.  I am a paladin dedicated to ridding this land of evil vermin!
+End
+
+Topic Paladin.1
+JoinClan
+End
+
+Topic Paladin.2
+Text "I am always loyal.
+End
+
+Topic Paladin.3
+Text "I have no gold.  Religion is all I need.
+End
+
+Topic Paladin.4
+Text "A legendary sword was once endowed upon the king.  Unfortunately, the king
+Text "was locked up in a dungeon by The Dark One and the sword was discarded deep
+Text "in the mines so that no one could use it.  Only the pure of heart may wield
+Text "such a weapon.
+#TellQuest Quest18
+End
+
+Topic Paladin.5
+Text "Some say The Dark One resides deep within the earth's core.  He hasn't been
+Text "seen for some time but given the chance, I'd destroy him myself!
+End
+
+# -----------------------------------------------------------------------------
+# Merchant
+# -----------------------------------------------------------------------------
+
+Topic Merchant.0
+Text "I am a merchant traveling from town to town selling wares.
+End
+
+Topic Merchant.1
+Text "I can't possibly join your clan!  I'm a simple merchant -- not a
+Text "sword-wielding adventurer!
+End
+
+Topic Merchant.2
+Text "I sell mainly weapons.  I have a special today on shortswords.  I will sell
+Text "you one for only 1000GP.  It usually costs around 1300GP.
+Text
+Prompt "Buy the shortsword? [|12Y/N|02]: |13
+Option Y NextLine
+Option N Stop
+{!$1000}Jump Merchant.2.NoGold
+# if you have that gold, take it
+Text
+Text "|10The merchant gives you the shortsword and you place it in your inventory.
+TakeGold 1000
+GiveItem Shortsword
+End
+
+        Topic Merchant.2.NoGold
+        Text
+        Text "|02You extend your hand with nothing in it.  The merchant laughs out loud.
+        Text "|10I only accept REAL gold, not imaginary gold!
+        End
+
+Topic Merchant.3
+Text "I do not carry any precious goods.
+End
+
+Topic Merchant.4
+Text "Traveling is hard on the spirit but it is worthwhile once you make a decent
+Text "sale.
+TellTopic Merchant.4.B
+End
+
+Topic Merchant.4.B
+Text "I have a perilous mission for you.  I am in great need of protection
+Text "considering the lands are filled with thieves waiting for someone like
+Text "me to roll along.  For 2000 GP, I would like you to travel alongside my
+Text "caravan to a neighbouring town.  We may face some thieves and other evil
+Text "but I hope that you can fend them off.  If you wish to help me out, meet
+Text "me on the outskirts of town.
+TellQuest Quest4
+End
+
+Topic Merchant.5
+Text "Some of my colleagues work within the mines!  They usually offer great deals
+Text "on excellent weapons.
+End
+
+# -----------------------------------------------------------------------------
+# Freak
+# -----------------------------------------------------------------------------
+
+Topic Freak.0
+Text "Good day to you.  I was just in the middle of reading this wonderful book.
+End
+
+Topic Freak.1
+Text "Whoever says I'm a murderer is a liar!  Although I used to be a soldier, I
+Text "never murdered anybody.  I may have chopped off a limb here and there but I
+Text "never went so far as to kill a man!
+TellTopic Freak.2
+End
+
+Topic Freak.2
+Text "The one causing the murders in town was not I!  There is a rich businessman in
+Text "town who controls underground affairs.  He wanted to get rid of some men
+Text "cleanly so he spread a rumour that I caused them!  Of course, people believed
+Text "the rumours since I'm a freak!!
+TellQuest Quest3
+End
+
+Topic Freak.3
+Text "The book I'm reading is called N.P. by Banana Yoshimoto.  Great novel.
+End
+
+Topic Freak.4
+Text "Ah, my axe.  I have never needed this old thing.  I am quite the axehandler,
+Text "but I haven't used it in ages.  You may have it.
+Text
+Prompt "Take the axe? [|12Y/N|02]: |13
+Option N STOP
+Option Y NextLine
+{!T1}GiveItem Battle Axe
+{!T1}Text
+{!T1}Text "|10You now have a Battle Axe!
+{T1}Text "|10Are you an idiot?  I just gave you the axe!
+SetFlag T1
+End
+
+# -----------------------------------------------------------------------------
+# Knight
+# -----------------------------------------------------------------------------
+
+Topic Knight2.0
+Text "I have nothing much to say so don't waste your time.
+End
+
+Topic Knight2.1
+JoinClan
+End
+
+Topic Knight2.2
+Text "At least it's not a forest.
+End
+
+Topic Knight2.3
+Text "Quests are an excellent way of building up experience and gold.
+End
+
+
+# -----------------------------------------------------------------------------
+# Blacksmith
+# -----------------------------------------------------------------------------
+
+Topic Smith.1
+Text "Just for you 'cos you have a pretty face, I'll sell ya this Mace for
+Text "only 700GP.  It usually costs around 900GP!
+Text
+Prompt "Buy the mace? [|12Y/N|02]: |13
+Option Y NextLine
+Option N Stop
+{!$700}Jump Smith.1.NoGold
+# if you have that gold, take it
+Text
+Text "|10The blacksmith gives you the mace and you place it in your inventory.
+TakeGold 700
+GiveItem Mace
+End
+
+        Topic Smith.1.NoGold
+        Text
+        Text "|02You extend your hand with nothing in it.  The smith looks at you with a
+        Text "disgruntled look and says |10I only accept REAL gold, not imaginary gold!
+        End
+
+Topic Smith.2
+Text "KOR rules!
+End
+
+Topic Smith.3
+Text "Always use your skills in combat!  You won't believe how useful they are until
+Text "you try 'em.  There *was* a reason you trained for those skills, don't you
+Text "think?  They're not just there for show!
+End
+
+Topic Smith.4
+Text "Don't waste your fights by fighting people who are just gonna kick your butt!
+End
+
+# -----------------------------------------------------------------------------
+# Peasant2
+# -----------------------------------------------------------------------------
+
+Topic Peasant2.1
+Text "I love a good mystery -- er, adventure.
+End
+
+Topic Peasant2.2
+JoinClan
+End
+
+Topic Peasant2.3
+Text "Ayukawa Madoka is a goddess!
+End
+
+Topic Peasant2.4
+Text "Full-time peasant.
+End
+
+Topic Peasant2.5
+Text "Supposedly, the freak of the town is causing some murders.  I don't believe it
+Text "myself though.
+End
+
+Topic Peasant2.6
+{!D9}Text "|03(The peasant sings a song for you.  You gain 1 monster fight.)
+{!D9}GiveFight 1
+{D9}Text "|03(The peasant sings a song for you -- the same one.  You feel indifferent.)
+SetFlag D9
+End
+
+Topic JoinClan
+JoinClan
+End
+
+# -----------------------------------------------------------------------------
+# Pirate
+# -----------------------------------------------------------------------------
+
+Topic Pirate.0
+{D6}Text "|12Arr, it's you again . . .
+{!D6}Text "|12Arr.  I be a pirate.
+{!D6}Text
+{!D6}Text "|06(You see a typical pirate.  Well, not so typical.  He's got two
+{!D6}Text "eyepatches.  One on each eye!)
+End
+
+Topic Pirate.1
+Text "|12I lost both eyes on a voyage.
+TellTopic Pirate.2
+End
+
+Topic Pirate.2
+Text "|12What's a sunglasses?
+End
+
+Topic Pirate.3
+TellTopic Pirate.6
+Text "|0CThe heck would I know?  What do I look like, a pirate?
+Text
+Text " |0A(|0B1|0A) |0CActually, yeah, you do.
+Text " |0A(|0B2|0A) |0CNo, but you remind me of a dead fish I once owned.
+Text " |0A(|0B3|0A) |0CForget it...
+Text
+Prompt "|0A[|0B123|0A]: |0F
+Option 1 Pirate.3.1
+Option 2 Pirate.3.2
+Option 3 Pirate.3.3
+End
+
+Result Pirate.3.1
+Text
+Text "Well, I guess I do look like a pirate.  I can assure you, it is merely
+Text "coincidental.
+End
+
+Result Pirate.3.2
+Text
+Text "Why would anyone own a dead fish?
+End
+
+Result Pirate.3.3
+Text
+Text "Forget what?
+End
+
+Topic Pirate.4
+Text "|12No, why?  You want one?
+End
+
+Topic Pirate.5
+JoinClan
+End
+
+Topic Pirate.6
+Text "|07I'm telling you, I don't know!
+TellTopic Pirate.7
+End
+
+Topic Pirate.7
+Text "|07You ain't gettin' anything outta me!
+TellTopic Pirate.8
+End
+
+Topic Pirate.8
+Text "|07Aw shucks, you dragged it outta me... find an X and dig there.  Oh, darn
+Text "it, I'll save you the trouble.  Here's 1000 gold pieces for your troubles.
+{!D10}GiveGold 1000
+{D10}Text
+{D10}Text "Wait a second!  I already gave you some gold today!  Get away now!
+SetFlag D10
+End
+
+
+
+# -----------------------------------------------------------------------------
+# Old Man #2
+# -----------------------------------------------------------------------------
+
+Topic OldMan2.1
+Text "I came from a small town near here called |S|06BrownTown|R.  It was an amazing
+Text "place...
+TellTopic OldMan2.2
+End
+
+Topic OldMan2.2
+Text "Darn it, it had the finest Blue Cows around!  I wish I could return to that
+Text "town but they kicked me out.
+TellTopic OldMan2.3
+TellTopic OldMan2.4
+End
+
+Topic OldMan2.3
+Text "I was kicked out for a very good reason . . .  I made a mistake.  |S|15I ERRED!|R
+Text "I can say no more!
+TellTopic OldMan2.5
+End
+
+Topic OldMan2.4
+Text "Ah, but there is truth to some legends, isn't there?
+Text
+Input OldMan2.4.1 1. Maybe so, but there's no such things as Blue Cows!!
+Input OldMan2.4.2 2. Um . . .  How should I know?!
+Input Stop        3. Maybe, but legends bore me, let's talk about something else...
+End
+
+        Result OldMan2.4.1
+        Text "They do so exist!
+        Text
+        Input OldMan2.4.1.More  1. They do not!
+        Input OldMan2.4.1.2     2. Ok, they do exist.
+        End
+
+        Result OldMan2.4.1.More
+        Text "They do so!
+        Text
+        Input OldMan2.4.1.YetMore       1. Do not!
+        Input OldMan2.4.1.2             2. Ok, fine, they do exist.
+        End
+
+        Result OldMan2.4.1.YetMore
+        Text "Do so!
+        Text
+        Input OldMan2.4.1.YetMore       1. Do not!
+        Input OldMan2.4.1.2             2. Have it your way, they do exist.
+        End
+
+        Result OldMan2.4.1.2
+        Text "I knew you'd see the light.
+        End
+
+        Result OldMan2.4.2
+        Text "I don't know.  I'm just a simple old man.  Simple on the outside but complex
+        Text "on the inside.
+        End
+
+
+Topic OldMan2.5
+Text "I'd like to see you try!  I don't even have a beard!  And if you thought I had
+Text "a cane, you were wrong about that too!  I will not reveal my past.
+TellTopic OldMan2.6
+End
+
+Topic OldMan2.6
+Text "Ok, good.  I won't.
+TellTopic OldMan2.7
+End
+
+Topic OldMan2.7
+Text "Ok, ok!!  I'll tell you, but you must promise not to tell any one else. . .
+pause
+Text
+Text "I was kicked out because . . .
+pause
+Text
+Text "I stink.
+End
+
+Topic OldMan2.8
+Text "Ah, I still remember the good times I had with my old friends.  Ron Ron, John
+Text "John, Tim Tim, Mark Mark, Don Don . . .
+TellTopic OldMan2.9
+End
+
+Topic OldMan2.9
+Text "Now that I think about it...yes, they all had dumb names.  No wonder they
+Text "were outcasts.  But then again their two heads probably caused some of their
+Text "misfortune as well . . .
+End
+
+# -----------------------------------------------------------------------------
+# Lone Wolf
+# -----------------------------------------------------------------------------
+
+Topic LW.1
+Text "I came from a land far away called Sommerlund.  It is a beautiful place.
+End
+
+Topic LW.2
+Text "Kai Warriors are the greatest warriors of all time.  I am one myself.
+End
+
+Topic LW.3
+Text "Scrolls are very useful in battle.
+End
+
+# -----------------------------------------------------------------------------
+# Dungeoner
+# -----------------------------------------------------------------------------
+
+Topic Dung.1
+Text "The world's fastest man is still Donovan Bailey.
+End
+
+Topic Dung.2
+Text "I enjoy dungeons.  I can only go down to a certain level by myself,
+Text "however.  I need the help of a clan to survive any lower.
+End
+
+Topic Dung.3
+Text "I have no use for gold.  I merely seek out adventures, not wealth.
+End
+
+# -----------------------------------------------------------------------------
+# Bartender
+# -----------------------------------------------------------------------------
+
+Topic Bartender.0
+Text "My name is Bart the Bartender.  Quit yer laughin'!
+End
+
+Topic Bartender.1
+Text "Strange, there's no tavern in this town.  Regardless, I come from another
+Text "town.  Perhaps one day this town will have a tavern.
+End
+
+Topic Bartender.2
+Text "I wouldn't know what's good.  I don't drink.  Strange, huh?
+End
+
+
+# -----------------------------------------------------------------------------
+# Ai
+# -----------------------------------------------------------------------------
+
+Topic Ai.0
+Text "             |04苘苘苘軀07
+Text "          |04苒圹圹圹圹圹軀07
+Text "       |04苒圹|12|20眧04|16圹圹|12|20眧04|16圹咣圹踻07
+Text "      |04圮|12|20眧04|16圹咣圻圹踻12|20皘04|16圹咣|08|20皘04|16輡07
+Text "     |04� 苘圻  遼08|20皘04|16遼12|20皘07|16 |04� |07� |04踻08|20皘04|16踻07
+Text "        |04哌 |07圻 苘  苒 |04苒踻08|20眧07|16
+Text "       |04� 圯|07迀15|23皘07|16踻12|23皘07|16圹圹|08|23皘07|16� |04遼08|20氨|07|16
+Text "       |04軀12|20皘04|16圮 |07咣踻04|23軀07|16圹|08|23鞍|07|16� |12|20皘08眧04|16輡07
+Text "    |04� 苓苒|12|20眧08皘07|16  咣圻� |04苓圻|07
+Text "         |04哌哌  |07� |04苓哌|07
+Text "    |01軀07        苘踻15|23皘07|16苒苘   |01軀07
+Text "     軀01咣|09|17軀01|16苘|07哌 哌�  |01苘苘圮圹哌|07
+Text "    迀15|23皘07|16� |01踻09|17圮軀01|16圹苘圹|09|17苘|01|16圹哌� |07苒
+Text "    圹|08|23皘07|16� |01遼09|17卑|01|16圮圹遼09|17斑|01|16圹圹 |15|23皘07|16圹|08|23皘07|16�
+Text
+Text "Hello.  My name is Ai.  I am the finest warrior in the land.  If anyone tells
+Text "you differently, he is lying.
+End
+
+Topic Ai.1
+Text
+Text "I have no past.  I have relinquished all ties with anyone I had known in order
+Text "to keep my anonymity.
+End
+
+Topic Ai.2
+Text
+Text "I have pledged to avenge my parent's deaths.  I am seeing out the one called
+Text "Sloryx but I have yet to find his whereabouts.  If you ever find out anything
+Text "about him, contact me at once!
+End
+
+Topic Ai.3
+Text
+Text "I cannot speak any more about myself.  I will only reveal information as you
+Text "need it.
+End
+
diff --git a/src/doors/clans-devkit/NPCS.TXT b/src/doors/clans-devkit/NPCS.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..67a1057f7f487c39d4ba017ab79dfc881c1f82a2
--- /dev/null
+++ b/src/doors/clans-devkit/NPCS.TXT
@@ -0,0 +1,453 @@
+# NPC info in the game -- see NPC-PC.TXT for .PC file info
+# FIXME: search out 100% odds and replace 'em
+
+# 0
+Index           _Knight1
+Name            The Knight
+# he is the 0th npc in the NPC-PC.TXT file
+QuoteFile       NPCQUOTE.Q
+NPCDAT          0
+MonFile         NPC.PC
+Loyalty         9
+# here go the quotes, they all appear in npcquote.q
+KnownTopic      Knight.Past Your Past
+Topic           Knight.3 The Sword
+Topic           Knight.About.King About My King
+KnownTopic      Knight.2 Adventuring
+Topic           Knight.4 The King
+Topic           Knight.JoinClan Join Our Clan
+
+# 1
+Index           _Fisherman
+Name            Fisherman
+QuoteFile       npcquote.q
+MaxTopics       5
+NPCDAT          1
+MonFile         NPC.PC
+KnownTopic      Fisherman.JoinClan Join Our Clan
+KnownTopic      Fisherman.Catch? Catch Anything?
+KnownTopic      Fisherman.Kingdom Old Kingdom
+Topic           Fisherman.EvilMan The Dark One
+KnownTopic      Fisherman.Music Music
+Topic           Fisherman.Money Gold
+
+# 2
+Index           _VIdiot
+MonFile         NPC.PC
+Name            Village Idiot
+KnownTopic      Vidiot.1 Hello.
+KnownTopic      Vidiot.2 How are you today?
+KnownTopic      Vidiot.3 The Knight
+Topic           Vidiot.4 More on The Knight?!
+Topic           Vidiot.5 A secret?
+Topic           Vidiot.6 What the?!
+OddsOfSeeing    20
+Wander          Street
+
+# 3
+Index           _Ussher
+MonFile         NPC.PC
+Name            Prince Ussher
+OddsOfSeeing    10
+MaxTopics       4
+KnownTopic      Ussher.1 Hello.
+KnownTopic      Ussher.2 Hint
+KnownTopic      Ussher.3 Secrets
+KnownTopic      Ussher.4 Cheats
+KnownTopic      Ussher.5 The Clans
+KnownTopic      Ussher.6 Other games
+KnownTopic      Ussher.7 Money
+KnownTopic      Ussher.8 What's your sign?
+Wander          Street
+HereNews        |06 � |14Prince Ussher |06is spotted on the street!
+
+# 4
+Index           _Lady
+MonFile         NPC.PC
+Name            Lovely Lady
+OddsOfSeeing    20
+Wander          Street
+KnownTopic      Lady.1 Hello
+KnownTopic      Lady.2 Occupation
+Topic           Lady.3 Seamstress?
+Topic           Lady.4 Friends
+HereNews        |06 � |12A lovely lady is spotted on the street.
+
+# 5
+# some beggars
+Index           _Beggar
+MonFile         NPC.PC
+Name            Beggar
+MaxTopics       4
+OddsOfSeeing    30
+Wander          Street
+IntroTopic      Beggar1.0
+KnownTopic      Beggar1.1 The Dark One
+KnownTopic      Beggar1.2 The Flag
+Topic           Beggar1.3 The Black Sun
+KnownTopic      Beggar1.4 Your past
+KnownTopic      Beggar1.5 How to get rich...
+
+# 6
+# some guys to join clans
+Index           _Villager
+MonFile         NPC.PC
+Name            Villager
+OddsOfSeeing    30
+NPCDat          2
+Loyalty         10
+Wander          Town Hall
+IntroTopic      Villager1.0
+KnownTopic      Villager1.1 Join Our Clan
+KnownTopic      Villager1.2 Loyalty
+KnownTopic      Villager1.3 Occupation
+KnownTopic      Villager1.4 Speaking
+
+# 7
+Index           _Warrior
+MonFile         NPC.PC
+Name            Warrior
+NPCDAT          3
+#OddsOfSeeing    100
+OddsOfSeeing    20
+Wander          Training Hall
+KnownTopic      Warrior.1 Adventure
+Topic           Warrior.2 Join Our Clan
+KnownTopic      Warrior.3 Loyalty
+KnownTopic      Warrior.4 The Wise One
+Loyalty         9
+
+# 8
+Index           _YS
+MonFile         NPC.PC
+Name            Young Sorcerer
+NPCDAT          4
+OddsOfSeeing    10
+Loyalty         6
+Wander          Mine
+IntroTopic      Sorcerer.0
+KnownTopic      Sorcerer.1 Join Our Clan
+KnownTopic      Sorcerer.2 Loyalty
+KnownTopic      Sorcerer.3 The Mines
+
+# 9
+Index           _Knight2
+MonFile         NPC.PC
+Name            Knight
+NPCDAT
+OddsOfSeeing    20
+Wander          Church
+IntroTopic      Knight2.0
+KnownTopic      Knight2.1 Join Our Clan
+KnownTopic      Knight2.2 The Mines
+KnownTopic      Knight2.3 Quests
+
+# 10
+Index           _Acolyte
+MonFile         NPC.PC
+Name            Acolyte
+MaxTopics       4
+NPCDAT          5
+OddsOfSeeing    20
+Loyalty         10
+Wander          Church
+KnownTopic      Acolyte.1 Join Our Clan
+KnownTopic      Acolyte.2 Loyalty
+KnownTopic      Acolyte.3 Prayer
+KnownTopic      Acolyte.4 Combat
+KnownTopic      Acolyte.5 Evil
+KnownTopic      Acolyte.6 The Church
+KnownTopic      Acolyte.7 Registration
+
+# 11
+Index           _Bum
+MonFile         NPC.PC
+Name            Bum
+Loyalty         0
+OddsOfSeeing    20
+NPCDAT          6
+Wander          Street
+IntroTopic      Bum1.0
+KnownTopic      Bum1.1 My life
+KnownTopic      Bum1.2 Occupation
+KnownTopic      Bum1.3 Ruling
+KnownTopic      Bum1.4 Loyalty
+KnownTopic      Bum1.5 Join Our Clan
+
+# 12
+Index           _Blacksmith
+MonFile         NPC.PC
+Name            Blacksmith
+OddsOfSeeing    30
+MaxTopics       3
+Wander          Market
+KnownTopic      Smith.1 A Mace
+KnownTopic      Smith.2 KOR
+KnownTopic      Smith.3 Tip 1
+KnownTopic      Smith.4 Tip 2
+
+# 13
+Index           _Peasant1
+MonFile         NPC.PC
+Name            Peasant
+MaxTopics       3
+OddsOfSeeing    20
+Wander          Church
+IntroTopic      Peasant1.0
+KnownTopic      Peasant1.1 Favourite Quote
+KnownTopic      Peasant1.2 Join Our Clan
+KnownTopic      Peasant1.3 What do you do?
+KnownTopic      Peasant1.4 Exaggerus
+KnownTopic      Peasant1.5 Gold
+KnownTopic      Peasant1.6 Bums
+KnownTopic      Peasant1.7 Murders
+
+# 14
+Index           _WiseOne
+MonFile         NPC.PC
+Name            The Wise One
+OddsOfSeeing    5
+MaxTopics       1
+Wander          Street
+IntroTopic      Wise.0
+KnownTopic      Wise.1 Strong Clan
+KnownTopic      Wise.2 Strong Army (1)
+KnownTopic      Wise.3 Strong Army (2)
+KnownTopic      Wise.4 Ruling (1)
+KnownTopic      Wise.5 Ruling (2)
+KnownTopic      Wise.6 Ruling (3)
+HereNews        |06 � |12The Wise One is seen answering questions.
+
+# 15
+Index           _Prof
+MonFile         NPC.PC
+Name            The Professor
+# this is actually an NPC you meet in an event, but just remove the next
+# two lines later on after testing
+OddsOfSeeing    20
+MaxTopics       1
+Wander          Street
+IntroTopic      Prof.0
+KnownTopic      Prof.1 The Twins
+KnownTopic      Prof.2 The Profit
+KnownTopic      Prof.3 A Sequence
+
+# 16
+Index           _Jester
+MonFile         NPC.PC
+Name            Jester
+IntroTopic      Jester.0
+KnownTopic      Jester.1 The Orc's Plan
+Topic           Jester.2 Other Orcs
+KnownTopic      Jester.3 Joke
+KnownTopic      Jester.4 Old Kingdom
+
+# 17
+Index           _Peasant2
+MonFile         NPC.PC
+Name            Peasant
+OddsOfSeeing    10
+Wander          Market
+Loyalty         6
+NPCDAT          10
+MaxTopics       3
+KnownTopic      Peasant2.1 Adventures
+KnownTopic      Peasant2.2 Join Our Clan
+KnownTopic      Peasant2.3 KOR
+KnownTopic      Peasant2.4 Occupation
+KnownTopic      Peasant2.5 Murders
+KnownTopic      Peasant2.6 A Song
+
+# 18
+Index           _OldMan
+MonFile         NPC.PC
+Name            Old Man
+OddsOfSeeing    0
+KnownTopic      OldMan.0 Adventure
+KnownTopic      OldMan.1 Gold
+KnownTopic      OldMan.2 Lost Gold
+
+# 19
+Index           _Psychic
+MonFile         NPC.PC
+Name            The Psychic
+OddsofSeeing    10
+KnownTopic      Psychic.0 Spirits
+KnownTopic      Psychic.1 Occupation
+KnownTopic      Psychic.2 The Spirit World
+KnownTopic      Psychic.3 Lelaz
+Topic           Psychic.4 Diablo
+
+# 20
+Index           _CommonMan
+MonFile         NPC.PC
+Name            Common Man
+OddsofSeeing    20
+Wander          Street
+KnownTopic      Common.0 Occupation
+Topic           Common.1 Research
+Topic           Common.2 Five Great Evils
+
+# 21
+Index           _Drunk
+MonFile         NPC.PC
+Name            Drunk Man
+OddsofSeeing    20
+MaxTopics       4
+Wander          Street
+KnownTopic      Drunk.1 The Arts
+KnownTopic      Drunk.2 The Three Doors
+KnownTopic      Drunk.3 Tavern
+KnownTopic      Drunk.4 Gold
+HereNews        |06 � |13The drunk man is wandering the streets today.
+
+# 22
+Index           _Guard
+MonFile         NPC.PC
+Name            Guard
+OddsOfSeeing    20
+Wander          Town Hall
+KnownTopic      Guard.0 Crime
+KnownTopic      Guard.1 Valiance
+KnownTopic      Guard.2 Honesty
+KnownTopic      Guard.3 Corruption
+KnownTopic      Guard.4 Pay
+
+# 23
+Index           _Poet
+MonFile         NPC.PC
+Name            Poet
+OddsOfSeeing    15
+MaxTopics       3
+Wander          Street
+KnownTopic      Poet.1 Poetry
+KnownTopic      Poet.2 Wealth
+KnownTopic      Poet.3 Government
+KnownTopic      Poet.4 Music
+KnownTopic      Poet.5 A Poem
+KnownTopic      Poet.6 Tip
+
+# 24
+Index           _Myau
+MonFile         NPC.PC
+Name            Myau
+OddsOfSeeing    10
+MaxTopics       3
+Wander          Market
+IntroTopic      Myau.0
+KnownTopic      Myau.1 The Vial
+KnownTopic      Myau.2 Join Our Clan
+KnownTopic      Myau.3 Muyans
+KnownTopic      Myau.4 Music
+KnownTopic      Myau.5 Healing
+
+# 25
+Index           _Paladin
+MonFile         NPC.PC
+Name            Paladin
+NPCDAT          7
+OddsOfSeeing    5
+MaxTopics       3
+Wander          Church
+Loyalty         10
+IntroTopic      Paladin.0
+KnownTopic      Paladin.1 Join Our Clan
+KnownTopic      Paladin.2 Loyalty
+KnownTopic      Paladin.3 Riches
+KnownTopic      Paladin.4 Heavenly Sword
+KnownTopic      Paladin.5 The Dark One
+HereNews        |03 � |11A holy paladin was spotted in church.
+
+# 26
+Index           _Merchant
+MonFile         NPC.PC
+Name            Merchant
+OddsOfSeeing    25
+MaxTopics       3
+Wander          Market
+IntroTopic      Merchant.0
+KnownTopic      Merchant.1 Join Our Clan
+KnownTopic      Merchant.2 Goods
+KnownTopic      Merchant.3 Precious goods
+KnownTopic      Merchant.4 Traveling
+Topic           Merchant.4.B A Mission
+KnownTopic      Merchant.5 The Mines
+
+# 30
+Index           _LW
+Name            Lone Wolf
+KnownTopic      LW.1    Sommerlund
+KnownTopic      LW.2    Kai Warriors
+KnownTopic      LW.3    Scrolls
+KnownTopic      JoinClan Join Our Clan
+OddsOfSeeing    10
+Wander          Mine
+NPCDAT          14
+MonFile         NPC.PC
+
+# 31
+Index           _Dung
+Name            Dungeoner
+KnownTopic      JoinClan Join Our Clan
+KnownTopic      Dung.1   World's Fastest Man
+KnownTopic      Dung.2   Dungeons
+KnownTopic      Dung.3   Gold
+OddsOfSeeing    10
+Wander          Mine
+NPCDAT          12
+MonFile         NPC.PC
+
+# 32
+Index           _Bartender
+Name            Bartender
+KnownTopic      JoinClan Join Our Clan
+IntropTopic     Bartender.0
+KnownTopic      Bartender.1 The Tavern
+KnownTopic      Bartender.2 Good Ale
+OddsOfSeeing    20
+Wander          Street
+NPCDAT          11
+MonFile         NPC.PC
+
+# 33
+Index           _Freak
+Name            Freak
+IntroTopic      Freak.0
+KnownTopic      Freak.1 Murderer
+Topic           Freak.2 Town murders
+KnownTopic      Freak.3 The book
+KnownTopic      Freak.4 Your axe
+
+# 34
+Index           _Pirate
+MonFile         NPC.PC
+NPCDAT          13
+QuoteFile       npcquote.q
+Name            Pirate
+IntroTopic      Pirate.0
+KnownTopic      Pirate.1 What's with the eye patches?
+Topic           Pirate.2 Why don't you just wear sunglasses?
+KnownTopic      Pirate.3 Where can I find treasure?
+KnownTopic      Pirate.4 Do you have a wooden leg?
+KnownTopic      Pirate.5 Join our clan!
+Topic           Pirate.6 Come on, where can I REALLY find treasure?
+Topic           Pirate.7 Quit foolin' around, I want to be rich!!
+Topic           Pirate.8 Ok, this is the last time I'll ask, where is the treasure!?
+OddsOfSeeing    20
+Wander          Mine
+
+# 35
+Index           _Oldman2
+QuoteFile       npcquote.q
+Name            Useless Old Man
+KnownTopic      OldMan2.1 BrownTown
+Topic           OldMan2.2 What was so great about it?!
+Topic           OldMan2.3 Why were you kicked out of BrownTown?
+Topic           OldMan2.5 Tell me or I'll grab you by the beard and swing you around.
+Topic           OldMan2.6 Fine, don't tell me.
+Topic           OldMan2.7 Oh, I changed my mind. I want to know!!
+Topic           OldMan2.4 Liar!  Blue Cows are only a legend!
+KnownTopic      OldMan2.8 Old Friends
+Topic           OldMan2.9 Did all your friends have dumb names?
+OddsOfSeeing    20
+Wander          Street
diff --git a/src/doors/clans-devkit/PAK.LST b/src/doors/clans-devkit/PAK.LST
new file mode 100644
index 0000000000000000000000000000000000000000..41a192ff8dac359107493ace48138b6633be3887
--- /dev/null
+++ b/src/doors/clans-devkit/PAK.LST
@@ -0,0 +1,37 @@
+menus.hlp       /hlp/menus
+bulletin.hlp    /hlp/bulletins
+citizen.hlp     /hlp/citizen
+clans.hlp       /hlp/general
+combat.hlp      /hlp/combat
+empire.hlp      /hlp/empire
+army.hlp        /hlp/army
+items.hlp       /hlp/items
+newbie.hlp      /hlp/newbie
+races.hlp       /hlp/races
+ruler.hlp       /hlp/ruler
+spells.hlp      /hlp/spells
+stats.hlp       /hlp/stats
+strategy.hlp    /hlp/strategy
+village.hlp     /hlp/village
+war.hlp         /hlp/war
+wizard.hlp      /hlp/wizard
+quests.e        /e/MyQuests
+eva.e           /e/Eva
+church.e        /e/Church
+pray.e          /e/Pray
+npcquote.q      /q/NpcQuote
+event.mon       /m/Eva
+output.mon      /m/Output
+npc.mon         /m/Npc
+secret.e        /e/Secret
+clans.npc       /dat/Npc
+items.dat       /dat/items
+spells.dat      /dat/spells
+races.dat       /dat/races
+classes.dat     /dat/classes
+schemes.txt     /d/Schemes
+strings.xl      /dat/Language
+list.asc        /px/List
+pxtit.asc       /px/Title
+pg.asc          /px/Pg
+pxnews.asc      /px/News
diff --git a/src/doors/clans-devkit/PG.ASC b/src/doors/clans-devkit/PG.ASC
new file mode 100644
index 0000000000000000000000000000000000000000..82a40523472905b252abbba7d5174605a2d2f5b3
--- /dev/null
+++ b/src/doors/clans-devkit/PG.ASC
@@ -0,0 +1,15 @@
+%C|07
+ 
+ 
+ 
+ 
+   |04圹哌哌哌哌哌哌哌哌哌哌哌咣圻哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌踻07
+|04   圹 |12苘苘苘苘�   苘苘苘苘  |04圹 |13This door game is rated PG for Pretty Good. |04踻07
+|04   圹 |12圹圹�  圹� 圹圹�  圹� |04圹 |12Warning:  |05This door game contains scenes    |04踻07
+|04   圹 |12圹圹�  圹� 圹圹踻07      |04圹 |05of hilarity, violence, and great fun.|07       |04踻07
+|04   圹 |12圹圹�  圹� 圹圹� 苘苘 |04圹|07                                             |04踻07
+|04   圹 |12圹圹圻哌�  圹圹�  圹� |04圹 |05This game was not found to be addictive by  |04踻07
+|04   圹 |12圹圹踻07      |12咣圹圮苒圻 |04圹 |05the Sergeant General.|07                       |04踻07
+|04   圹|07                       |04圹|07                                             |04踻07
+|04   哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌哌遼07
+
diff --git a/src/doors/clans-devkit/PRAY.EVT b/src/doors/clans-devkit/PRAY.EVT
new file mode 100644
index 0000000000000000000000000000000000000000..f223cf704f6f15eff7850d97b759e49627601d8e
--- /dev/null
+++ b/src/doors/clans-devkit/PRAY.EVT
@@ -0,0 +1,80 @@
+# events when you pray that occur
+
+# you are given a book -- book of stamina or healing -- rare
+# given money
+# followers
+# you see a white light and it envelopes you, you gain experience
+# you feel cold -- nothing happens
+# you see the statue of the god of somethingerother cry -- gain experience (ansi)
+
+Event Nothing
+Text "|10Sadly, your prayer has no effect.
+End
+
+Event Nothing2
+Text "|10Sadly, your prayer has no effect.
+End
+
+Event Nothing3
+Text "|10Sadly, your prayer has no effect.
+End
+
+Event Nothing4
+Text "|10Sadly, your prayer has no effect.
+End
+
+Event Nothing5
+Text "You are granted an extra fight by the gods!
+GiveFight 1
+End
+
+Event Pray.1
+Text "|02You pray . . .  What did you pray for?
+Text
+Text " (|05W|02)orld Peace
+Text " (|05G|02)old
+Text " (|05F|02)ollowers
+Text " (|05M|02)ore Monster Fights
+Text " (|05N|02)othing
+Text
+Prompt "[|12WGFMN|02]: |13
+Option W Pray.W
+Option G Pray.G
+Option F Pray.F
+Option M Pray.M
+Option N Pray.N
+End
+
+Result Pray.W
+Text "|02You feel you asked for the impossible.  You get nothing.
+End
+
+Result Pray.G
+Text "|02You pray for gold and feel your gold sack get heavier.  You check it.
+Text "|10You received 1 gold piece!  |02You feel your god is mocking your greed.
+GiveGold 1
+End
+
+Result Pray.M
+Text "|02You pray for another monster fight.
+pause
+Text
+Text "|10You get it!  You gain one monster fight.
+GiveFight 1
+End
+
+Result Pray.F
+Text "|02You watch as 15 people march towards you and offer themselves.
+Text "|03(You gained 15 new followers!)
+GiveFollowers 15
+End
+
+Result Pray.N
+Text "|02You pray for nothing.
+pause
+Text
+Text "Suddenly, a huge sack of gold falls onto your lap.  You open the sack and
+Text "count |10100 |02gold pieces!
+GiveGold 100
+End
+
diff --git a/src/doors/clans-devkit/PXNEWS.ASC b/src/doors/clans-devkit/PXNEWS.ASC
new file mode 100644
index 0000000000000000000000000000000000000000..7ca5cf5c618399ac3481b5ecf18302a45eb39dd8
--- /dev/null
+++ b/src/doors/clans-devkit/PXNEWS.ASC
@@ -0,0 +1,38 @@
+%C|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
+  |12Ye Old Log Of Happenings
+|05==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==-==
+|06  A little boy was found today!  |05But blind, deaf, and dumb.
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |12New Player: |05Napolean
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid by |12O.J. Simpson
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid by |12Joe Blow
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid by |08E|07v|15i|07l D|15o|07e|08r
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid by |04The Clap
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06turns down |09WidowMaker|06's hand in marriage.
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid off
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid by |12Layman
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06was rushed to the hospital!!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Violent |06got laid by |12The Doctor
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |12Mirage |05found the first candle!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |12Mirage |05found the second candle!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |12Mirage |05found the third candle!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |12Mirage |05celebrates his 3rd birthday!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Bark's House |05has been added as an IGM!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+|06  |13Mayor declares today a national holiday!
+                        |05-|13=|05-|13=|05-|13=|05-        |05-|13=|05-|13=|05-|13=|05-
+%P
diff --git a/src/doors/clans-devkit/PXTIT.ASC b/src/doors/clans-devkit/PXTIT.ASC
new file mode 100644
index 0000000000000000000000000000000000000000..ec560c2096b731278e34ea32e9927251b56aca8c
--- /dev/null
+++ b/src/doors/clans-devkit/PXTIT.ASC
@@ -0,0 +1,16 @@
+|07
+ 
+ 
+ 
+            |04苘苘苘苘苘�  |02苘苘苘苘苘   |01苘苘�   |05苘苘  |03苘苘|07     |03苘苘|07
+            |04踻12圹圹|20策|16踻20瞸16踻20軀04|16� |02踻10|18瞸16圹|18策遼16踻18曹|02|16� |01踻09|23瞸17哌遼16踻01� |00|21皘13臂鄄|05|16� |00|19皘11瞸16圹|19軀07|16  |03軀11|19苒圹|00皘07|16
+            |00|20皘12|16踻20瞸16踻00|20皘07|16 |04瞸12圹踻20皘00眧07|16 |02遼10|18臂|16踻02� |00|18皘10|16踻23瞸16踻02� |01踻09踻00|17眧07|16 |00|17皘01|16哕  |05哌哌  |00|19眧11踻16踻19瞸03|16� |11|19苒瞸15瞸11圹|00眧07|16
+            |04踻12圹踻04圮眧12踻23瞸16踻20眧00皘07|16 |02苘遼10|18眧02|16圮踻10|18瞸16圹|00|18眧07|16 |00|17皘09瞸00皘01|16苘|09|17軀00皘07|16 |05軀13|21苘苘|00皘07|16  |03遼11|19遼03|16軀11|19軀03|16軀11|19苒圹遼03|16遼07
+            |04踻12|20瞸23瞸16圹踻20遼16踻20瞸16踻20瞸04|16� |02踻10踻18懿|16圹圹圹|00|18皘07|16 |00|17眧09边踻23瞸17瞸01|16� |05踻13|21策|23瞸21踻05|16�    |03遼11|19咣鄄遼03|16遼07
+            |04踻12圹|20瞸16踻20瞸04|16苓|12|20哌|04|16圻 |02踻10踻18瞸16踻18策|23瞸16踻18策|02|16� |01遼09|17遼07|16 |01遼09|17哌|01|16� |00|21眧05|16哕|13|21槽|05|16�   |03軀11|19苒圹圹軀03|16軀07
+            |04圻|12|20眧16圹踻04踻07      |00|18皘10遼16圹|02� 踻10|18圮|02|16�  |05苘苘苘苘  遼13|21咣|05|16� |03軀11|19苒槽踻00皘11踻15瞸11圻軀03|16軀07
+            |04曹踻12|20皘04|16踻12踻00|20皘07|16      |00|18眧02|16圻|10|18弑|07|16 |02踻10|18卟眧00皘07|16 |00|21皘05|16遼13|21遼23瞸21圹圮|05|16軀13|21苘槽|00皘07|16 |03踻11|19瞸03|16苓|11|19遼03|16� 遼11|19遼03|16哕|11|19軀00眧07|16
+            |04郾�  咣|07      |00|18瞸02|16�  � � 遼10|18遼00眧07|16 |05踻13|21遼07|16 |05遼13|21哌哌哌哌 |05|16� |00|19皘11哌|07|16       |11|19哌|00皘07|16
+ 
+                                  |13P|05roject|01-|09X|07
+ 
diff --git a/src/doors/clans-devkit/QUESTS.EVT b/src/doors/clans-devkit/QUESTS.EVT
new file mode 100644
index 0000000000000000000000000000000000000000..80b6e6ac3c0aa03980caab6cf69197e34ceaa763
--- /dev/null
+++ b/src/doors/clans-devkit/QUESTS.EVT
@@ -0,0 +1,533 @@
+# -----------------------------------------------------------------------------
+# The Orcs -- Act I
+Event   Quest1
+Text "%C
+Text "|10The Orcs |02-- |14Act I
+Text
+Text "|02Several orcs have been wreaking havoc on the townspeople.  So far, no one
+Text "has been able to stop them from looting shops and killing the innocent.
+Text "Using the reports of many villagers, you were able to figure out the location
+Text "of the orc's hideout.
+pause
+Text
+Text "You find the entrance to the mine where the orcs are hiding out and
+Text "follow it.
+pause
+Text
+Text "|02You eventually find the doors to the orc's hideout.  Without haste,
+Text "you kick down the doors to reveal several orcs awaiting your wrath...
+pause
+AddEnemy EVENT.MON 13
+AddEnemy EVENT.MON 13
+AddEnemy EVENT.MON 13
+AddEnemy EVENT.MON 13
+AddEnemy EVENT.MON 14
+AddEnemy EVENT.MON 15
+{R30}AddEnemy EVENT.MON 13
+{R20}AddEnemy EVENT.MON 14
+{R20}AddEnemy EVENT.MON 14
+{R10}AddEnemy EVENT.MON 15
+{R10}AddEnemy EVENT.MON 15
+Fight NextLine STOP STOP
+Text
+Text "|02After destroying the orcs, you free many prisoners they had held captive.
+Text "Among them, you find one with a peculiar costume . . .
+pause
+Chat _Jester
+Text
+Text "|02You escort the jester to town and soon he is among safe hands.  The
+Text "townspeople cheer you on and many are impressed.  |03(50 followers join the
+Text "clan!  You gain 50 points also!)
+GiveFollowers 50
+GivePoints    50
+DoneQuest
+End
+
+# -----------------------------------------------------------------------------
+# The Quest for Justice
+Event   Quest2
+Text "%C
+Text "|10The Quest for Justice |02-- |14Act I
+Text
+Text "|02Using the directions given to you by the peasant, you find the home of the
+Text "evil beast deep in the forest.  You see smoke rise from the chimney.  The
+Text "beast must be here right now.
+pause
+Text
+Text "You enter the house unnoticed and eventually make your way into the den
+Text "where you find the beast sitting down and reading a book.  He doesn't look
+Text "up from his book.  You can see that he is human with a few freakish features
+Text "such as a totally hairy face.  What do you wish to do?
+Text
+Text " (|05A|02)ttack the Freak now before it's too late!
+Text " (|05T|02)alk to the freak
+Text
+Prompt "[|12AT|02]: |13
+Option A Quest2.Attack
+Option T NextLine
+Chat _Freak
+Text
+Text "|02You realize you must search out and defeat the rich murderer in town.
+Text "|03(You gain 100 points for the quest!)
+GivePoints 100
+DoneQuest
+End
+
+        Result Quest2.Attack
+        Text
+        Text "|02You ready your weapons as the beast he looks up from his book.
+        Text
+        Text "|10I am quite apt at protecting myself|02, he says as he readies his large
+        Text "axe.
+        pause
+        AddEnemy EVENT.MON 23
+        Fight NextLine Quest2.Defeat STOP
+        Text
+        Text "|10I was invincible!! |02the beast says.  |10Please listen to me.  I am not the
+        Text "murderer you are looking for.  <cough>  I was made the scapegoat.  There is a
+        Text "very rich man in the village who wanted to get rid of some people and he did
+        Text "so by <cough> framing me with the crimes.  I am simple man who was forced to
+        Text "live as a recluse because of my features. <cough>  Please exact my revenge and
+        Text "defeat the rich murderer! |02he says as he dies at your feet.
+        TellQuest Quest3
+        # make it so he is dead
+        SetFlag P1
+        Text
+        Text "|03(You gain 50 points for the quest!)
+        GivePoints 50
+        DoneQuest
+        End
+
+        Result Quest2.Defeat
+        Text
+        Text "|10Perhaps that'll teach you a lesson in manners!|02 says the beast after
+        Text "finishing off the clan.
+        End
+
+# -----------------------------------------------------------------------------
+Event Quest3
+Text "%C
+Text "|10The Quest for Justice |02-- |14Act II
+Text
+Text "|02You seek out the home of the rich businessman who is the sole cause of the
+Text "recent town murders.  You stand before the large mansion that is his home.
+Text "Before you are the gates that lead inside.  You are shocked to see the gates
+Text "are unlocked.  What do you do?
+Text
+Text " (|05E|02)nter through the open gates
+Text " (|05S|02)neak in another way
+Text
+Prompt "[|12ES|02]: |13
+Option E Quest3.E
+Option S Quest3.S
+End
+
+        Result Quest3.E
+        Text
+        Text "|02You enter through the gates and see no one initially.
+        pause
+        Text
+        Text "You turn and see 6 hellhounds pursuing you!  You turn and fight.
+        pause
+        AddEnemy EVENT.MON 21
+        AddEnemy EVENT.MON 21
+        AddEnemy EVENT.MON 21
+        AddEnemy EVENT.MON 21
+        AddEnemy EVENT.MON 22
+        AddEnemy EVENT.MON 22
+        Fight NextLine STOP STOP
+        Text
+        Text "|02The clan moves quickly towards the house after defeating the hounds.
+        pause
+        Jump Quest3.Fountain
+        End
+
+        Result Quest3.S
+        Text
+        Text "|02You find a low part on the fence and the clan quickly hops over it in
+        Text "sequence.  Once over you look around and see a gardener busy working on
+        Text "some flowers.  He looks up with eyes raging red.  He is not human!  He lifts
+        Text "his hoe and charges towards you!
+        pause
+        AddEnemy EVENT.MON 24
+        Fight NextLine STOP STOP
+        Text
+        Text "|02You walk away from the rotting corpse of the gardener and make your way
+        Text "towards the mansion.
+        pause
+        Jump Quest3.Fountain
+        End
+
+        Result Quest3.Fountain
+        Text
+        Text "|02Outside the doors into the house is a beautiful fountain with a statue of a
+        Text "mermaid in the middle.  The water looks refreshing but you are unsure of its
+        Prompt "safety.  Do you wish to drink from the fountain? [|12Y/N|02]: |13
+        Option Y Quest3.Drink
+        Option N NextLine
+        Jump Quest3.Hall
+        End
+
+        Result Quest3.Drink
+        Text
+        Text "|02Each clansman drinks from the fountain and is refreshed!  All lost HP is
+        Text "regained.  The water has some magical healing strengths!
+        Heal
+        pause
+        Jump Quest3.Hall
+        End
+
+        Result Quest3.Hall
+        Text "%C
+        Text "|02Inside the mansion is marvelous.  Large paintings line the walls while a
+        Text "marble floor lies below.  You are still in awe when you hear the sound of
+        Text "footsteps.  You turn to see 3 guards coming your way.
+        pause
+        AddEnemy EVENT.MON 25
+        AddEnemy EVENT.MON 26
+        AddEnemy EVENT.MON 25
+        Fight NextLine STOP STOP
+        Text
+        Text "|02After defeating the guards you notice that a large man had been standing
+        Text "watching you all along.
+        Text "
+        Text "|10I don't know how you got passed the hounds and the guards but you will not
+        Text "get passed me.  |02You watch as the businessman grabs a sword spread out against
+        Text "the wall and swings it around.
+        pause
+        AddEnemy EVENT.MON 27
+        Fight NextLine STOP STOP
+        Text
+        Text "|02You defeat the businessman and see some scattered sheets on a desk up ahead.
+        Text "After reading through the sheets, you realize these are sufficient evidence
+        Text "to clear the freak's name.
+        pause
+        Text
+        {P1}Text "Unfortunately, you realize you had killed the beast.  His name will
+        {P1}Text "be cleared either way you tell yourself.  He would have wanted it this
+        {P1}Text "way . . .  |03(You gain 50 points.)
+        {P1}GivePoints 50
+        {!P1}Text "You rush out to the freak's house and tell him the good news.  Soon the word
+        {!P1}Text "gets around that he is not the murderer they were looking for!
+        {!P1}Text "|10For your kindness, the freak gives you 500 gold pieces!
+        {!P1}GiveGold 500
+        {!P1}Text "|03(For clearing the freak's name, you receive 100 points.)
+        {!P1}GivePoints 100
+        DoneQuest
+        End
+
+# -----------------------------------------------------------------------------
+Event   Quest4
+Text "%C
+Text "|10Caravan
+Text
+Text "|02You meet the merchant along the outskirts of town as planned.  He provides
+Text "you with horses and your journey begins...
+pause
+Text
+Text "You spend an hour traveling and not much occurs.  The sun is up high and the
+Text "wind is soothing.  Suddenly you hear a noise to the left of the caravans.
+Text "What do you wish to do?
+Text
+Text " (|05I|02)nvestigate
+Text " I(|05g|02)nore it
+Text
+Prompt "[|12IG|02]: |13
+Option I NextLine
+Option G Quest4.G
+Text
+Text "|02You motion for the rest of the clan to follow your lead.  You tell the
+Text "merchant to wait behind.
+pause
+Text
+Text "After about moving |1050 |02feet, five thieves jump out of the bushes!
+pause
+AddEnemy EVENT.MON 28
+AddEnemy EVENT.MON 28
+AddEnemy EVENT.MON 28
+AddEnemy EVENT.MON 28
+AddEnemy EVENT.MON 28
+Fight NextLine STOP NoRun
+Text
+Text "|02After defeating the thieves, you turn to return to the merchant.  You find
+Text "him being harassed by more thieves!  You gallop towards the merchant but some
+Text "of the thieves run off with goods in hand!  Three thieves remain waiting for
+Text "you to near.
+pause
+AddEnemy EVENT.MON 29
+AddEnemy EVENT.MON 29
+AddEnemy EVENT.MON 29
+Fight NextLine STOP NoRun
+Text
+Text "|02The merchant, although not hurt, looks at you with great anger.
+Text "|10I lost about 500 gold worth of goods!  That's coming out of your pay!
+SetFlag T1
+pause
+Jump Quest4.2
+End
+
+        Result Quest4.G
+        Text
+        Text "|02You ignore the noise and continue moving forward.  You hear more noises but
+        Text "this time you can see their source.  10 thieves approach your caravan with
+        Text "weapons in hand!
+        pause
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 28
+        AddEnemy EVENT.MON 29
+        AddEnemy EVENT.MON 29
+        AddEnemy EVENT.MON 29
+        Fight NextLine STOP NoRun
+        Text "|02The merchant is not hurt and smiles.  He is obviously pleased with your
+        Text "efforts.
+        pause
+        Jump Quest4.2
+        End
+
+        Result Quest4.2
+        Heal
+        Text
+        Text "|02You wander for another hour and come upon another group.  This time it is
+        Text "one thief, but he is very large!
+        pause
+        AddEnemy EVENT.MON 30
+        Fight NextLine STOP NoRun
+        Text
+        Text "|02The large thief collapses with a great THUD!  You continue your caravan until
+        Text "you are on the outskirts of the destination town.
+        pause
+        Heal
+        Text
+        Text "|02The clan breathes a collective sigh of relief for finally reaching their
+        Text "destination.  After hearing more noises from behind, you realize you are not
+        Text "out of the bushes yet.  You turn to see 2 wyverns approaching!
+        pause
+        AddEnemy EVENT.MON 31
+        AddEnemy EVENT.MON 31
+        Fight NextLine STOP NoRun
+        Text
+        Text "|02You deliver a final blow to the remaining wyvern and hurry into town.  The
+        {T1}Text "merchant is somewhat pleased by the trip's success.  |10Although you got me to
+        {T1}Text "town, I am deducting 500 gold from your pay of 2000GP since you let those
+        {T1}Text "thieves get some of my items!  |03(He gives you 1500GP.)
+        {T1}GiveGold 1500
+        {T1}Text
+        {T1}Text "|02After receiving your pay, you return home.  |03(You receive 50 points.)
+        {T1}GivePoints 50
+        {!T1}Text "merchant is very pleased by the trip's success.  |10Since you got me to
+        {!T1}Text "town safely without sacrficing any of my wares, I will give you the 2000GP
+        {!T1}Text "I promised.  |03(He gives you 2000GP.)
+        {!T1}Text
+        {!T1}GiveGold 2000
+        {!T1}Text "|02After receiving your pay, you return home.  |03(You receive 75 points.)
+        {!T1}GivePoints 75
+        DoneQuest
+        End
+
+# -----------------------------------------------------------------------------
+# The Minstrel
+Event Quest5
+Text "%C
+Text "|10The Minstrel
+Text
+Text "|02You enter the mines and follow a path your instincts tell you is the way to
+Text "the minstrel.
+pause
+Text
+Text "|06After half an hour of walking, your clan comes upon a fork in the mines.  You
+Text "ponder on which route to take.  The left looks less used than the right route.
+Text
+Text " (|05L|06)eft Route
+Text " (|05R|06)ight Route
+Text
+Prompt "|06[|12LR|06]: |13
+Option L Quest5/L
+Option R Quest5/R
+End
+
+        Result Quest5/L
+        Text
+        Text "|06You follow the left route until you come upon several hellhounds.  They seem
+        Text "to be sniffing some dead bodies until they notice you.  They slowly come
+        Text "towards you . . .
+        pause
+        AddEnemy EVENT.MON 32
+        AddEnemy EVENT.MON 32
+        AddEnemy EVENT.MON 32
+        Fight NextLine STOP NoRun
+        Text
+        Text "|06You finish off the hellish beasts and move on.  You continue walking
+        Text "and reach another fork in the mines.  You see the left route lights up a
+        Text "little.  The right route seems to grow darker as you peer down its path.
+        Text "Which route do you take?
+        Text
+        Text " (|05L|06)eft Route
+        Text " (|05R|06)ight Route
+        Text
+        Prompt "|06[|12LR|06]: |13
+        Option L Quest5/L/L
+        Option R Quest5/L/R
+        End
+
+        Result Quest5/L/L
+        Text
+        Text "|14You follow the path and find you have exited the mines!  You realize it
+        Text "would be too late to search for the minstrel again today and you head back
+        Text "to town.
+        End
+
+        Result Quest5/L/R
+        Text
+        Text "|07You follow the right route and enter a room with metallic walls.  However,
+        Text "the walls are covered with a strange green goo.  You watch as the goo slowly
+        Text "joins together and green slyme forms!
+        pause
+        AddEnemy EVENT.MON 33
+        AddEnemy EVENT.MON 33
+        Fight NextLine STOP NoRUN
+        Text
+        Text "|06You curse the green goo as you wipe it off your hands.  Soon, you are on
+        Text "your way again.  You continue walking until you see a light up ahead!
+        pause
+        Text
+        Text "|14The light finally leads to the outside world.  You rub your eyes and the
+        Text "world comes into focus once more.  Seeing that it would be too late to
+        Text "search for the minstrel again, you return to town.
+        End
+
+        Result Quest5/R
+        Text
+        Text "|06The right route is well lit as torches line the walls.  You hear noise up
+        Text "ahead.  The clan readies their weapons.  You are not surprised when a group
+        Text "of six skeletal fiends charges towards you.
+        pause
+        AddEnemy EVENT.MON 34
+        AddEnemy EVENT.MON 34
+        AddEnemy EVENT.MON 34
+        AddEnemy EVENT.MON 34
+        AddEnemy EVENT.MON 34
+        AddEnemy EVENT.MON 34
+        Fight NextLine STOP NoRUN
+        Text
+        Text "|06You smile as you finish off the final skeletal fiend.  You look around and
+        Text "find |101000GP |06on the ground!
+        GiveGold 1000
+        pause
+        Text
+        Text "|06You look down and kick one of the skeletal fiend's skulls into the air
+        Text "and smile to yourself.
+        pause
+        Text
+        Text "|06You walk further down the corridors and come upon two more paths.  The left
+        Text "route seems to be lit up by a red light but you cannot see what the source
+        Text "of the light is.  You look to the right and see the corridor is dark.
+        Text "Which route do you take?
+        Text
+        Text " (|05L|06)eft Route
+        Text " (|05R|06)ight Route
+        Text
+        Prompt "[|12LR|06]: |13
+        Option L Quest5/R/L
+        Option R Quest5/R/R
+        End
+
+        Result Quest5/R/L
+        Text
+        Text "|04You follow the path and then realize what the source of the light is.  You are
+        Text "awestruck to see a large golden dragon resting with several red candles
+        Text "surrounding it.  It was sleeping as you entered but even your breathing has
+        Text "awoken it!  It raises its large head and stares at you with anger.
+        pause
+        # fight here
+        AddEnemy EVENT.MON 35
+        Fight NextLine STOP NoRUN
+        Text
+        Text "|06After defeating the dragon, you look around and find 600 gold pieces!
+        Text "You follow the path as it leads behinds the dragons den and see that it leads
+        Text "back to the outside world.  By now, the clan is too tired to journey back into
+        Text "the mines to search for the minstrel and you decide to call it a day and
+        Text "return to town . . .
+        GiveGold 600
+        End
+
+        Result Quest5/R/R
+        Text
+        Text "|06You follow the darker path and your ears suddenly detect something.  A voice!
+        Text "You rush along the dark path and find an iron door on the side.  The door is
+        Text "locked, but you find it breaks easily with a heavy kick.  You open the door
+        Text "and find a thin man with a mandolin in hand.  He is singing a beautiful song
+        Text "as you enter and it soothes your nerves.  The clan feels magically healed by
+        Text "the wonderful sounds!  You explain your story to the minstrel and he agrees to
+        Text "be rescued.  (Thank goodness!)  You lead him out and follow the trail further.
+        pause
+        Text
+        Text "|02Soon you see the light ahead and realize you are almost out of the mines.
+        pause
+        Text
+        Text "|02Suddenly, the bright light ahead is covered by the silhouettes of several
+        Text "ghouls.  Their howl is definitely not music to your ears.  You ready your
+        Text "weapons and tell the minstrel to stand aside for now.
+        pause
+        Heal
+        AddEnemy EVENT.MON 36
+        AddEnemy EVENT.MON 36
+        AddEnemy EVENT.MON 36
+        AddEnemy EVENT.MON 36
+        Fight NextLine STOP NoRUN
+        Text
+        Text "|06You deliver a final blow to the ghoul and watch as falls to the ground, limbs
+        Text "flailing.  You rush back to the minstrel and lead him out into the daylight.
+        Text "After returning to town with him, he sings another wondrous song which
+        Text "inspires the clan further.  |03(You gain 1 monster fight!)
+        GiveFight 1
+        DoneQuest
+        End
+
+
+# -----------------------------------------------------------------------------
+Event Quest11
+Text "%C
+Text "|10The Orcs |02-- |14Act II
+Text
+Text "|02Using the jester's instructions, you find the hideout of the second group
+Text "of orcs.
+pause
+Text
+Text "You arrive outside the orc's hideout and see two guards.  They spot the clan
+Text "immediately and come brandishing their swords.
+pause
+AddEnemy EVENT.MON 18
+AddEnemy EVENT.MON 18
+Fight NextLine STOP STOP
+Text
+Text "|02After doing away with the orcs, you enter the main hideout and attack the
+Text "rest . . .
+pause
+AddEnemy EVENT.MON 16
+AddEnemy EVENT.MON 16
+AddEnemy EVENT.MON 16
+AddEnemy EVENT.MON 16
+AddEnemy EVENT.MON 16
+AddEnemy EVENT.MON 16
+AddEnemy EVENT.MON 17
+AddEnemy EVENT.MON 17
+{R30}AddEnemy EVENT.MON 16
+{R20}AddEnemy EVENT.MON 16
+{R20}AddEnemy EVENT.MON 17
+{R10}AddEnemy EVENT.MON 17
+Fight NextLine STOP STOP
+Text
+Text "|02After destroying the orcs, you find no prisoners hidden away, but you do find
+Text "a few sacks of gold totalling 800 gold pieces!
+GiveGold 800
+pause
+Text
+Text "You feel relieved after removing the orcish plague from the townspeople.
+DoneQuest
+End
+
diff --git a/src/doors/clans-devkit/QUESTS.HLP b/src/doors/clans-devkit/QUESTS.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..b9ec4b2834532656cf1313f621099194665a3ac3
--- /dev/null
+++ b/src/doors/clans-devkit/QUESTS.HLP
@@ -0,0 +1,125 @@
+^The Orcs -- Act I
+|10The Orcs -- Act I
+|06-----------------
+|02Search out the orcish lair and end their wrath on the poor villagers.
+
+|12Difficulty: Very Easy
+^END
+
+^The Quest for Justice -- Act I
+|10The Quest for Justice -- Act I
+|06------------------------------
+|02Defeat the beast who lives in the forest to end his murderous wrath.
+
+|12Difficulty: Moderately Hard
+^END
+
+^The Quest for Justice -- Act II
+|10The Quest for Justice -- Act II
+|06-------------------------------
+|02Defeat the rich murderer who framed the freak.
+
+|12Difficulty: Moderately Hard
+^END
+
+^Caravan
+|10Caravan
+|06-------
+|02Guide the merchant and his wares to the safety of another town.  You will
+encounter various foes.  You'll need lots of energy as you won't be healed
+after combat!
+
+|12Difficulty: Moderately Hard
+^END
+
+^The Minstrel
+|10The Minstrel
+|06------------
+|02Leonard the minstrel has been kidnapped by some creatures in the mines.
+Attempt a rescue of Leonard.
+
+|12Difficulty: Hard
+^END
+
+^Drakuul's Legacy
+|10Darkuul's Legacy
+|06----------------
+|02The vampire Darkuul has been causing several deaths and the townspeople have
+had enough of it.  They want him destroyed once and for all.
+
+|12Difficulty: Very Hard
+|12WARNING: Quest not complete!
+^END
+
+^The Quest for the Lost King
+|10The Lost King
+|06-------------
+|02The king of the old empire was kidnapped and imprisoned by The Dark One.
+Find the king and attempt a rescue mission.
+
+|12Difficulty: Hard
+|12WARNING: Quest not complete!
+^END
+
+^The Quest for the Lost Knight
+|10The Lost Knight
+|06-------------
+|12Difficulty: Moderate
+|12WARNING: Quest not complete!
+^END
+
+^The Quest for Vengeance
+|10The Quest for Vengeance
+|06-----------------------
+|12Difficulty: Easy
+|12WARNING: Quest not complete!
+^END
+
+^The Spirits of Lovers
+|12WARNING: Quest not complete!
+^END
+
+^The Orcs -- Act II
+|02Search out the second orcish lair and destroy those within.
+
+|12Difficulty: Easy
+^END
+
+^The Lost Treasure
+|12WARNING: Quest not complete!
+^END
+
+^The Spirit World
+|12WARNING: Quest not complete!
+^END
+
+^The Wyvern Lord
+|12WARNING: Quest not complete!
+^END
+
+^The Orc Lord
+|12WARNING: Quest not complete!
+^END
+
+^The Dragon Lord
+|12WARNING: Quest not complete!
+^END
+
+^The Demon Lord
+|12WARNING: Quest not complete!
+^END
+
+^Sword of The Heavens
+|12WARNING: Quest not complete!
+^END
+
+^The Poet's Quill
+|02Find the thieves and return the quill to the poet.
+
+|12Dfficulty: Moderate
+|12WARNING: Quest not complete!
+^END
+
+^The Dark One
+|12WARNING: Quest not complete!
+^END
diff --git a/src/doors/clans-devkit/RACES.HLP b/src/doors/clans-devkit/RACES.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..6b36e763b92dda0097deb5ce2aa1361c462c5f87
--- /dev/null
+++ b/src/doors/clans-devkit/RACES.HLP
@@ -0,0 +1,198 @@
+^Classes
+
+ |0BBarbarian    |0CNo skills but strongest fighter.
+ |0BWarrior      |0CA few skills.  Not as strong as a barbarian.  High agility.
+ |0BKnight       |0CHigh starting gold.  High charisma.  High agility.
+ |0BMartial Artist
+              |0CLow starting gold.  High agility, high dexterity, mystic
+              skills.
+ |0BAssassin     |0CHigh agility and dexterity, a few skills.  Low charisma.
+              High starting gold.
+ |0BHealer       |0CSeveral spells used for healing or protection.  Not a good
+              fighter.
+ |0BNecromancer  |0CSeveral spells used to raise and banish the undead. Weak fighter.
+ |0BSorcerer     |0CHas several destructive spells.  Low strength.
+ |0BWizard       |0CSeveral general spells.  Low strength.
+ |0BPirate       |0CVery agile but no spells.
+ |0BSamurai      |0CLike martial artists but stronger and less agile.
+
+^END
+
+^Barbarian
+ |0BBarbarian
+
+ |0CNo skills but strongest fighter.  These are the strongest warriors and
+ are often included in most clans.
+
+^END
+
+^Warrior
+ |0BWarrior
+
+ |0CWarriors have learned a few skills in training.  They are not as strong
+ as barbarians, however.  They do have high agility.
+
+^END
+
+^Knight
+ |0BKnight
+
+ |0CKnights, because of their background, have high starting gold and high
+ charisma.  Through training, they have learned to improve their agility
+ and dexterity.
+
+^END
+
+^Martial Artist
+ |0BMartial Artist
+
+ |0CMartial artists depend on their amazing agility and dexterity.  Strength
+ is less important but they are not weak.  They have low starting gold.
+ Training has allowed them to learn some mystic skills.
+
+^END
+
+^Assassin
+ |10Assassin
+
+ |0CHigh agility and dexterity, a few skills.  Low charisma.  High starting gold.
+
+^END
+
+^Healer
+ |0BHealer
+
+ |0CThese magicians have several spells used for healing or protection.  They
+ are poor at combat but are excellent at helping other members of the clan
+ out if they are in need of healing while in battle.
+
+^END
+
+^Necromancer
+ |0BNecromancer
+
+ |0CNecromancers have in their arsenal several spells to raise and banish
+ the undead.  They make weak fighters but their spellcasting abilities make
+ up for this.
+
+^END
+
+^Sorcerer
+ |0BSorcerer
+
+ |0CSorcerers have several destructive spells at their disposal.
+
+^END
+
+^Wizard
+ |0BWizard
+
+ |0CWizards have several general spells to use and aren't as focused on
+ specific styles as much as sorcerers or necromancers.  They have low strength.
+
+^END
+
+^Pirate
+ |0BPirate
+
+ |0CPirates are surprisingly agile and fairly strong but lack skills.
+
+^END
+
+^Samurai
+ |0BSamurai
+
+ |0CUsing martial arts but also shear strength, these mystic warriors
+ are powerful and know some skills.
+
+^END
+
+^Races
+
+ |0BHuman        |0CAverage stats.
+ |0BDwarf        |0CHigh strength and hitpoints.
+ |0BElf          |0CHigh hitpoints and wisdom.  Dextrous.  Build up mana
+              quickly.
+ |0BHalf-Elf     |0CA combination of human and elven stats.
+ |0BHalfling     |0CHave high dexterity and agility.
+ |0BOrc          |0CHigh strength and agility, but low charisma.
+ |0BMuya         |0CA strange race of cute, rabbit-like creatures.  Can use
+              magic very well.
+ |0BMinotaur     |0CThese half-men/half-bulls are the strongest race available
+              but are not very agile.
+ |0BDemon        |0CDemons are able to instill fear in their enemy.
+
+^END
+
+^Human
+ |0BHuman
+
+ |0CAverage stats.  Can be most any class.
+
+^END
+
+^Dwarf
+ |0BDwarf
+
+ |0CVery tough race.  High strength and hitpoints.  Can endure with the best
+ of them.
+
+^END
+
+^Elf
+ |0BElf
+
+ |0CA wise race.  Excellent at using magic.  Dextrous but not too strong.  They
+ can build up their mana quickly.
+
+^END
+
+^Half-Elf
+ |0BHalf-Elf
+
+ |0CA cross between elves and humans.  They have statistics varying between
+ the two races.
+
+^END
+
+^Halfling
+ |0BHalfling
+
+ |0CSmall human-like race.  These are very quick beings and have high agility
+ and dexterity.  They have poor strength, however.
+
+^END
+
+^Orc
+ |0BOrc
+
+ |0COrcs are quite strong and have fairly high endurance.  They are mainly
+ warriors and make poor magicians.
+
+^END
+
+^Muya
+ |0BMuya
+
+ |0CMuyans are a strange race.  They are small and resemble a cross between
+ a rabbit and a cat.  They have large ears and are extremely cute (giving
+ them high charisma).  However, they have poor strength and often become
+ healers as they have a great build-up of mana.
+
+^END
+
+^Minotaur
+ |0BMinotaur
+
+ |0CThese beasts are the most powerful race but their bulky size prevent them
+ from moving quickly and efficiently.
+
+^END
+
+^Demon
+ |0BDemon
+
+ |0CDemons are red, winged creatures.  They are quite dextrous and possess
+ some skills.
+
+^END
diff --git a/src/doors/clans-devkit/RACES.TXT b/src/doors/clans-devkit/RACES.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..003b19132dc36265a83b810dd6b0885ea9f9ffe5
--- /dev/null
+++ b/src/doors/clans-devkit/RACES.TXT
@@ -0,0 +1,107 @@
+# Stats, an explanation (for myself):
+#
+# for stats, 5 is average, 8 is excellent, 3 is poor, 10 is amazing
+#
+# armorstr, 1 is average, 0 is ok, 2 is excellent
+
+
+Name            Human
+Agility         5
+Dexterity       5
+Strength        5
+Wisdom          4
+ArmorStr        0
+Charisma        4
+MaxHP           12
+MaxMP           4
+Gold            300
+
+Name            Dwarf
+Agility         4
+Dexterity       5
+Strength        8
+Wisdom          3
+ArmorStr        2
+Charisma        3
+MaxHP           17
+MaxMP           3
+Gold            75
+
+Name            Elf
+Agility         7
+Dexterity       8
+Strength        4
+Wisdom          7
+ArmorStr        0
+Charisma        5
+MaxHP           16
+MaxMP           6
+Gold            50
+
+Name            Half-Elf
+Agility         6
+Dexterity       7
+Strength        5
+Wisdom          6
+ArmorStr        0
+Charisma        4
+MaxHP           14
+MaxMP           4
+Gold            80
+
+Name            Halfling
+Agility         8
+Dexterity       7
+Strength        3
+Wisdom          4
+ArmorStr        0
+Charisma        3
+MaxHP           15
+MaxMP           8
+Gold            80
+
+Name            Orc
+Agility         4
+Dexterity       3
+Strength        8
+Wisdom          2
+ArmorStr        2
+Charisma        0
+MaxHP           14
+MaxMP           3
+Gold            500
+
+Name            Muya
+Agility         6
+Dexterity       5
+Strength        4
+Wisdom          7
+ArmorStr        0
+Charisma        6
+MaxHP           8
+MaxMP           7
+Gold            500
+
+Name            Minotaur
+Agility         2
+Dexterity       2
+Strength        9
+Wisdom          0
+ArmorStr        3
+Charisma        0
+MaxHP           15
+MaxMP           0
+Gold            0
+
+Name            Demon
+Agility         5
+Dexterity       8
+Strength        5
+Wisdom          4
+ArmorStr        1
+Charisma        0
+MaxHP           12
+MaxMP           5
+Gold            0
+Spell           19
+Spell           18
diff --git a/src/doors/clans-devkit/RESET.HLP b/src/doors/clans-devkit/RESET.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..f89ce155ddf192256ddbbcb3d366033098597492
--- /dev/null
+++ b/src/doors/clans-devkit/RESET.HLP
@@ -0,0 +1,65 @@
+Reset Help for The Clans
+
+^Date Game Starts
+|07 The Start Date Configuration allows you to reset the game earlier than
+ actually starting.  This option is very useful for League Coordinators
+ in Inter-BBS games to force all systems to start on the same date (using
+ league-wide reset).  This option is also useful for Tournament games in
+ which you want to allow players to sign up early.
+^END
+
+^Last Join Date
+|07 The Join Date option allows the sysop (or LC) to determine the last
+ date a player can join the game.  This is useful for restricting access
+ to latercomers in the game for tournaments, etc.
+^END
+
+^Village Name
+|07 This option is only used in a local game.  It allows you to define the
+ name of the village in the game.
+^END
+
+^Elimination Mode
+ |07Elimination mode play is different from regular play.
+
+ ** Feature not yet implemented in the current version.
+
+ |12**NOTE**  |07In InterBBS games, only the League Coordinator can use this
+ option.  If any other BBS sets it, it will not have any affect on the game.
+^END
+
+^Clan Travel
+|07 This toggles whether or not a clan can travel from one village to another
+ in a league.  (InterBBS Only)
+^END
+
+^Lost Troops
+|07 This sets how many days before lost troops (and other data) will be returned
+ to this BBS.  (InterBBS Only)
+^END
+
+^Clan Empires
+|07 If you do not want the players to build up clan empires, toggle it off
+ with this option.
+^END
+
+^Mine Fights
+|07 This option sets how many mine fights a clan gets each day.
+^END
+
+^Clan Combat
+|07 This option sets how many clan vs clan fights a clan gets each day.
+^END
+
+^Max Permanent Members
+|07 This setting will allow you to choose how many permanent members a clan
+ can have.  If you wish each user to go solo, set this value to 1.  On the
+ other hand, if you want them to have the most number of members (disabling
+ the ability of NPCs) set this value to 6.
+^END
+
+^Days Of Protection
+|07 This is the number of days a clan will be in protection for.  Protection
+ is used to allow new users to enter the game and build up a bit before
+ being attacked by experienced users already playing.
+^END
diff --git a/src/doors/clans-devkit/RULER.HLP b/src/doors/clans-devkit/RULER.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..e981332061551729b21b095b06d7b0717cb18710
--- /dev/null
+++ b/src/doors/clans-devkit/RULER.HLP
@@ -0,0 +1,122 @@
+^Tax Rate
+ |0CThe tax rate is simply the amount of taxes collected from warriors who
+ fight within the mines.  After fighting in the mines, they are taxed by
+ the tax rate the ruler sets.
+
+ |14A good starting value is 10%.
+
+^END
+
+^GST
+ |0CThis is the goods and services tax and is applied whenever a good is
+ purchased or service is provided for a fee.
+
+ |14A good starting value is 6%.
+
+^END
+
+^Training Hall
+ |0CThe training hall is needed for training clan members.  Without one, clans
+ cannot upgrade their strengths and fight in tougher levels.  If you are in
+ a league, it is a good idea to build this right away.
+
+ |0BA higher level training hall will allow clans to require less training
+ points to train.
+
+^END
+
+^Church
+ |0CThe church allows ressurection of the dead among other things.  It is not
+ important in the beginning of a game but will become important later on when
+ clan members are killed easily.
+
+ |0BA higher level church will allow more resurrections.
+
+^END
+
+^Color Scheme
+ |0CThe colour scheme of the game can be changed here.  Only the ruler may
+ change the colour scheme and it may be a good way to leave your mark on
+ the villagers.
+^END
+
+^Flag
+ |0CThe flag can be changed by the ruler only.  It is a good idea to come up
+ with an original flag that you will wave whenever *you* are in rule.
+^END
+
+^Vault
+ |0CThe vault is where the town's gold is stored.  This is the gold used for
+ building or upgrading structures within the town (such as a church).
+ You can withdraw and deposit into this vault.  Doing with either one
+ will either decrease or increase your popularity respectively.
+
+^END
+
+^Deposit into Vault
+ |0CThis allows you to deposit gold into the village vault.  This gold can be
+ used to help the town grow.  It is a good idea to deposit into the vault
+ regularly if you wish to stay in power.  Other clans will see you are doing
+ this is be more loyal.
+
+^END
+
+^Withdraw from Vault
+ |0CThis option allows you to withdraw gold from the town's vault.  Be careful
+ when withdrawing gold.  Doing it too often or in excess *will* be noticed
+ by other clans.  This may cause them to rebel and overthrow you.
+
+^END
+
+^Make Announcement
+ |0CThis option allows you to make an announcement which will be seen in the
+ daily news.
+
+^END
+
+^Smithy
+ |0CBy upgrading the weapon shop, better stats will be produced when items
+ such as weapons, shields, and armor are bought.  It is very important to
+ have a weapon shop in an InterBBS game!
+
+^END
+
+^Government System
+ |0CThe government system used decides how the ruler is chosen each day.  If
+ a Dictatorial system is used, the current ruler will continue to reign
+ regardless of votes.  (Voting is actually disabled.)  If a Democratic system
+ is used, voting decides who the ruler will be each day.
+
+^END
+
+^Show Empire Stats
+ |0CUse this feature to toggle whether or not users can see the village's
+ empire stats.  This feature is extremely useful for a Dictator system of
+ government as it helps keep the enemy in the dark.
+
+^END
+
+^Conscription Rate
+ |0CThe conscription rate dictates how much of a clan's followers gained will be
+ taken into the town's empire.
+
+^END
+
+^Voting Booth
+ |0CThe voting booth allows you to vote for the clan which you think will rule
+ best.  At the end of the day, a new ruler is chosen from the top votes.  Of
+ course, if the town is under dictatorial rule, voting is disabled and the
+ current ruler will continue to reign unless ousted through an empire war.
+^END
+
+^Pawn Shop
+ |0CA Pawn Shop is required for users to buy and sell used goods.  A higher
+ level of pawn shop allows the shop to keep more items in stock each day.
+
+^END
+
+^Wizard's Shop
+ |0CA Wizard's Shop provides the town with magical items.  A higher level of
+ Wizard's Shop allows the wizard to sell a wider variety of goods.
+
+^END
diff --git a/src/doors/clans-devkit/SCHEMES.TXT b/src/doors/clans-devkit/SCHEMES.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..14fe97292bac3796634e7d800dfe9d00fb174ac9
--- /dev/null
+++ b/src/doors/clans-devkit/SCHEMES.TXT
@@ -0,0 +1,12 @@
+Boring 2 5 2 2 3 7 11 1 9 1 2 2 10 2 5 2 10 15 2 0 0 2 10
+Pigeon_Eye1 1 9 7 1 15 7 7 1 9 1 2 2 10 2 5 2 10 15 7 0 0 2 10
+Pigeon_Eye2 1 9 7 1 15 7 7 1 9 1 1 7 15 3 4 2 10 15 7 0 0 2 10
+Red_Stuff 4, 12, 2, 4, 4, 7, 12, 3, 11, 8,   4, 3, 11,3,4,   2,10,15, 12,0,0,   2, 7
+Red_Hot 6 12 4 5 5 7 13 1 9 1 5 6 14 4 5 4 12 15 2 0 0 8 4
+The_Blues 1 9 3 1 11 7 3 2 10 2 5 3 9 5 13 1 9 15 7 0 0 8 4
+Cyan+Green 2 3 2 8 8 8 7 7 15 8 8 2 3 4 12 1 9 15 2 0 0 8 7
+Bright_Stuff 8 7 15 9 3 7 11 6 14 3 9 3 11 3 4 1 9 11 7 0 0 4 7
+Default 2 3 2 6 6 7 3 3 5 8 6 2 3 4 12 6 4 2 2 0 0 6 3
+CompetitionDoors 14 15 11 10 8 3 9 4 14 12 9 14 12 3 12 7 9 15 10 0 0 9 15
+Ayukawa 6 14 7 5 13 7 5 8 3 8 5 14 6 4 12 4 12 3 6 0 0 1 9
+Lush 4 12 7 8 12 14 7 4 12 4 8 7 12 9 13 7 5 13 7 0 0 8 7
diff --git a/src/doors/clans-devkit/SECRET.EVT b/src/doors/clans-devkit/SECRET.EVT
new file mode 100644
index 0000000000000000000000000000000000000000..da841fc14a54c3bb7f8a359519efa8ea10c0827b
--- /dev/null
+++ b/src/doors/clans-devkit/SECRET.EVT
@@ -0,0 +1,689 @@
+# The Youth Hostel
+
+>> Comment Begins
+
+What you must do:
+
+- at the bus stop, get on bus #26
+- at hostel, you meet a girl who loves cakes
+- go to the kitchen, talk to guy there, says he will not give you a cake
+  without a meal ticket
+- in the bath, you find one (must take a bath first) -- floating in the water
+  --> can't get in water before washing self ;)
+- get cake
+- go to girl who is in the lounge watching tv
+- she thanks you --> the end for now
+
+flags:
+        T1 = did you talk to the girl yet?
+        T2 = Get the meal ticket yet?
+        T3 = Got the cake yet?
+        T4 = Give her the cake yet?
+        T5 = Got coins?
+        T6 = Went to reception desk and got key?
+        T7 = Got towel?
+        T8 = Washed up FIRST?
+        T9 = Got bus pass?
+        T10= Got KOR manga yet?
+
+>> Comment Ends
+
+Event 2
+Text "%C
+Text "|12 Utano Youth Hostel
+Text
+Text "|07It is raining outside.  You sit on the bus and watch the outside world
+Text "pass you by.  Soon you hear the words "Utano Yusu Hosteru" uttered by the
+Text "bus.  You pay for the ride and get off with your backpack on.
+Text
+pause
+Jump 2.BusStop
+END
+
+    Result 2.BusStop
+    Text
+    Text "|12The Bus Stop
+    Text
+    Text "|07You are standing at the bus stop on the left side of the road.  (They DO
+    Text "drive on the other side of the road, you know.  You watch the traffic go
+    Text "by as the rain pitter patters on the road.  It is pouring.  To the north
+    Text "you can see a sign that points up an alley towards the hostel.
+    Text
+    {T4}Text "The [G]irl is here and so is the [B]us.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N
+    Text
+    Prompt "`02Where to? `0A
+    {T4}Option G 2.BusStop.Girl
+    {T4}Option B 2.BusStop.Bus
+    Option N 2.Alley
+    Option Q Stop
+    END
+
+        Result 2.BusStop.Girl
+        Text
+        Text "|15"Let's go to the shopping arcade." |07she says.
+        pause
+        Jump 2.BusStop
+        End
+
+        Result 2.BusStop.Bus
+        {!T9}Text "You're about to get on the bus when you realize you don't have your bus
+        {!T9}Text "pass on you!  Realizing you don't want to pay, you decide to get off the
+        {!T9}Text "bus and not take it till you find your bus pass.
+        {!T9}Jump 2.BusStop
+        Text
+        Text "|07You hop on the bus and head to the shopping arcade.  It's still raining,
+        Text "but the sun shines in this girl's eyes.
+        pause
+        End
+
+    Result 2.Alley
+    Text
+    Text "|12The Alley
+    Text
+    Text "|07You are walking along an alley that leads north and south.  To the
+    Text "north you can see the road stretches on for a bit more and then abruptly
+    Text "changes direction.  To the west is the entrance to the Utano Youth Hostel.
+    Text "To the south you see the alley leads to the bus stop where you got off.
+    Text
+    Text "There is a [P]hone here.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F S W
+    Text
+    Prompt "`02Where to? `0A
+    Option P 2.Alley.Phone
+    Option S 2.BusStop
+    Option W 2.Entrance
+    Option Q Stop
+    END
+
+        Result 2.Alley.Phone
+        Text "|07You pick up the phone and call home.  Ahh, home sweet home.  You start
+        Text "having thoughts about what it's like to sleep in your own bed and how
+        Text "it is already late evening there...  Soon the time runs out on your phone card
+        Text "and you realize you're still in a far away land.
+        Text
+        pause
+        Jump 2.Alley
+        END
+
+    Result 2.Entrance
+    Text
+    Text "|12The Entrance
+    Text
+    Text "|07You are standing at the entrance to the youth hostel.  You are inside.
+    Text "To the north you see a small lounge with a TV.  Some hostellers are watching
+    Text "it but you can't see what's showing.  To the West you see the
+    Text "reception desk.  To the south is the dining area.  To the east is the alley.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N S E W
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option E 2.Alley
+    Option W 2.Reception
+    Option N 2.Lounge
+    Option S 2.Dining.1
+    END
+    
+    Result 2.Reception
+    Text
+    Text "|12The Reception Desk
+    Text
+    Text "|07You are at the Reception Desk.  To the south is the laundry room, to the
+    Text "east is the entrance and to the north is the lounge.
+    {!T6}Text
+    {!T6}Text "A guy in his 20s sees you and looks over your papers and eventually hands you
+    {!T6}Text "a map and tells you you are in room 18 upstairs.  You thank him.
+    {!T6}SetFlag T6
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N S E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option E 2.Entrance
+    Option N 2.Lounge
+    Option S 2.Laundry
+    END
+
+    Result 2.Laundry
+    Text
+    Text "|12The Laundry Room
+    Text
+    Text "|07You're in the laundry room.  To the north is the reception desk.
+    Text
+    {!T7}Text "You see a [T]owel on the floor.
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    {!T7}Option T 2.Laundry.Towel
+    Option N 2.Reception
+    END
+
+        Result 2.Laundry.Towel
+        Text "
+        Text "You pick up the towel and stick the whole thing in your back pocket.
+        SetFlag T7
+        pause
+        Jump 2.Laundry
+        END
+    
+    Result 2.Lounge
+    Text
+    Text "|12The Lounge
+    Text
+    Text "|07You see many [P]eople watching [T]V in the lounge.  To the south is the
+    Text "entrance to the hostel.  To the west you see a hallway.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F S W
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option P 2.Lounge.People
+    Option W 2.1FHall1
+    Option S 2.Entrance
+    Option T 2.Lounge.TV
+    END
+
+        Result 2.Lounge.TV
+        Text
+        Text "A baseball game is on.  You'd change the channel, but the fat guy watching
+        Text "the game is bigger than you (way bigger).
+        pause
+        Jump 2.Lounge
+        Text
+
+        Result 2.Lounge.People
+        Text
+        Text "You see a fat white guy sitting with a can of Pocari Sweat in his hand.
+        Text "There is also a couple Japanese teenagers discussing something and not paying
+        Text "attention to the TV.
+        Text
+
+        {T1&!T4}Text "The girl is still here and continues to stare out the window.
+        {T1&T4}Text "The girl is long gone.  Where did she go again?
+
+        {!T1&!T3}Text "You see a cute Japanese girl sitting down just staring out the window,
+        {!T1&!T3}Text "lost in thought.  She speaks (in English):  "I wish I had a cake."
+        {!T1&!T3}SetFlag T1
+
+        {T1&T3&!T4}Text
+        {T1&T3&!T4}Text "Here's a cake. you say.  She looks up and sees you holding a cake in
+        {T1&T3&!T4}Text "your hand.  Thanks a lot!  She quickly takes the cake and makes short
+        {T1&T3&!T4}Text "work of it.  Wanna go somewhere? she asks.  You say Ok.  I'll meet
+        {T1&T3&!T4}Text "you at the bus stop she says.
+        {T1&T3&!T4}SetFlag T4
+        pause
+        Jump 2.Lounge
+        END
+
+    Result 2.1FHall1
+    Text
+    Text "|12The Downstairs Hallway
+    Text
+    Text "|07You are in the hallway.  To the west is more hallway and to the north are some
+    Text "stairs leading up.  To the east is the lounge.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N W E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option N 2.Stairs
+    Option W 2.1FHall2
+    Option E 2.Lounge
+    END
+
+    Result 2.Stairs
+    {!T6}Text
+    {!T6}Text "I'm sure it would be best if you went to the reception desk FIRST!
+    {!T6}pause
+    {!T6}Jump 2.1FHall1
+    Text
+    Text "|12The Stairs
+    Text
+    Text "|07You are standing on some stairs that lead up to the second floor and down
+    Text "to the first floor.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F U D
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option D 2.1FHall1
+    Option U 2.2FHall1
+    END
+
+    Result 2.2FHall1
+    Text
+    Text "|12The Upstairs Hallway
+    Text
+    Text "|07You are on the second floor of the hostel.  To the east you can see
+    Text "a balcony.  To the north are flights of stairs leading down.  To the west
+    Text "is more hallway.  You see a [P]hone here.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option N 2.Stairs
+    Option E 2.Balcony
+    Option P 2.2FHall1.Phone
+    END
+
+        Result 2.2FHall1.Phone
+        Text
+        Text "|07You pick up the phone but it doesn't accept long distance calls so you put
+        Text "down the receiver.
+        pause
+        Jump 2.2FHall1
+        End
+
+        Result 2.Balcony
+        Text "|12The Balcony
+        Text
+        Text "|07You slip on a pair of balcony slippers and walk onto the balcony.
+        Text "It would be enjoyable if it wasn't raining.
+        Text
+        {!T10}Text "|07You see a copy of [K]OR manga volume #10.
+        {!T10}Text
+        Text
+        Text "`02[`0AQ=Quit`02] `03Directions:`0F W
+        Text
+        Prompt "`02Where to? `0A
+        Option Q Stop
+        Option W 2.2FHall1
+        {!T10}Option K 2.Balcony.KOR
+        END
+
+        Result 2.Balcony.KOR
+        Text "|07You pick up the KOR manga (v10).  Even though it's soaking wet, it's
+        Text "still readable.  You flip through it a bit before sticking it into
+        Text "your back pocket (it's a HUGE pocket).
+        SetFlag T10
+        pause
+        Jump 2.Balcony
+        END
+
+    Result 2.1FHall2
+    Text
+    Text "|12The Downstairs Hallway
+    Text
+    Text "|07You are in the hallway.  To the west is the female sleeping area.  To the
+    Text "north is the men's bath and to the east is some more hallway.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N W E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option N 2.Bath
+    Option W 2.Women
+    Option E 2.1FHall1
+    END
+
+        Result 2.Women
+        Text
+        Text "Oh, I should've mentioned it before.  You play a male in this "game" and
+        Text "yer not allowed in the female area.  Tough (pervert)!
+        pause
+        Jump 2.1FHall2
+        END
+
+    Result 2.Bath
+    ClearFlag T8
+    Text
+    Text "|12The Changing Room
+    Text
+    Text "|07You are in the changing room of the bath.  Basically, you strip here and go
+    Text "bathe in the bathing area.  Oh yeah, bring a towel.
+    Text
+    Text "To the south is the hallway, to the east is the bathing area.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F S E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option S 2.1FHall2
+    {T7}Option E 2.Bath.Wash
+    {!T7}Option E 2.Bath.Wash.NoTowel
+    END
+
+        Result 2.Bath.Wash.NoTowel
+        Text
+        Text "You should probably get a towel first to cover yourself up a bit.
+        pause
+        Jump 2.Bath
+        END
+
+        Result 2.Bath.Wash
+        Text
+        Text "|12The Bathing Area
+        Text
+        Text "|07You're in the bathing area and there are a few other nude men so try not to
+        Text "look down.  To the west is the changing room.  You see a giant [H]ot tub and
+        Text "individual washing [F]acilities (basically, a small stool, some soap, a mirror,
+        Text "a shower-head, and a basin.
+        Text
+        Text "`02[`0AQ=Quit`02] `03Directions:`0F W
+        Text
+        Prompt "`02Where to? `0A
+        Option Q Stop
+        Option W 2.Bath
+        Option H 2.Tub
+        Option F 2.WashUp
+        END
+
+        Result 2.Tub
+        Text
+        {!T8}Text "You are about to jump into the steamy hot tub when somebody stops you.
+        {!T8}Text "It seems it is customary to wash up BEFORE going into the tub.  So wash up!
+        {T8}Text "You jump into the tub and relax for a few minutes.  Ahh, it's nice and hot.
+        {T8&!T2}Text
+        {T8&!T2}Text "You suddenly see a plastic object floating in the tub.  It's a
+        {T8&!T2}Text "meal ticket!  You quickly snatch it up and put it in your uh...
+        {T8&!T2}Text "pocket... yeah, that's it....
+        {T8&!T2}SetFlag T2
+        pause
+        Jump 2.Bath.Wash
+        END
+
+        Result 2.WashUp
+        Text
+        Text "You sit down on a stool and proceed to wash yourself (of course, you DID
+        Text "remove your towel, right?).  After washing up thoroughly, you feel refreshed!
+        SetFlag T8
+        pause
+        Jump 2.Bath.Wash
+        END
+
+
+    Result 2.Dining.1
+    Text
+    Text "The Dining Area
+    Text
+    Text "|07You are standing in the dining area for the youth hostel.  You can see
+    Text "some [V]ending machines selling beverages of all sorts.  To the east you
+    Text "see a self-serve kitchen.  To the south is more of the dining area.  To the
+    Text "north is the entrance to the hostel.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N S E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option N 2.Entrance
+    Option S 2.Dining.2
+    Option E 2.Kitchen
+    Option V 2.Dining.1.Vending
+    END
+
+        Result 2.Dining.1.Vending
+        Text
+        Text "|07You insert a 110 yen into the machine and get yourself a nice cold
+        Text "glass of Pocari Sweat.  Ahh, refreshing.
+        Text
+        Pause
+        Jump 2.Dining.1
+        END
+
+    Result 2.Kitchen
+    Text
+    Text "The Kitchen
+    Text
+    Text "|07The kitchen is fairly small.  There's a fridge, a stove, and a bunch of
+    Text "other things you'd normally find in a kitchen.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F W
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option W 2.Dining.1
+    END
+
+    Result 2.Dining.2
+    Text
+    Text "The Dining Area
+    Text
+    Text "|07You are standing in the southern portion of the dining area.  There is
+    Text "a [P]iano here.  To the east is the w[I]ndow leading to the kitchen (not
+    Text "the same as the self-serve kitchen).  To the north is more dining area.
+    Text "To the west you can see a garden
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F N W
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option N 2.Dining.1
+    Option P 2.Dining.2.Piano
+    Option I 2.Dining.2.Window
+    Option W 2.Garden
+    END
+
+        Result 2.Dining.2.Piano
+        Text
+        Text "The Piano
+        Text
+        Text "|07You sit down and begin to play the piano.  You play whatever it is on
+        Text "your mind.  Soon the fun is over and you get up.
+        pause
+        Jump 2.Dining.2
+        END
+
+        Result 2.Dining.2.Window
+        Text
+        Text "The Window
+        Text
+        Text "|07You look inside the window and see a few people busily preparing
+        Text "a meal...
+        Text
+        {T1&!T3&!T2}Text "YOU SEE A CAKE!
+        {T1&!T3&!T2}Text
+        {T1&!T3&!T2}Text "You reach out to take it but your hand is quickly slapped by a large
+        {T1&!T3&!T2}Text "man with hairy arms and many tatoos.  NO TICKET, NO CAKE!
+
+        {T3}Text "No more cakes for you.  You've already had yours.
+
+        {T1&T2&!T3}Text
+        {T1&T2&!T3}Text "Can I have a cake, please? you ask.  You give your meal ticket and the large
+        {T1&T2&!T3}Text "man with hairy arms and many tatoos gives you a whole cake!
+        {T1&T2&!T3}SetFlag T3
+        pause
+        Jump 2.Dining.2
+        END
+
+    Result 2.Garden
+    Text
+    Text "The Garden
+    Text
+    Text "|07You are in the garden.  How relaxing.
+    Text
+    Text "`02[`0AQ=Quit`02] `03Directions:`0F E
+    Text
+    Prompt "`02Where to? `0A
+    Option Q Stop
+    Option E 2.Dining.2
+    END
+
+
+
+
+# ----------------------------------------------------------------------------
+
+Event 3
+Text "It's easy to sit there and say you'd like to have more money.
+Text " And I guess that's what I like about it.  It's easy.  Just
+Text "sitting there, rocking back and forth, wanting that money.
+Text
+Text "`03Secret coming soon!
+pause
+END
+
+Event 4
+Text "`07I've got a magic wand to see her in the morning.
+Text "Crystal eyes to read between the lines.
+Text
+pause
+END
+
+Event 5
+Text "`0A
+Text "Whether they live in an igloo or a grass shack or a mud hut,
+Text "people around the world all want the same thing: a better
+Text "house.
+pause
+Jump ProjectX
+END
+
+# ----------------------------------------------------------------------------
+Result ProjectX
+    Text "%C
+    Text "|08LOADING THE RALM...
+    Pause
+
+    display "/px/Title
+    pause
+    display "/px/Pg
+    pause
+    Jump PX.Loop
+End
+
+Result PX.Loop
+Text "%C
+Text
+Text
+Text
+Text "                          |15Caveman Technologies Presents
+Text
+Text "                              |14Project-X v99.80Special
+Text "                             |04A Game by |12Al Shunsler
+Text "                               |04copyrigt (|06c|04) |121996
+Text
+Text "                   |05This game has been running for |13several |05days
+Text "                 |05Players are deleted after |1314 |05days of inactivity
+Text "                 |13"Bringing you yesterday's technology....today!
+Text
+Text "                            |04UNREGISTERED:  |24NOT WINNABLE! (don't bother!)|16
+Text
+Text "                           |06(|05E|06) |12Enter this Realm of Mystery
+Text "                           |06(|05L|06) |12List Active Players
+Text "                           |06(|05N|06) |12News
+Text "                           |06(|05R|06) |12Registration Info
+Text "                           |06(|05Q|06) |12Quit Game
+Text
+Prompt "                             |06Enter Choice Now : |12
+Option S PX.Stupid
+Option N PX.News
+Option E PX.Enter
+Option Q PX.Quit
+Option L PX.List
+Option ~ PX.Secrets
+Option R PX.RegInfo
+
+Result PX.Stupid
+  Text
+  Text "|03You pressed |11S|03.  S is for STUPID!
+  Text
+  pause
+  Text
+  Text "|12New Year's Day:  |04A Story
+  pause
+  Text
+  Text "|06Once upon a time, there was a kid named Johnny.
+  pause
+  Text
+  Text "|12The End.
+  pause
+  Jump PX.Loop
+End
+
+Result PX.News
+  Text
+  Text "|03If you want news, go watch |11CNN|03!
+  pause
+  Text
+  Text "Ok, fine, here's the news:
+  pause
+  Display "/px/News
+  Jump PX.Loop
+End
+
+Result PX.Enter
+  Text "This is only a small sampling of Project-X.  To play the whole thing,
+  Text "download TXDS and then Project-X from the author's BBS.  (It is a door game
+  Text "parody for those of you who are slow and didn't catch on.)
+  pause
+  Text "%C
+End
+
+Result PX.Quit
+  Prompt "|04Are you really sure you wanna quit this wicked game? [No] : |04
+  Option N PX.NoQuit
+  Option ~ PX.NoQuit
+  Option Y NextLine
+
+  Prompt "|04You really, really want to quit?! [No] : |04
+  Option N PX.NoQuit
+  Option ~ PX.NoQuit
+  Option Y NextLine
+
+  Prompt "|04You're not serious, are you? [No] : |04
+  Option N PX.NoQuit
+  Option ~ PX.NoQuit
+  Option Y NextLine
+
+  Prompt "|12Ok, for the last time, do you want to quit or not!? [No] : |04
+  Option N PX.NoQuit
+  Option ~ PX.NoQuit
+  Option Y NextLine
+
+  Text "|14Sorry, I just can't let you do that.
+  pause
+  Jump PX.Loop
+End
+
+Result PX.List
+  display "/px/LIST
+  pause
+  Jump PX.Loop
+End
+
+Result PX.Secrets
+  Text
+  Text "You have pressed an invalid key.  Please press one that is valid.  A valid
+  Text "key is one of the keys in parentheses (( or )).  After pressing one of those
+  Text "keys down, the option will be activated.  When the option is activated, please
+  Text "release your finger from the key or else a problem may arise.  Thank you for
+  Text "taking the time to read this message.
+  pause
+  Jump PX.Loop
+End
+
+Result PX.NoQuit
+  Jump PX.Loop
+End
+
+Result PX.RegInfo
+ Text "|15REGISTRATION INFO for PROJECT-X!!
+ Text
+ Text "|03Thank you for reading this section.  Registration is only $20.
+ Text "This is easy money to get.  If you need $20 right now, you could try
+ Text "this:  Go out on the street with an old hat.  Grab a harmonica.
+ Text "Sit down on the sidewalk.  Place the hat right in front of you.  Play
+ Text "the harp, er, harmonica and wait.  I'm sure you'll soon rack up the
+ Text "cash!  |08(Note:  Author does not suggest actually doing this.)
+ Text
+ Text "|09Once you get the money together, send the money to the author of
+ Text "TXDS and tell him it's a registration for TXDS!  He'll appreciate
+ Text "it.
+ Text
+
+ Text "|12Special deal (for 1996-1998 only!)
+ Text
+ Text "|13We at Caveman Technologies are offering this special deal.  If you
+ Text "and another sysop register together (and included the reg forms in the
+ Text "same envelope) the registration fee will only be $20 EACH!  If a third
+ Text "sysop gets in on the deal, add on a measly $20 and you've got yourself
+ Text "a deal!  You get a savings of at least 32 cents for postage!!!  I urge
+ Text "you to get in on this deal before it's over!!!
+ pause
+ Jump PX.Loop
+End
diff --git a/src/doors/clans-devkit/SPELLS.HLP b/src/doors/clans-devkit/SPELLS.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..402b19db94a7908ffb156111aaf985c0b6f99533
--- /dev/null
+++ b/src/doors/clans-devkit/SPELLS.HLP
@@ -0,0 +1,118 @@
+^Partial Heal
+ |0CThis spell will cause the recipient to regain some lost hitpoints incurred
+ in battle.
+^END
+
+^Heal
+ |0CThis spell causes the recipient to regain much of his lost hitpoints.
+^END
+
+^Slow
+ |0CThis causes the victim of the spell to move very slowly causing him to
+ have a reduced agility.
+^END
+
+^Strength
+ |0CThe recipient of this spell will have increased strength for a few rounds.
+^END
+
+^Ropes
+ |0CThis skill allows one to quickly tie up an enemy in ropes.  The enemy
+ will eventually free himself from the ropes but it will take a few rounds to
+ do so.
+^END
+
+^Raise Undead
+ |0CA difficult spell to cast properly, this will cause undead beings to be
+ summoned which will fight alongside your clansmen.
+^END
+
+^Banish Undead
+ |0CIf one is being harassed by the undead whilst in combat, this spell
+ will banish them from the world of the living.
+^END
+
+^Mystic Fireball
+ |0CA burst of flames will emanate from the caster's hands and land a hit on
+ its victim.
+^END
+
+^Dragon's Uppercut
+ |0CMastered by martial artists, this special skill allows the attacker to do
+ great damage with a rising uppercut.
+^END
+
+^Summon Dead Warrior
+ |0CWhen this spell is cast, an undead warrior will come to the aid of the
+ party.
+^END
+
+^Death and Decay
+ |0CThis evil spell will cause great damage to the |11entire|0C enemy clan
+ at once!
+^END
+
+^Mystic Bond
+ |0CThis spell will quickly bind its victim in an invisible rope for a few rounds.
+ The victim will be unable to do anything until it wears off.
+^END
+
+^Holy Heal
+ |0CThis somewhat weak spell will cause its recipient to regain some lost
+ hit points.
+^END
+
+^Lightning Bolt
+ |0CThis powerful spell causes a great lightning bolt to appear out of thin
+ air and can cause great damage on an unsuspecting foe.
+^END
+
+^Backstab
+ |0CThis special skill allows one to quickly sneak up behind a foe and stab
+ him with a small dagger hidden in one's pocket.
+^END
+
+^Spells
+ |14Skills/Spells
+
+ |02This option will allow you to pick a special skill or a spell to be used by
+ the current character you are controlling.
+^END
+
+^Bloodlust
+ |0CThis spell will cause the recipient to fight with great fury and strength
+ as he has never fought before.
+^END
+
+^Fear
+ |0CThis spell instills fear in the enemy and causes him to fight with reduced
+ strength and agility.
+^END
+
+^Heavy Blow
+ |0CThis special skill allows the attacker to do great damage on its victim.
+^END
+
+^Light Blow
+ |0CThis special skill allows the attacker to do a bit of damage to its victim.
+^END
+
+^Hurricane Kick
+ |0CThis special skill will cause the warrior to do a blazingly fast kick which
+ will do light damage to the enemy.
+^END
+
+^Blind Eye
+ |0CThis special skill will cause the victim to be blinded for a few rounds.
+ Being blinded, the victim is unable to see his attackers and will have
+ reduced agility and dexterity.
+^END
+
+^Divine Warrior
+ |0CThis spell will call upon an angelic warrior to fight alongside the clan.
+^END
+
+^Rain of Terror
+ |0CThis powerful spell will cause a fireballs to rain down on the enemy,
+ doing much damage on the whole clan!
+^END
diff --git a/src/doors/clans-devkit/SPELLS.TXT b/src/doors/clans-devkit/SPELLS.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..785dfc9c6ad13da928e1405ca03ee393e7712613
--- /dev/null
+++ b/src/doors/clans-devkit/SPELLS.TXT
@@ -0,0 +1,275 @@
+# spells file for The Clans
+
+# No "target" specified means target assumed, otherwise use "Notarget" if no
+# target for spell is required -- quite rare
+
+# 1
+Name		Partial Heal
+Flag		Heal
+Friendly
+Value		10
+Level		0
+SP              8
+HealStr         |02� |10%SS casts |15Partial Heal |10on |15%SD.%L  |10%SD |02regains |14%SV HP.
+
+# 2
+Name		Heal
+Flag		Heal
+Friendly
+Value		14
+Level		0
+SP		13
+HealStr         |02� |10%SS cast |15Heal on |15%SD.%L  |10%SD |02regains |14%SV HP.
+
+# 3
+Name		Slow
+Flag		Modify
+Agility 	-2
+Level           3
+ModifyStr	|02� |10%SS casts slow on %SD.  Agility is reduced!
+WearoffStr	|02� |10The slow spell has worn off %SD!
+
+# 4
+Name		Strength
+Friendly
+SP              6
+Energy		30
+Flag		Modify
+Strength	+5
+Level           5
+ModifyStr	|02� |10%SS casts Strength on |15%SD!
+WearoffStr	|02� |10%SD's super strength wears off!%L
+
+# 5
+Name		Ropes
+SP		9
+Energy          35
+Flag		Incapacitate
+Level           3
+ModifyStr	|02� |10%SS ties up %SD in ropes!
+WearoffStr	|02� |10%SD breaks free from the ropes!%L
+StatusStr	|02� |10%SD is still tied up!%L
+StrengthCanReduce
+
+# 6
+Name		Raise Undead
+SP		13
+Flag		RaiseUndead
+Value		1
+Level           5
+OtherStr	|02� |10%SS casts Raise Undead!
+UndeadName	Undead
+NoTarget
+
+# 7
+Name		Banish Undead
+SP		9
+Flag		BanishUndead
+Level           5
+OtherStr	|02� |10%SS casts Banish Undead!
+NoTarget
+
+# 8
+Name		Mystic Fireball
+SP		4
+Flag		Damage
+Value		9
+Level           6
+DamageStr	|02� |10%SS shoots a fireball at %SD.%L    %SD loses %SV HP.
+
+# 9
+Name		Dragon's Uppercut
+SP		6
+Flag		Damage
+Value		12
+Level           8
+DamageStr	|02� |10%SS uppercuts %SD.%L	  %SD loses %SV HP.
+
+# 10
+Name		Summon Dead Warrior
+SP		7
+Flag		RaiseUndead
+NoTarget
+UndeadName	Mystic Warrior
+Value		1
+Level		5
+OtherStr	|02� |10%SS summons an undead Mystic Warrior!
+Agility 	8
+Dexterity	6
+Strength	5
+
+# 11
+Name		Heavy Blow
+SP		6
+Flag		Damage
+Value           10
+Level           9
+DamageStr	|02� |10%SS delivers a heavy blow to %SD.%L	 %SD loses %SV HP.
+
+# 12
+Name		Death and Decay
+SP              7
+Flag		Damage
+Value           3
+Level           9
+DamageStr	|02� |10%SS casts death and decay on %SD!%L	 %SD loses %SV HP!
+MultiAffect
+NoTarget
+
+# 13
+Name		Mystic Bond
+SP		12
+Energy          25
+Flag		Incapacitate
+Level           4
+ModifyStr	|02� |10%SS casts Mystic Bond on %SD!%L    %SD is bound!
+WearoffStr	|02� |10Mystic Bond wears off %SD.%L
+StatusStr	|02� |10%SD is still bounded!
+
+# 14
+Name		Holy Heal
+Flag		Heal
+Friendly
+Value           4
+Level		0
+SP              7
+HealStr 	|02� |10%SS casts Holy Heal on %SD.  %SD regains %SV HP.
+
+# 15
+Name		Lightning Bolt
+SP		15
+Flag		Damage
+Value		25
+Level           8
+DamageStr	|02� |10%SS casts Lightning Bolt on %SD.%L	%SD loses %SV HP.
+
+# 16
+Name		Backstab
+SP		9
+Flag		Damage
+Value		17
+Level           9
+DamageStr	|02� |10%SS stabs %SD in the back!%L	  %SD loses %SV HP.
+
+# 17
+Name		FireBreath
+SP		9
+Flag		Damage
+Value           10
+Level           15
+DamageStr	|02� |10%SS breathes fire.%L	  %SD loses %SV HP.
+MultiAffect
+NoTarget
+
+# 18
+Name		Bloodlust
+Friendly
+SP		7
+Energy		30
+Flag		Modify
+Strength	+10
+Level		6
+ModifyStr	|02� |10%SS casts bloodlust on |15%SD!
+WearoffStr	|02� |10%SD's bloodlust wears off!%L
+
+# 19
+Name		Fear
+SP		9
+Energy		30
+Flag		Modify
+Strength	-3
+Agility 	-2
+Level		6
+ModifyStr	|02� |10%SS instills fear on |15%SD!
+WearoffStr      |02� |10%SD is no longer afraid!
+
+# 20
+Name		Light Blow
+SP		4
+Flag		Damage
+Value		13
+Level           3
+DamageStr	|02� |10%SS delivers a light blow to %SD.%L	 %SD loses %SV HP.
+
+# 21
+Name		Hurricane Kick
+SP		4
+Flag		Damage
+Value		10
+Level           5
+DamageStr	|02� |10%SS hurricane kicks %SD.%L	%SD loses %SV HP.
+
+# 22
+Name		Divine Warrior
+SP		8
+Flag		RaiseUndead
+NoTarget
+UndeadName	Divine Warrior
+Value		1
+Level		5
+OtherStr	|02� |10%SS summons a Divine Warrior!
+Agility 	8
+Dexterity	6
+Strength	14
+
+# 23
+Name		Blind Eye
+SP		6
+Energy		20
+Flag		Modify
+Dexterity	-3
+Agility 	-6
+Level           5
+ModifyStr	|02� |10%SS uses Blind Eye on |15%SD!
+WearoffStr      |02� |10%SD is no longer blinded.
+StatusStr	|02� |10%SD is still blinded!%L
+
+# 24
+Name            FireBreath
+SP		9
+Flag		Damage
+Value           6
+Level           15
+DamageStr	|02� |10%SS breathes fire.%L	  %SD loses %SV HP.
+MultiAffect
+NoTarget
+
+# 25
+Name            Rain of Terror
+SP              14
+Flag		Damage
+Value           4
+Level           12
+DamageStr       |02� |10%SS's Rain of Terror causes %SV damage on %SD!
+MultiAffect
+NoTarget
+
+# 26
+Name            Summon Khaos
+Flag		Damage
+Value           10
+Level           12
+DamageStr       |02� |10Khaos rains down fire on %SD.  %SV damage is done.
+MultiAffect
+NoTarget
+
+
+# 27
+Name            Summon Dragon
+Flag		RaiseUndead
+NoTarget
+UndeadName      Gold Dragon
+Value		1
+Level           9
+OtherStr        |02� |10%SS summons a Gold Dragon!
+Agility         12
+Dexterity       14
+Strength        16
+
+# 28
+Name            Ice Blast
+Flag		Damage
+Value           20
+Level           9
+DamageStr       |02� |10%SS shoots an Ice Blast at %SD.%L    %SD loses %SV HP.
+
diff --git a/src/doors/clans-devkit/STATS.HLP b/src/doors/clans-devkit/STATS.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..67ced49f8f3e379f1a98c1a7e96cb704d90b4ef4
--- /dev/null
+++ b/src/doors/clans-devkit/STATS.HLP
@@ -0,0 +1,56 @@
+^SP
+ |0CSkill Points are required for casting spells or using skills.  These are
+ regenerated during each round of combat and fully regenerated at the start
+ of each day.
+^END
+
+^HP
+ |0CHitpoints are the energy used by your characters.  The more the better as
+ they can survive strikes much longer.
+^END
+
+^Attributes
+ |0CAttributes are the characteristics of each character.  These make a character
+ what he or she is (i.e. a strong fighter or a magic-user).
+^END
+
+^Dexterity
+ |0CThe higher dexterity a character has, the better chances he or she will
+ strike an enemy.  A high dexterity is also desirable in the event that your
+ clan wishes to run away whilst in combat.  A low dexterity will prevent you
+ from running!
+^END
+
+^Agility
+ |0CThe higher agility a character has, the better his odds of attacking first
+ are.  In close combat, the first strike often decides the outcome.  A high
+ agility is also helpful in avoiding an enemy attack.
+^END
+
+^Strength
+ |0CRaw strength is desirable for not only attacking enemies but for using a
+ weapon.  Certain weapons require high strength to be wielded.  If the
+ character using the weapon does not have high strength, he will suffer in
+ other attributes such as dexterity.
+^END
+
+^Wisdom
+ |0CWisdom is needed mainly for magic-users or users of skills.  The higher
+ wisdom a character possesses, the more quickly he or she will regain skill
+ points.  When you are attacked by another clan (and you are not around to
+ control your characters) a high wisdom is helpful.  The higher wisdom a
+ character has, the better his chances of successful use of skills.
+^END
+
+^Charisma
+ |0CCharisma is currently only needed for speaking out for or against the ruler.
+ A high charisma will cause a larger amount of the population to notice than
+ a lower one.
+^END
+
+^Armor Strength
+ |0CArmor Strength is the amount of damage that is absorbed by the character
+ without the use of armor itself.  Obviously, this attribute is very
+ important.  A high armor strength will often prevent attacks from doing
+ any damage to the character.
+^END
diff --git a/src/doors/clans-devkit/STRATEGY.HLP b/src/doors/clans-devkit/STRATEGY.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..6d2a5e2c7d0cea85c123ef1811dc7c10d3213e73
--- /dev/null
+++ b/src/doors/clans-devkit/STRATEGY.HLP
@@ -0,0 +1,22 @@
+Strategy Help file for Clans
+
+^Gaining Power
+|0C If you wish to gain power as ruling clan of the village, you must get
+ support from other clans.  While it is possible to simply fight the current
+ ruling clan in a clan war to achieve ruling status, your clan's reign may
+ be short lived unless it has ties with other clans.
+
+ Be sure to form alliances with other clans.  This provides you with much
+ needed troops in clan wars.
+
+ Once in power, |0Bdo not make your supporters angry |0Cor they will break off
+ their alliances with you and rebel to overthrow you!  Do not let power go
+ to your head!
+^END
+
+^Starting Out
+|0C As a new player, you will not have sufficient troops to do battle in clan
+ wars yet.  So, the main focus should be building up your clan's stats.
+ Fight in the mines, but fight intelligently.  Be sure to spread around the
+ experience gained by your four clansmen.
+^END
diff --git a/src/doors/clans-devkit/STRINGS.TXT b/src/doors/clans-devkit/STRINGS.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..c7c812f5796cd0747614d094b4be494925e5fe69
--- /dev/null
+++ b/src/doors/clans-devkit/STRINGS.TXT
@@ -0,0 +1,1364 @@
+#------------------------------------------------------------------------------
+#
+# Language Data for The Clans
+#
+# To modify the language for The Clans, modify this file the way you wish then
+# compile it using the The Clans Language Compiler.  It used as follows:
+#
+# LangComp <filename>
+#
+# For example, to compile this file:
+#
+# LangComp strings
+#
+# **************************************************************
+# YOU MUST READ THE FOLLOWING BEFORE EDITING THIS FILE!!!!
+# **************************************************************
+#
+#
+# Lines MUST be in the following form
+#
+# xxxx <String>
+#
+# xxxx is the FOUR digit number which the string is referenced by.
+# <String> is the string that xxxx uses.  There must be a space after the xxxx.
+#
+# All blank lines and lines starting with a pound symbol (#) are comments and
+# not treated as strings.
+#
+# If any of these are left out, major errors could result.
+#
+# Here are other special codes which can be used here only:
+#
+# ^M            LineFeed (%LF)
+# ^N            Carriage Return (%\r)
+# ^H            Backspace (%\b)
+# ^[            Escape code (alt-27, %<)
+# ^G            Beep (same as Ctrl-G in DOS)
+# ^-            End line here.  (useful for editors which remove trailing
+#                                spaces)
+# ^^            caret symbol (^)
+#
+# It is suggested that these be used as much as possible since they are
+# convereted to the real DOS special codes and not the MCI codes that CLANS
+# uses.  This will save memory and improve the screen output performance as
+# well.
+#
+#------------------------------------------------------------------------------
+# Organization
+#------------------------------------------------------------------------------
+#
+# 0001-0100     Various strings
+#
+# 0050+         colors
+#
+# 0100-         Help functions
+#
+# 0300+         menus!
+#
+# 0200-         System specific
+# 0400-         Various Stats
+#
+#
+# 0800-         News messages
+#
+# 0900-1000     Various System strings
+#
+# 1000+, more junk!? :)
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# Various Strings
+#------------------------------------------------------------------------------
+
+0001 |S|0V<|0Wpaused|0V>|R
+0002 |S|0WMore? |0V[Y/n]|R
+0003 |04Couldn't find clan.^M%P
+0004 |04Aborted^M
+0005 |0GEnter option|0E> |0F
+0006 Yes
+0007 No
+0008 |15The village cannot afford it!^M%P
+0009 Quit^M
+
+0010 Agility
+0011 Dexterity
+0012 Strength
+0013 Wisdom
+0014 Armor Strength
+0015 Charisma
+
+;0020 |0K+--+-----------------------------------------------------------------------+--+^M
+0020 |0K屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+;0021 |0D+--+-----------------------------------------------------------------------+--+^M
+0021 |0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+0022 |12Invalid item!^M
+
+0030  |0MSkills/Spells Known^M |0D湍哪哪哪哪哪哪哪哪蚟M |0C
+0031 |0SDo you wish to join this game of clans?
+0032 ^M|10All right!  Let's begin by creating your clan!^M
+0033 ^M|0SWhat will you call your clan?^M|0E> |0F
+0034 |02Now, we will create clansmen for your clan.^M%P
+0035 |13Creating clansman %d of %d^M^M
+0036 |11Please choose a race for this character.^M
+0037 |11Please choose a class for this character.^M
+0038 |13Stats generated for this player^M
+0039 ^M|0SEnter the name of this member^M|0E> |0F
+0040 |10%s joins the clan.^M%%P
+
+0050 |00
+0051 |01
+0052 |02
+0053 |03
+0054 |04
+0055 |05
+0056 |06
+0057 |07
+0058 |08
+0059 |09
+0060 |10
+0061 |11
+0062 |12
+0063 |13
+0064 |14
+0065 |15
+0066 |16
+
+# buildmenu
+0073  |0A(|0BC|0A) |0CBuild a Church^M
+0074  |0A(|0BC|0A) |0CUpgrade Church to Level     |0B%d^M
+0075      |0CChurch Level                |0B%d^M
+0076  |0A(|0BT|0A) |0CBuild a Training Hall^M
+0077  |0A(|0BT|0A) |0CUpgrade T. Hall to Level    |0B%d^M
+0078      |0CTraining Hall Level         |0B%d^M
+0079  |0A(|0BH|0A) |0CRuling Help^M
+0080  |0A(|0BQ|0A) |0CQuit^M
+0081 |15The church is at its maximum level already.^M
+0082 |0CIt will cost |0B%ld GP |0Cto build a church.^MThe village has |0B%ld |0CGP.^M^M
+0083 |0SBuild the church?
+0084 |15The village now has a church!^M%P
+0085 |0CIt will cost %ld GP to upgrade the church to level %d.^MThe village has |0B%ld |0CGP.^M^M
+0086 |0SUpgrade the church?
+0087 |15The church has been upgraded to level %d!^M%%P
+0088 |15The training hall is at its maximum level already.^M
+0089 |0CIt will cost %ld GP to build a training hall.^MThe village has |0B%ld |0CGP.^M^M
+0090 |0SBuild the training hall?
+0091 |15The village now has a training hall!^M%P
+0092 |0SIt will cost %ld GP to upgrade the training hall to level %d.^MThe village has |0B%ld |0CGP.^M^M
+0093 |0SUpgrade the training hall?
+0094 |15The training hall has been upgraded to level %d!^M%%P
+
+0100 |12Help not found!^M
+0101 |12Help data not found!^M
+0102 |0K屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M|0C
+0103 |0CEnter option or |0B?|0C for list.  Enter blank line to quit.^M|0E> |0F
+0104 |14Display Options^M
+0105 ^M|12Invalid option!^M^M
+0106 END
+0107 PAUSE
+
+# hall options
+0108 Destroy Hall
+0109 Change Password
+0110 View Clan Stats
+0111 Quit
+0112 Redisplay Menu
+0113 Deposit Gold
+0114 Withdraw Gold
+0115 Chat with Others
+0116 Empire Menu
+0117 Donation Room
+0118 War Room
+
+# alliance crap
+0120 |10You already have 5 alliances.  You cannot create any more.^M%P
+0121 ^M|0SAre you sure you wish to invite that clan into this alliance?
+0123 |07That clan is already in the alliance!^M%P
+0124 |07That clan is already in too many alliances.^M%P
+0125 |10An alliance with that clan has been proposed.^M|02You may now send a letter to that clan.^MAborting the letter aborts the proposition for an alliance.^M
+0126 |07No alliances.^M%P
+0127 |07Alliances^M|08湍哪哪哪蚟M
+
+# town hall stuff
+0130  |0CDays of Reign                   |0B%d^M
+0131  |0CPopulation                      |0B%ld units^M
+0140  |0CVillage Vault                   |0B%-ld GP^M
+#0142  |0A(|0BE|0A) |0CEconomics Menu               |0A(|0BC|0A) |0CChange Colour Scheme^M
+#0143  |0A(|0BL|0A) |0CChange Flag                  |0A(|0BS|0A) |0CStructures^M
+#0144  |0A(|0BM|0A) |0CMake Announcement            |0A(|0BM|0A) |0CMake Announcement^M
+#0145  |0A(|0BP|0A) |0CPublic Discussion            |0A(|0BH|0A) |0CRuling Help^M
+#0146  |0A(|0BV|0A) |0CView Clan Stats              |0A(|0BG|0A) |0CHire Village Guards^M
+#0147  |0A(|0BF|0A) |0CFine a Clan                  |0A(|0BI|0A) |0CInvestigate Clan^M
+#0148  |0A(|0B!|0A) |0CAbdicate                     |0A(|0BQ|0A) |0CQuit^M
+0149
+0152 |0SEnter your announcement now.  It will go in the daily news.^M|0A> |0F
+0156 |0SAre you sure you wish to give up rule?
+0160  |0CCurrent Ruling Clan             |0BNone^M^M
+0161  |0CCurrent Ruling Clan             |0B%s |0A[ruled for %d day(s)]^M^M
+0162  |0CTax Rate                        |0B%d%%^M
+#0163  |0CInterest Rate                   |0B%d%%^M
+0164  |0CGoods and Services Tax          |0B%d%%^M
+0166  |0CVillage Vault                   |0B%ld GP^M
+0167 |0SHow much do you wish to deposit into the village vault?
+0168 |14%ld |07gold deposited into village vault.^M^M
+0169 ^M|07You've spoken out already today.^M%P
+0170 ^M|07There is currently no ruler.^M%P
+0171  |0A(|0BT|0A) |0CTax Rate                    |0B%d%%^M
+#0172  |0A(|0BI|0A) |0CInterest Rate               |0B%d%%^M
+0173  |0A(|0BG|0A) |0CGoods and Services Tax      |0B%d%%^M
+0174  |0A(|0BB|0A) |0CBuild a Bank^M
+# continued 185
+
+0175 |16|0SDo you wish to add on to the conversation?
+0176 ^M|0SPlease enter your comment now (enter up to 3 lines; blank line to stop).^M
+0177 |07There is currently no leader to speak of!^M%P
+
+# continued from 0174
+0185  |0A(|0BB|0A) |0CUpgrade Bank to Level       |0B%d^M
+0186      |0CBank Level                  |0B%d^M
+0187  |0A(|0BW|0A) |0CWithdraw from Vault^M |0A(|0BD|0A) |0CDeposit into Vault^M
+0188  |0A(|0BH|0A) |0CRuling Help^M
+0189  |0A(|0BQ|0A) |0CQuit^M
+0190 |07You may set the tax rate only once per day.^M%P
+0191 |0SPlease enter the tax rate (0 to 50)
+#0192 |07You need a bank first if you wish to set the interest rate.^M%P
+#0193 |07You may set the interest rate only once per day.^M%P
+#0194 |0SPlease enter the interest rate (0 to %d)
+0195 |07You may set the GST once per day.^M%P
+0196 |0SPlease enter the GST (0 to 50)
+
+# continued on 414
+
+0200 ^M^M|S|04-|12:< |07Sysop chat begins |12>:|04-|R^M
+0201 ^M|S|04-|12:< |07Sysop chat ends |12>:|04-|R^M
+0202 ^M^M^M^M
+
+# more options :)
+0205 Check Mail
+0206 Write Mail
+0207 Write Public Mail
+0208 Lastread Pointer
+0209 Quit
+0210 View Stats
+0211 Redisplay Menu
+0212 Global Post
+0213
+0214
+0215
+0216
+
+#0220 |01$$$$$$$$$$$$$$$$$$$$$$$$$P"'         |11,asssssssa.  s$$$$$$$$$$$b, |01Y$$$$$$$$$$$$
+#0221 $$$$$$$$$$$$$$$$$P"'      |03,ssd$$$$$b  |11 ^齓$$$$$$$$$$$$$$$$$$$$$$b,|01`$$$$$$$$$$$
+#0222 $$$$$P'          |03 .sssd$$$$$$$$$P' |03sd$$b.  |11~~^^`Y$$$$$$齘""^`�$$$$|01 $$$$$$$$$$$
+#0223 $$$$P |03.asS$$$$$$$$$$$$$$$$$$$P'|03,sd$$$$$$$$$$$$$b, |11`Y"'|15 sd$$$$b|11`Y$$|01 $$$$$$$$$$$
+#0224 $$$$$b, |03`^�$$$$$$$$$P�"^^^~  |03sd$$$$$$$$$$$$$$$$$$$b.|15 d$$$$$$$$;|11,~'|01,$$$$$$$$$$$
+#0225 $$$$$$$$$bsa,  |03`YP'|11,sd$$$$$$bs. |03 "^$$$$$$$$$$$$$$ |15$$$$$$$$$$;$ |01d$$$$$$$$$$$$
+#0226 $$$$$$$$$$$$$$bs, |11  `Y$$$$$$$P  |01sd$s.   |03`Y$$$$$$$P' |15`Y$$$$$$$P' |01d$$$$$$$$$$$$$
+#0227 $$$$$$$$$$$$$$$$$$bsss.     .sd$$$$$$$$s,           |15  `Y$$$P'   |01~~齓$$$$$$$$$$
+#0228 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$   |07 d$$$b, |15~ |07,d$$$$$  |01$$$$$$$$$$
+#0229 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  |07$$$$$$$$$$$$$$$$$$$ |01$$$$$$$$$$
+#0230 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  |07$$$$$$$$$$$$$$$$$$$$ |01$$$$$$$$$$
+
+#0220 |06-------------------------------------------------------------------------------
+#0221 |04$$$|07                |12$ $$$$$$$$$$$$$$.�'$$$$$$$$$$$$b."$$|07                   |04$$$$$
+#0222 $$$|07                 |12$$."    `$$$$$$$s$s"Y'|07      |12`Y$$$$"$|07                 |04$$$$$$
+#0223 $$$$s.|07              |12$$$|07,|15$" s.|12`a$$$$$$$$$|15.s$$" $s.  |12"s.$$|07                 |04$$$$$$
+#0224 $$$$$$s|07             |12$$$|15$$|02, |15$$ |12$$$$$$$$$$|15$$$$|02. |15$$$ $|07s |12$$$|07     |12$s|07          |04$$$$$$
+#0225 $$$$$$$$$s.|07         |12^$$|15$$|02: |15^' |12$$$$$$$$$$|07$|15$$$.|02s |15^' $$|07$ |12$$$   $$$|07          |04$$$$$$
+#0226 $$$$$$$$$$$$$|07        |12$$|07"|15$s|02`$'|12.$$$$$$$$$$s|15`S$$.|02$ss$|07" |12$$$$$  $$$$|07           |04$$$$$
+#0227 $$$$$$$$$$$$$$$$s.   |12$$$s|07^` |12.$$$S~$$$$$$$s.|07~^ |02`^~|12.s$$$$$   $$$$|07           |04$$$$$
+#0228 $$$$$$$$$$$$$$$$$$$  |12$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$   $$P'|07           |04$$$$$
+#0229 $$$$$$$$$$$$$$$$$$$$ |12$$$$$$$$$$$b.$$$$$$$$$$$$$$$$$$$$$   "'|07               |04$$$$
+#0230 |06-------------------------------------------------------------------------------^M              |14T     H     E         C     L     A     N     S^M
+
+#0220 |07 |04------------------------------------------------------------------------------
+#0221  圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹|14|20ansi by no.6 |04|16�
+#0222  踻12|20败|04|16圻哌  苘    咣踻07     |04苒圹圹圹圹哌   苘� 哌咣圹踻07     |04苘 哌咣圹圻�   苘� 哌圹�
+#0223  |12|20辈輡07|16     |04圹|07      |04圹    捋圹圹圹圹踻07     |04咣圹    咣圯    圹�    咣�    捋圯    圹
+#0224  |12|20氨|04|16�    迀12|20卑|04|16圮苘苒圹    捋圹圹圹圹踻07     |04苘軀07      |04圹    捋圹�    踻07     |04圹�    捋�
+#0225  圹|07     |12|20捋� 眧04|16圹|12|20皘04|16圹�    捋圹圹圹圹�    捋圹踻07     |04圹    捋圹�    圹苘   哌圮苒圹�
+#0226  踻12|20皘07|16     |12|20薏眧04|16圻哌哌圯    圹圮    咣�    捋圹�    捋�    捋圹|07     |04圹哌哌圮   哌圹�
+#0227  圹|07     |04圹圻    捋�    圹圹�    圯    圹圹|07     |04圹�    捋圯    捋    捋圹    捋�
+#0228  圹�    哌    苘圹|07     |04哌|07     |04苒踻07     |04圹圯    捋踻07     |04圹踻07     |04圹�    哌    苒圹
+#0229  圹|12|20皘04|16圹圹圹圹圹圹圹|12|20皘04|16圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹
+#0230  ------------------------------------------------------------------------------
+
+#0220 |07 |04屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐屯
+#0221  |12|20鄄眧04|16踻12|20遼04|16踻12|20鷟04|16圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹|12|20遼04|16圹圹圹圹圹圹|12|20鷟04|16圹踻12|20� 弑槽
+#0222 |07|16 |12|20蔺鷟04|16圻哌  苘    咣踻07     |04苒圹圹圹圹哌   苘� 哌咣圹踻07     |04苘 哌咣圹圻�   苘�  咣|12|20卟
+#0223 |16 |20皘04|16圹|07     |04圹|07      |04圹    捋圹圹圹圹�  |08�  |04咣圹    咣圯    圹�    咣�    捋圯    踻12|20�
+#0224 |16 |04圹�    捋圹苘苘圹�    捋圹圹圹圹踻07     |04苘軀07      |04圹 |08�  |04捋圹�    踻07     |04圹� |08卑 |04捋|12|20�
+#0225 |07|16 |12|20鷟04|16踻07     |04圹圹圹圹圹� |08�  |04捋圹圹圹圹� |08�  |04捋圹�  |08�  |04圹  |08� |04捋圹� |08�  |04圹苘   哌圮苒踻12|20皘04|16�
+#0226  圹 |08�   |04圹圹哌哌咣輡08卑� |04圹圮    咣輡08�   |04捋圹� |08�  |04捋� |08�  |04捋圹 |08�   |04圹哌哌圮   哌圹�
+#0227  |12|20皘04|16� |08脖  |04圹圻|08卑  |04捋輡08脖  |04圹圹輡08卑  |04圯|08脖  |04圹圹 |08薏� |04圹輡08脖  |04捋圯|08薏� |04捋 |08辈 |04捋圹 |08脖 |04迀12|20
+#0228 |07|16 |12|20卑|04|16� |08�  |04哌    苘圹 |08哌  |04哌|07     |04苒� |08哌  |04圹圯 |08哌 |04捋� |08哌  |04圹� |08哌  |04圹� |08�  |04哌  |08� |04軀12|20䙡04|16踻12|20�
+#0229 |07|16 |12|20鄄軀04|16踻12|20䙡04|16踻12|20鷟04|16圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹圹|12|20軀04|16圹|12|20䙡04|16踻12|20馨辈
+#0230 |16|07 |04屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐屯`00`07
+
+#0220 |07 |08哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪
+#0221  |11圻 |15圹� |11哌哌 |15哌哌哌� |11哌咣圻哌哌哌哌哌哌踻19脖|03|16� |14|20皘04|16踻12|20眧04|16圹� |14|20眧04|16圹圹 哌|14|20眧12卑|04|16圹圹圹圹  圹圹踻00|20N6^M
+#0222 |07|16 |11� |15圹圹圹圹 圹圹圹圹蒇圮 |11|19瞸07|16 |15圹蒇圹圹圹圯|11迀19眧03|16踻19 |07|16 |04捋|12|20皘04|16圹圮 哌|12|20皘04|16圻�   咣|12|20皘04|16圹圹圹�  |14|20皘12眧04|16圹圹^M
+#0223   |15圹圻哌咣� 哌哌哌圹� 哌 |11|19軀07|16 |15圹葸哌哌咣圯|11迀03圹|11|19皘03|16�  |04哌圹|12|20皘04|16圮�  |07苒圹苘  |04哌哌哌哌  哌|12|20皘04|16圹^M
+#0224  |11苘苘苒遼15捋� |11|19瞸16圹|19瞸16遼15捋� |11|19瞸16踻19瞸16圻|15捋� |11|19膊|16踻19瞸16遼15捋� |11|19脖|03|16圹圹圮�   |04哌� |07咣�   哌咣圮苘 |04哌咣苘苘躛M
+#0225  |11|19辈|16哌� |15苒圯|11捱哌 |15苒圯|11捱哌 |15苒圯|11捱哌 |15苒圯 |11遼19舶|03|16圹踻11|19皘03|16� |04軀14|20皘12皘04|16圹苘 |07捋輡09踻01|15軀07�  咣圹圹� |12|20眧04|16圻 躛M
+#0226  |11|19辈|07|16 |15圹圹圻 |11|19瞸07|16 |15圹圹圻 |11|19瞸07|16 |15圹圹圻 |11|19瞸07|16 |15圹圹圻圹� |11|19脖|03|16�  |04苘苘 哌|12|20瞸04|16圻 |07圯|01苓|15苒踻23軀07|16� 踻15|23皘07|16圹� |04� 苘|08|20皘04|16踍M
+#0227  |11|19氨|07|16 |15哌哌  |11哌 |15哌哌  |11哌 |15哌哌  |11哌 |15哌哌 |11� |15哌 |11� |04軀12|20眧04|16圹圹哌�  |07苘圹苘苘苘苘圹圹� |04苒|12|20卑|04|16圻|07^M
+#0228 |04 |03踻11|19氨瞸07|16 圻哌� � |11踻19瞸16� |07圻哌� 圻哌� 圻哌� |11踻19脖辈|07|16 |14|20皘12眧04|16圹圻  � |07圹圹踻23 |15� |07|16圹|23        |16 |04迀14|20皘04|16圹圯 踍M
+#0229  |03圹踻11|19皘07|16 圮苘� 圮苘� 圻哌� � |11|19遼07|16 � 苘苘� |11|19脖|03|16踻11|19皘03|16輡04捋圹圯 軀14|20皘04|16圮 |07咣|23  |15皘07|16踻23 |16圹|23     |16圹� |12|20眧04|16圹|08|20氨|07|16 |04圹^M
+#0230  |08哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪^M^M
+
+0220  |01哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪^M
+0221  |09圻 |15圹� |09哌哌 |15哌哌哌� |09哌咣圻哌哌哌哌哌哌 |15葺|09� |14皘08圹圹� |14皘08圹圹 哌|14皘08|22瞸16圹圹圹圹�  圹圹踻00|23N6^M
+0222 |07|16 |09� |15圹圹圹圹 圹圹圹圹蒇圮 |09|17瞸07|16 |15圹蒇圹圹圹圯 |09軀01軀09|17眧07|16 |08捋圹鄄� 哌|22瞸16圻�   咣|22瞸16圹圹圹�  |14皘08圹圹踍M
+0223   |15圹圻哌咣� 哌哌哌圹� 哌 |09|17軀07|16 |15圹葸哌哌咣圯|09迀01圹|09|17皘01|16�  |08哌圹圹苘  |07苒圹苘  |08哌哌哌哌  哌|22瞸16鄄^M
+0224  |09苘苘苒遼15捋� |09|17瞸16圹|17瞸16遼15捋� |09|17瞸16踻17瞸16圻|15捋� |09|17脖|16踻17瞸16遼15捋� |09|17脖|01|16圹圹圮�   |08哌� |07咣�   哌咣圮苘 |08哌咣苘苘躛M
+0225  |09|17辈|16哌� |15苒圯|09捱哌 |15苒圯|09捱哌 |15苒圯|09捱哌 |15苒圯 |09遼17舶|01|16圹踻09|17皘01|16� |08軀14皘08圹曹� |07捋輡14踻06䙡01鷟15軀07�  咣圹圹� |08槽� 躛M
+0226  |09|17辈|07|16 |15圹圹圻 |09|17瞸07|16 |15圹圹圻 |09|17瞸07|16 |15圹圹圻 |09|17皘07|16 |15圹圹圻圹� |09|17脖|01|16�  |08苘苘 哌圹� |07圯|06苓|15苒踻23軀07|16� 踻15|23皘07|16圹� |08� 苘槽^M
+0227  |09|17氨|07|16 |15哌哌  |09哌 |15哌哌  |09哌 |15哌哌  |09哌 |15哌哌 |09� |15哌 |09� |08懿圹圹哌�  |07苘圹苘苘苘苘圹圹� |08苒|22瞸16槽遼07^M
+0228 |08 |01踻09|17氨瞸07|16 圻哌� � |09踻17瞸16� |07圻哌� 圻哌� 圻哌� |09踻17脖辈|07|16 |14皘08槽圹�  � |07圹圹踻23 |15� |07|16圹|23        |16 |08迀14皘08圹圯 踍M
+0229  |01圹踻09|17皘07|16 圮苘� 圮苘� 圻哌� � |09|17遼07|16 � 苘苘� |09|17脖|01|16踻09|17皘01|16輡08捋圹圯 軀22瞸16圮 |07咣|23  |15皘07|16踻23 |16圹|23     |16圹� |08|22瞸16圹脖 圹^M
+0230  |01哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪^M^M
+
+
+0231 Buy Weapon
+0232 Quit
+0233 Redisplay Menu
+0234 View Stats
+0235 Buy Armor
+0236 Buy Shield
+0237 Trade With Clans
+0238 Chat w/Villagers
+0239 Pawn Shop
+
+# combat stuff
+0240 ^M|15All members of your clan are either dead or unconscious!^M|07Come back tomorrow when able to do things again!^M%P
+0241 ^M|05>> |02%ld people were impressed by your battles and join your following!^M   %ld were recruited by the government.^M
+0242 |07You've already fought that clan today.^M%P
+0243 ^M^M|03** |14%s |03vs. |11%s |03**^M^M
+0244 |07%-13s |10%d/%d HP   %d/%d SP^M
+# 0245 |10(|15A|10)|02ttack (S)pecific attack (R)un (P)layer stats s(K)ills (V)iew stats (?)Help^M
+# 0245 |02[|05A|02]ttack s[k]ills [s]pecific attack [r]un [p]layer stats [v]iew stats [?]help^M
+# 0245 |02(|05a|02)ttack (|05f|02)ight to death s(|05k|02)ills (|05s|02)pecific attack^M(|05r|02)un (|05p|02)layer stats (|05v|02)iew stats (|05?|02)help^M^M
+0245 |0C(|0Ba|0C)ttack (f)ight to death s(k)ills (s)pecific attack^Mattack(#) r(e)ad scroll sk(i)p move (r)un (p)layer stats (?)help^M^M
+0246 |14
+0247 |04
+0248 � |12%s missed!^M^M
+0249 � |15%s's |07%s is destroyed!^M^M
+0250 � |04%s attacks %s for |12%d damage.
+0251  [%ld]
+0252 � |14%s |12is killed!  |04[%d]^M^M
+0253 � |14%s |12is mortally wounded!  |04[%d]^M^M
+0254 � |14%s |12is knocked unconscious!  |04[%d]^M^M
+0255 |02You receive |10%ld gold|02!^M
+0256 |12%ld gold |02was lost to taxes.^M^M
+#0257 |02Which enemy to attack? (|03?=List;|10Enter|02=First enemy): |15
+0257 |0SWhich enemy to attack? (|0B?=List;|10Enter|0C=First enemy)^M> |0F
+#0258 |10%d|02. |07%-20s %d/%d hp^M
+#0259 |10%d|02. |07%s^M
+0258 |0A(|0B%c|0A) |0C%-20s %d/%d hp^M
+0259 |0A(|0B%c|0A) |0C%s^M
+0260 ^M^M|14** That character either isn't here or isn't alive!^M
+0261 ^M|10You achieve victory!^M
+0262 ^M|12Your clan has been defeated!^M
+0263 |10*** |02Your clan runs away!^M^M
+0264 |10*** |02Your clan tries running but fails!^M^M
+0265 |15You cannot run away whilst battling a fellow clan!^M^M
+
+# town stuff
+0273 |02It will cost %ld GP to upgrade the smithy to level %d.^M|10The village has |15%ld |10GP.^M^M
+0274 |0SUpgrade the smithy?
+0275 |15The smithy has been upgraded to level %d!^M%%P
+0276
+0277
+0278
+0279
+
+# spell stuff
+0280 ^M|07No skills are available for that character!^M^M
+0281 |0A(|0B%c|0A) %s%-20s (%2d sp)^M
+0282 |0A(|0B?|0A) |0CHelp^M|0A(|0BQ|0A) |0CAbort^M
+0283 |0SChoose Skill [|0BEnter=Abort|0S]: |0F
+0284 |04You do not have enough skill points.^M%P
+0285 |0SDo you wish to use this skill?
+0286 � |15%s |07attempts %s, but fails.^M^M
+0287 � |14No undead to banish!  Spell does nothing.^M^M
+0288
+0289
+0290
+
+0335 Structures Menu
+0336 Economics Menu
+0337 Change Color Scheme
+0338 Change Flag
+0339 Ruling Help
+0340 Make Announcement
+0341 Public Discussion
+0342 Abdicate
+0343 View Clan Stats
+0344 Redisplay Menu
+0345 Quit
+0346 Chat w/Villagers
+0347 Voting Booth
+0348 System of Government
+0349 Manage Empire
+
+0350 Pawn Shop
+0351 Wizard's Shop
+0352 Build Farms
+0353 Church
+0354 Training Hall
+0355 Ruling Help
+0356 Redisplay Menu
+0357 Quit
+0358 Upgrade Smithy
+0359
+
+# managing troops
+0360 Train Footmen
+0361 Train Axemen
+0362 Train Knights
+0363 Redisplay Menu
+0364 Quit
+0365 Help
+0366
+0367
+
+# outsider town hall
+0380 Deposit into Vault
+0381 Write to Ruler
+0382 Voting Booth
+0383 View Clan Stats
+0384 Public Discussions
+0385 Help
+0386 Redisplay Menu
+0387 Quit
+0388 Chat w/Villagers
+0389 Donate to Empire
+
+0390 Tax Rate
+0391 GST
+0392 Withdraw from Vault
+0393 Deposit into Vault
+0394 Ruling Help
+0395 Redisplay Menu
+0396 Quit
+0397
+0398
+
+
+# Village stats                          .
+0400  |0CStats for |0B%s |0X踻0Y踻0Z踻16^M
+0401  |0CClan Population         |0B%d clans          |0CRuling Clan    |0B%-s^M^M
+0402  |0CTax Rate                        |0B%d%%^M
+#0403  |0CInterest Rate                   |0B%d%%^M
+0404  |0CGoods and Services Tax          |0B%d%%^M
+#0405  |0LEntrance Fee            |0M%d GP^M
+0406  |0CEntrance Bonus                  |0B%d GP^M^M
+0407  |0CVault Gold                      |0B%ld GP^M
+0408 ^M |0CGame in progress for |0B%ld |0Cday(s) (since |0N%s|0C)^M |0CElimination mode is |0B%s^M
+0409 ^M |0CGame will begin on |0B%s^M
+0410 ^M |0CThe game is currently not in progress^M
+0411  |0CPopulation                      |0B%ld units^M
+0412  |0CPublic Approval                 |0B%d%% ^-
+0413  |0CCrime Rate                      |0B%d%%^M^M
+
+# fort stuff contines on 550
+
+0450  |0LStats for |0M%s   |0N%d/%d HP   %d/%d SP ^-
+0451  |0LRace             |0M%s^M
+0452  |0LClass            |0M%s^M
+0453  |0LAgility          |0M%-2d |0N(%2d)  ^-
+0454  |0LDexterity        |0M%-2d |0N(%2d)^M
+0455  |0LStrength         |0M%-2d |0N(%2d)  ^-
+0456  |0LWisdom           |0M%-2d |0N(%2d)^M
+0457  |0LArmor Strength   |0M%-2d |0N(%2d)  ^-
+0458  |0LCharisma         |0M%-2d |0N(%2d)^M
+0459  |0LLevel            |0M%-2d       ^-
+0460  |0LExperience       |0M%ld |0N(req. %ld)^M |0LTraining Points  |0M%d^M
+0461  |0LWeapon:          |0M%s^M
+0462  |0LWeapon:          |0MNone^M
+0463  |0LArmor:           |0M%s^M
+0464  |0LArmor:           |0MNone^M
+0465  |0LShield:          |0M%s^M
+0466  |0LShield:          |0MNone^M
+0467  |0LValues in ()'s are the values after modifiers.^M
+;0468 |0P(|0QE|0P)quip (|0QD|0P)rop (|0QS|0P)top Using e(|0QX|0P)amine (|0QL|0P)ist (|0Q?|0P)Help |0Q(|0RQ|0Q)|0Puit : |0R
+0468 ^M|0P(|0QL|0P=List,|0Q?|0P=Help,|0REnter|0P=Quit)> |0R
+0469 Examine Item^M^M
+0470 |04No items found.^M
+0471 |0SWhich item to examine? |04(0=abort)
+0472 |04Item does not exist.^M
+0473 List Items^M^M
+0474 Drop Item^M^M
+0475 |0SWhich item to drop? |04(0=abort)
+0476 |04Item is still in use.  Stop using it first.^M
+0477 |0SAre you sure you wish to drop %s?
+0478 %s dropped!^M^M
+0479 Stop Using Item^M^M
+# continued on 530
+
+0480  |0BName                                         |0ASymbol  Score   Status^M
+0481 |0K屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+
+# 0490  |0LStats for |0M%s  |07(%d-%d)^M
+# 0490  |0LStats for |0M%s |%02d%s^M
+0490  |0LStats for |0M%s %s^M
+0491  |0LLast game played: |0M%s^M
+0492  |0LGold            : |0M%ld^M
+0493  |0LMine Level      : |0M%d^M^M
+0494  |0P(|0QI|0P)nventory (|0QA|0P)llies (|0QV|0P)illage Stats (|0QS|0P)ymbol (|0QE|0P)mpire |0Q(|0RQ|0Q)|0Puit : |0R
+0495  |0LUntrained Followers    |0M%ld^M
+
+0520 |0SHow much do you wish to deposit into the village vault?
+0521 |15%ld gold deposited into village vault.^M^M
+0522 |07You may only withdraw 3 times a day!^M%P
+0523 |0SHow much do you wish to withdraw from the village vault?
+0524 |15%ld gold withdrawn from village vault.^M^M
+0525
+0526
+0527
+0528
+0529
+
+0530 |04Nothing equipped!^M
+0531 |0SWhich item to stop using? |04(0=abort) ^-
+0532 |04Item not in use!^M
+0533 ^M|0C%s unwields |0B%s^M
+0534 ^M|0C%s takes off |0B%s^M
+0535 ^M|0C%s stops using |0B%s^M
+0536 Equip^M^M
+0537 |04Everything already equipped!^M
+0538 |0SWhich item to equip?
+0539 |04Item already equipped!^M
+0540 |0A(|0B%c|0A) %s%-20s |0C%-s equipped^M
+0541 |0A(|0BQ|0A) |0CAbort^M^M
+0542 |0SWho will equip |0B%s|0S? |0F^-
+0543 |0SThat member is already wielding |0B%s|0S.  Unequip this first?
+0544 ^M|0C%s equips |0B%s!^M
+0545 |0SThat member is already wearing |0B%s|0S.  Unequip this first?
+0546 ^M|0C%s wears |0B%s!^M
+0547 |0SThat member is already using |0B%s|0S.  Unequip this first?
+0548 ^M|0C%s readies |0B%s!^M
+
+# manage troops
+0570  |07    Soldier        Cost(GP)    Owned^M
+0571  |0A(|0B1|0A) |0CFootmen            15       |0B%ld^M
+0572  |0A(|0B2|0A) |0CAxeman             30       |0B%ld^M
+0573  |0A(|0B3|0A) |0CKnights            60       |0B%ld^M
+0576  |0A(|0BH|0A) |0CHelp on Troops^M |0A(|0BQ|0A) |0CQuit^M^M
+0577 |0CYou have |0B%ld |0Cfollowers and |0B%ld |0Cgold.^M
+0578 ^M|0SHow many Footmen to train?
+0579 ^M|0B%ld |0CFootmen trained!  %ld gold deducted^M^M
+0580 ^M|0SHow many axemen to train?
+0581 ^M|0B%ld |0Caxemen trained!  %ld gold deducted^M^M
+0583 ^M|0SHow many knights to train?
+0584 ^M|0B%ld |0Cknights trained!  %ld gold deducted^M^M
+
+# Market Menu stuff
+0600 ^M|0B  Weapons Available^M
+0601 ^M|0B  Armor Available^M
+0602 ^M|0B  Shields Available^M
+0603 |07      name                    cost (gp)^M
+0604   |0A(|0B%c|0A) %s%-23s |15%ld^M
+0605   |0A(|0B?|0A) |0CHelp on Equipment^M  |0A(|0BQ|0A) |0CAbort^M^M  |0AYou have |0B%ld gold|0A.^M
+0606   |0GChoose one|0E> |0FAbort
+0607 Help on Equipment^M
+0608 |04Aborted^M^M
+0609 ^M|0B Cost is %ld gold.  |0CYou have %ld gold.^M^N
+0610 |0S Examine this?
+0611 |12You have no more room in your inventory!^M%P
+0612 |12You cannot afford it!^M%P
+0613 |0SMaterials available:^M |0A(|0BA|0A) |0CPolymetral^M |0A(|0BB|0A) |0CLaconia^M^M
+0614 |0SPlease choose the material to use: |0FPolymetral
+0615
+0616
+
+# getclass stuff
+0650 |0A(|0B%c|0A) |0C%s^M
+0651 |0A(|0B?|0A) |0CHelp^M
+0652 |0GEnter choice|0E> |0F
+0653 |0SChoose this?
+0654
+
+# options again :)
+0655 Train Member
+0656 Add a Member
+0657 Release a Member
+0658 Quit
+0659 Redisplay Menu
+0660 View Stats
+0661 Chat w/Villagers
+
+# color scheme stuff
+0670  |15Current Scheme Example:^M^M
+0671 |0D屯哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯^M
+0672   |0A(|0BE|0A) |0CEnter the Mines^M
+0673   |0A(|0BV|0A) |0CView Your Stats^M
+0674 |0D屯哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯^M
+0675  |0H[|0I12:13|0H] |0GEnter option|0E> |0F^M^M
+0676 |0K屯哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐蚟M
+0677 |0LStat         |0MStat Value    |0NMore Stats    |0O(More)^M
+0678 |0K屯哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪耐蚟M
+0679 |0Q(I)|0Pnventory, |0Q(C)|0Pharacters...|0Q(|0RQ|0Q)|0Puit^M^M
+0680 |0V<|0Wpause|0V>^M|0SQuestion?  |0A(|0CYes|0B/no|0A)^M
+0682
+0683
+0684
+0685 |071. () around hotkey      2. Hotkey                3. Option name^M
+0686 4. Line Divider          5. "Enter option" prompt 6. > after prompt^M
+0687 7. Prompt default choice 8. Time brackets         9. Time lit up^M
+0688 A. Time unlit            B. Stat line divider     C. Stat^M
+0689 D. Stat Value            E. More Stats            F. (More)^M
+0690 G. Stat option unlit     H. Stat option lit       I. Stat option hilight^M
+0691 J. Questions             M. Pause border          N. Pause prompt^M
+# 0692 !. list colours          Z. Choose scheme         Q. Quit^M^M
+0692 |15Z. Choose scheme         |07Q. Quit^M^M
+0693 |0GPlease choose an option|0E> |15
+0694
+
+
+# mail stuff
+0700 ^M|0CEnter up to |0B40 |0Clines.  Wrap-around is detected.^MType |0B/S |0Con a blank line to save.  |0B/A |0Cto abort.  |0B/? |0Cfor help.^M
+0701 |0C|16
+0702 |12No text entered.  Can't save blank message.^M
+0703 ^N|12Saved.^M
+0704 ^N|12Aborting message.^M
+0705 ^N|12Starting over^M
+0706 |12No text has been entered yet!^M
+0707 |13%d: |05%s|16
+0708 |1040 |02lines entered, message being saved.^M%P
+0709
+0710
+0720 |14Checking mail.^M
+0721 |0L From    : |0M%s^M|0L Date    : |0M%s ^-
+0722 |0L Date    : |0M%s ^-
+0723 |0N(PUBLIC POST #%d)
+0724 |0L Subject : |0M%s invites you to join the alliance of %s.^M
+0725 ^N                       ^N
+0726 |11|16 ^-
+0727 ^M|02+--+-: |02Do you wish to join this Alliance?
+0728 |0SReply to message?
+0729 %s rejected your alliance proposal.^M
+0730 %s has agreed to join your alliance!^M
+;0731 ^M|0K+------|0P[|0QR|0P]eply[|0QS|0P]kip[|0QQ|0P]uit|0Q[|0REnter=Skip|0Q] |0P: |05
+0731 ^M|0K屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M |0P(|0QR|0P)eply(|0QS|0P)kip(|0QQ|0P)uit|0Q(|0REnter=Skip|0Q) |0P: |05
+;0732 ^M|0K+------|0Q[|0RD|0Q]elete[|0QR|0P]eply[|0QS|0P]kip[|0QQ|0P]uit[|0QEnter=Delete|0P] |0P: |05
+0732 ^M|0K屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M |0Q(|0RD|0Q)elete|0P(|0QR|0P)eply(|0QS|0P)kip(|0QQ|0P)uit(|0QEnter=Delete|0P) |0P: |05
+0733 Reply^M^M
+0734 |0SDelete original message?
+0735 Delete^M^M
+0736 |10Deleting message.^M
+0737 Skip^M^M
+0738 Quit^M^M
+0740 |16|06[|10Command? : ?=help|06] : ^-
+0741 ^N|03(C)ontinue:(S)ave:(A)bort:(R)estart:(L)ist : [C] : ^-
+0742 ^N                                                                 ^N
+0743 |0SReally start message over?
+0744 |0SReally save?
+0745 |0SReally Abort?
+0746
+0747
+0748
+0749
+0750 |03Quote message?
+0751 |03Enter first line to quote |06[|10Enter=All|06]: |15
+0752 |10Quoting All of text...^M
+0753 |03Enter last line to quote: |15
+0754 |05> ^-
+0755 ^M|0CEnter up to |0B40 |0Clines.  Wrap-around is detected.^MType |0A/S |0Con a blank line to save.  |0A/A |0Cto abort.  |0A/Q |0Cto quote.  |0A/? |0Cfor help.^M
+0756 |0SPost as a public message?
+0757 ^N|03(C)ontinue:(S)ave:(A)bort:(R)estart:(Q)uote Line:(L)ist : [C] : ^-
+0758 ^M|10%02d: |02%s|16
+0759 ^M|03Enter line to quote: |15
+0760
+0761
+0762
+0763
+0764
+
+0800 |0A � |0CA new clan is formed: |0B%s^M^M
+0801 |0CNews for |0B%s^M^M
+0802 |0A � |0CThe village is now ruled by |0B%s^M^M
+0803 |0A � |0COur ruler |0B%s |0Chave built a bank for the village!^M^M
+0804 |0A � |0CUnder the rule of |0B%s|0C, the bank was upgraded to level %d!^M^M
+0805 |0A � |0CThe current rulers (|0B%s|0C) make an announcement:|0B^M^M     ^-
+0806 |0A � |0CThe government of |0B%s|0C has decided to use this flag: |%02d踻%02d踻%02d踍M^M
+0807 |0A � |0COur ruler |0B%s |0Chave built a church for the village!^M^M
+0808 |0A � |0CUnder the rule of |0B%s|0C, the church was upgraded to level %d!^M^M
+0809 |0A � |0COur ruler |0B%s |0Chave built a training hall for the village!^M^M
+0810 |0A � |0CUnder the rule of |0B%s|0C, the training hall was upgraded to level %d!^M^M
+0811 |0A � |0B%s gave up their rule of this village!^M^M
+0813 %s was heard speaking badly about your rule in public!
+0815 |0A � |0B%s embezzeled %ld gold |0Cfrom the village vault.^M^M
+0816 |0A � |0B%s |0C%s the tax rate from |0B%d%% to %d%%^M^M
+#0817 |03 � |15%s |02%s the interest rate from |10%d%% to %d%%^M^M
+0818 |0A � |0B%s |0C%s the GST from |0B%d%% to %d%%^M^M
+0819 |0A � |0BClan Combat:  |0C%s was defeated by %s!^M^M
+0820 Your clan was attacked by %s in hand-to-hand combat.^M |12Unfortunately, you were defeated!
+0821 |0A � |0BClan Combat:  |0C%s attacked %s but lost!^M^M
+0822 Your clan was attacked by %s in hand-to-hand combat.^M |15However, you were victorious and fended them off well!
+0823 |0A � |0CUnder the rule of |0B%s|0C, the smithy was upgraded to level %d!^M^M
+0829 |0A � |0CThe game has been reset!^M^M
+0830 |0A � |0CWaiting for InterBBS reset.^M^M
+0831 |0A � |0CThe game has been reset by the League Coordinator!^M^M
+0832 |0A � |0CThis BBS has joined the league and the game has begun!^M^M
+0833 |0A � |0B%s |0Chave entered town!^M^M
+0834 |0A � |0B%s |0Chave left town!^M^M
+0835   ID  Username              Clan Name^M----- --------------------  --------------------^M
+0836 |0A � |0BThe town of |13%s |08(%s) |0Chas joined the league!^M^M
+0837 |0A � |0B%s donated %ld gold |0Cto the village vault.^M^M
+0838 OUTBOUND.TMP
+0839 |07Your clan has the maximum number of permanent members already.^M%P
+0840 |0SAre you sure you wish to remove %s from the clan?
+0841 |0B%s |0Chas been removed from the clan!^M
+0842 |0A � |0BClan Combat:  |0C%s attacked %s but then retreated!^M^M
+0843 Your clan was attacked by %s in hand-to-hand combat.^M |13However, they ran away!
+
+0880 |07Sorry, this game is currently taking in no new players.^M
+0881 |02Your clan was last seen headed for |14%s |02(%s)!^MPlease call that BBS instead.^M^M
+0882 |0CThis BBS = |0B%s|0C, |0B%s|0C.^M%%P%%C
+0883  |07This BBS is not in a league.^M
+0884 ^MSomeone is currently playing the game on another node.^MPlease return in a few minutes.^M%P
+0885 |07World Travel is only permitted in InterBBS games.^M%P
+0886 |07There is currently no ruler of %s^M
+0887  |07A Canadian Product |04踻04|23|16|04踍M^M |07No dropfile (|15DOOR.SYS, DORINFOx.DEF, etc.|07) was found for that node.^M Please check the settings in your configuration.  If you wish to^M play locally, use |14CLANS /L |07as your command line.^M
+0888
+0889
+0890 Attend Mass
+0891 Ask for Blessing
+0892 Pray
+0893 Resurrect Clan Member
+0894 Quit
+0895 Redisplay Menu
+0896 View Stats
+0897 Revive Unconscious Member
+0898 Chat w/Villagers
+0990
+
+0900 Error opening village.dat!^M%P
+0901 - Couldn't open PC file.^M
+0902 CLANS.PC
+0903 VILLAGE.DAT
+0904 CLANS.MSJ
+0905 Couldn't open CLANS.MSJ file!^M
+0906 /hlp/ruler
+0907 /hlp/NEWBIE
+0908 /hlp/general
+0909 |07This option only applies to InterBBS games.^M%P
+0910 |14The game has not yet begun.^M^M
+0911 ^M|15Game begins on %s^M^M
+0912  Scores for The Clans^M^M Name                                         Symbol  Score   Status^M屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+0913 ^[[0m^[[2J^[[0;36m Scores for The Clans^M^M Name                                         Symbol  Score   Status^M^[[0;35m屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+0914 No one has played The Clans yet^M
+0915 No one has played The Clans yet^M
+0916  %-30s %s%s  %-6ld  ^-
+0917 Away
+0918 Here
+0919   (Ruler)^M
+0920 ^[[0m %-30s ^[[38m%s%s^[[0;1m  %-6ld  ^-
+0921 ^[[0;32mAway
+0922 ^[[1;35mHere
+0923 ^[[1;36m  (Ruler)^M
+0924 |10>> |15%s |02raises to level |14%d |02and gains %d training points!^M
+0925 Eliminated
+0926 Eliminated
+0927 NEW.PC
+0928 |12User online -- skipping packet processing^M
+0929 |12Could not find WORLD.NDX file.  If you are not in an InterBBS league,^Mturn off the InterBBS option in the CONFIG.EXE program.^M^M
+
+0930 Look for Creatures
+0931 Fight Other Clan
+0932 Quit
+0933 Redisplay Menu
+0934 View Stats
+0935 Change Mine Level
+0936 Go on a Quest
+0937 event
+0938 Chat w/Villagers
+0939 Who's Here?
+
+# reg messages
+0940 |01+---+---------------------------------------------------------------+---+^M
+0941    |09眧01� |11* unregistered * unregistered * unregistered * unregistered * |01硘09盺M
+0942 |01+---+---------------------------------------------------------------+---+^M
+0943 |07   This copy of The Clans is currently unregistered.  Please encourage^M
+0944    your sysop to register.  The cost is $15US ($20CAN)^M^M
+0945    Registration removes this message and also allows users to go beyond^M   level 4 of the mines, to upgrade characters beyond level 5, and to^M   access more than 10 Quests (and a few other things).^M^M   You can now register online using your credit card.^M   See PLASTIC.DOC for info!^M
+0946 |01+---+---------------------------------------------------------------+---+^M
+0947 |07This game is registered to |14%s |07for use on |14%s|07.^M
+0948 |02format:  |07CLANS |02[options]^M^M|02options:^M^M |10/Nx      |02-- |07use Node x^M |10/L       |02-- |07run game in local mode^M |10/O       |02-- |07create outbound packets now^M |10/I       |02-- |07process inbound packets now^M |10/M       |02-- |07run maintenance^M |10/FM      |02-- |07force daily maintenance to run (local only)^M |10/F       |02-- |07run in "fullmode"^M |10/T       |02-- |07use timeslicing code^M |10/USERS   |02-- |07see userlist^M |10/LIBBS   |02-- |07Local InterBBS support^M |10/Recon X |02-- |07send recon to BBS with ID X^M |10/NewNDX  |02-- |07send new WORLD.NDX file to all boards^M^M
+0949 |07That is the highest upgrade allowed in the UNREGISTERED version of this game.^M%P
+
+0950 Enter Game
+0951 See Scores
+0952 Today's News
+0953 Yesterday's News
+0954 Help
+0955 Instructions
+0956 Quit
+0957 Display Menu
+0958 Bulletins
+0959 Village Stats
+0960 Game Settings
+0961 League Scores
+
+0970 Enter the Mines
+0971 Quit
+0972 Redisplay Menu
+0973 View Stats
+0974 Market Menu
+0975 World Travel Menu
+0976 Communications Menu
+0977 Town Hall
+0978 Manage Empire
+0979 Church Menu
+0980 Training Hall
+0981 Chat w/Villagers
+0982 Newbie Help
+0983 Delete Clan
+0984 Memory Usage
+0985 Alliances Menu
+0986 Secret #2
+0987 Secret #3
+0988 Secret #4
+0989 Secret #5
+
+0990 View Other Villages
+0991 Quit
+0992 Redisplay Menu
+0993 View Stats
+0994 Travel to Another Village
+0995 Help on Villages and Travel
+0996 See Current Travel Info
+
+
+# combat options
+1000 Specific Attack
+1001 Attack
+1002 Run
+1003 Attack
+1004 Attack
+1005 Attack
+1006 Attack
+1007 Attack
+1008 Attack
+1009 Attack
+1010 Attack
+1011 Attack
+1012 Skip Move
+1013 View Player Stats
+1014 Skill
+1015 Help
+1016 Fight to Death
+1017 #
+1018 Read Scroll
+1019 Default
+
+1020  |0BAlliances Menu^M
+1021  |0A(|0B%c|0A) |0C%s^M
+1022  |0A(|0BZ|0A) |0CCreate an Alliance^M |0A(|0BQ|0A) |0CQuit^M
+1023 ^M|0SCreate an alliance?
+1024 |07You cannot create a new alliance, there are already too many.^M
+1025 |02Enter password^M|06> |07
+1026 ^M|12Wrong password!^M
+1027 Create Alliance^M
+#1028 |02Enter a password that others will need to use to get in this hall.^M|06> |07
+1029 |0SEnter a name for this alliance.^M|0E> |0F
+
+1030  |0CGold in Vault                   |0B%ld^M
+1031  |0CLand                            |0B%d^M
+1032  |0CFollowers                       |0B%ld^M
+1033  |0CFootmen                         |0B%ld^M
+1034  |0CArchers                         |0B%ld^M
+1035  |0CKnights                         |0B%ld^M
+1036  |0CCatapults                       |0B%ld^M
+1037  |0CAlliance Name                   |0B%s^M
+1038  |0CAlliance Owner                  |0B%s^M^M
+
+# options for empire menu
+1050 Donate Followers
+1051 Donate Footmen
+1052 Donate Archers
+1053 Donate Knights
+1054 Donate Catapults
+1055 Withdraw Followers
+1056 Withdraw Footmen
+1057 Withdraw Archers
+1058 Withdraw Knights
+1059 Withdraw Catapults
+1060 View Stats
+1061 Quit
+1062 Redisplay Menu
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+
+# troop donations
+1091 ^M|0P(|0QD|0P)rop item (|0QT|0P)ake item e(|0QX|0P)amine (|0QL|0P)ist own items^Ml(|0QI|0P)st room items (|0Q*|0P)destroy item (|0Q?|0P)Help |0Q(|0RQ|0Q)|0Puit : |0R
+
+# misc crap
+1150 /hlp/menus
+1151 /hlp/races
+1152 /hlp/village
+1153 /hlp/items
+1154 /hlp/bulletins
+1155 /hlp/fort
+1156 /hlp/combat
+1157 /hlp/stats
+1158 /hlp/strategy
+1159 /hlp/spells
+1160 /hlp/citizen
+1161 /hlp/war
+1162 /hlp/empire
+1163 /hlp/army
+
+1180 Buy items
+1181 Sell items
+1182 View Stats
+1183 Quit
+1184 Redisplay Menu
+1185
+1186
+1187
+1188
+1189
+1190 List
+1191 Quit
+1192 Buy
+1193 Examine
+1194 Help
+1195 List
+1196 Quit
+1197 Sell
+1198 Examine
+1199 Help
+
+1210 |0A圻|07    |06圹|07    |0A咣|07 ^-
+1211 |0A� |07 |06 哌|15|22軀07軀06|16哌 |07 |0A 踻07 ^-
+1212 |0A踻07     |15踻07�     |0A踻07 ^-
+1213 |0A踻07     |15踻07�     |0A踻07 ^-
+1214 |0A踻07     |15踻07�     |0A踻07 ^-
+1215 |0A圮|07    |15迀07�    |0A苒|07 ^-
+1216 |0A圻|07  軀15|23軀07|16圹圮  |0A咣|07 ^-
+1217 |0A� |07 踻15|23瞸07|16圹圹圹 |0A 踻07 ^-
+1218 |0A� |07 圹哌哌|08|23皘07|16� |0A 踻07 ^-
+1219 |0A� |07 踻15|23皘07|16圯捋|08|23眧07|16� |0A 踻07 ^-
+1220 |0A� |07 捋圯捋|08|23瞸07|16� |0A 踻07 ^-
+1221 |0A圮|07  咣蒉|08|23遼07|16�  |0A苒|07 ^-
+1222 |0A圻|07 踻15|23瞸07|16圹圹圹 |0A咣|07 ^-
+1223 |0A� |07 踻15|23踻07|16圹圹|08|23皘07|16� |0A 踻07 ^-
+1224 |0A� |07 踻15|23踻07|16圹圹|08|23瞸07|16� |0A 踻07 ^-
+1225 |0A� |07 踻15|23踻07|16圹圹|08|23踻07|16� |0A 踻07 ^-
+1226 |0A踻07   |15|23哕|07|16圹|08|23苓|07|16   |0A踻07 ^-
+1227 |0A圮|07   咣圻   |0A苒|07 ^-
+1228 |0A圻|07 苘苘苘苘 |0A咣|07 ^-
+1229 |0A� |07遼00|23哪哪哪膢07|16� |0A 踻07 ^-
+1230 |0A� |07 迀00|23------|07|16� |0A 踻07 ^-
+1231 |0A� |07 踻00|23-----|07|16�  |0A 踻07 ^-
+1232 |0A� |07 迀00|23--|07|16踻00|23--|07|16圯 |0A 踻07 ^-
+1233 |0A圮|07咣圹圹圹� |0A苒|07 ^-
+1234 |0A圻|06  軀07軀06哕|07    |0A咣|07 ^-
+1235 |0A� |06 圹 |07踻06 踻07    |0A踻07 ^-
+1236 |0A� |06圹圹 |07� |06踻07  |0A 踻07 ^-
+1237 |0A� |06圹圹� |07� |06� |0A 踻07 ^-
+1238 |0A� |06 圹圹遼07苓|06苓|0A 踻07 ^-
+1239 |0A圮|06  咣軀07|22遼06|16苓 |07 |0A苒|07 ^-
+1240 |0A圻|07  苘苘苘  |0A咣|07 ^-
+1241 |0A� |07 |15|23瞸07|16踻08|23皘07|16  |15|23瞸07|16圹 |0A 踻07 ^-
+1242 |0A� |07    軀15|23眧07|16踻08|23皘07|16� |0A 踻07 ^-
+1243 |0A� |07   |15|23皘07|16踻08|23皘07|16�   |0A 踻07 ^-
+1244 |0A� |07   哌�    |0A 踻07 ^-
+1245 |0A圮|07   |15|23皘07|16踻08|23眧07|16    |0A苒|07 ^-
+
+# Manage Empire menu
+1260 Build Structure
+1261 Manage Army
+1262 Attack Army
+1263 Quit
+1264 Redisplay menu
+1265 Spy on Empire
+1266 Donate to Empire
+1267 Develop Land
+1268 Help
+
+# structures menu
+1270 Quit
+1271 Redisplay menu
+1272 Barracks
+1273 Walls
+1274 Towers
+1275 Steel Mills
+1276 Stables
+1277 Intelligence Agencies
+1278 Security Centers
+1279 Gymnasium
+1280 Developers Halls
+1281 Destroy Buildings
+1282 Shops
+1283 View Stats
+
+# alliance menu
+1290 List alliance members
+1291 Invite clan into alliance
+1292 Remove clan from alliance
+1293 See member's stats
+1294 Chat Room
+1295 Donation Room
+1296 Manage Empire
+1297 Destroy Alliance
+1298 View Clan Stats
+1299 Quit
+1300 Redisplay menu
+1301 Write to Allies
+1302 Remove self
+
+# voting booth
+1310 Quit
+1311 Redisplay options
+1312 View Clan Stats
+1313 Change Vote
+#1314
+
+# wizard's shop
+1320 Buy Scroll
+1321 Buy Book
+1322 Examine Item
+1323 Quit
+1324 Redisplay Help
+1325 View Clan Stats
+
+# result of wars
+1350
+1351
+1352
+1353
+1354 |0B %ld |0CFootmen, |0B%ld |0CAxemen, |0B%ld |0CKnights ^M
+1355 ^M|0C You lost the following:^M  |0B%ld |0CFootmen, |0B%ld |0CAxemen, |0B%ld |0CKnights^M
+1356 |0SAttempt to loot how much steal land? (1-10%)
+1357 |0SAttempt to loot how much gold? (1-15%)
+1358 |0SAttempt how much damage? (1-15%)
+
+#
+1380  |0A(|0BP|0A) |0CBuild a pawn shop^M
+1381  |0A(|0BP|0A) |0CUpgrade pawn shop to level  |0B%d^M
+1382      |0CPawn Level                  |0B%d^M
+1383  |0A(|0BZ|0A) |0CBuild a Wizard shop^M
+1384  |0A(|0BZ|0A) |0CUpgrade Wiz. shop to Level  |0B%d^M
+1385      |0CWizard Level                |0B%d^M
+1386  |0A(|0BS|0A) |0CUpgrade Smithy to Level     |0B%d^M
+1387 Pawn shop is at max. level.^M
+1388 |02It will cost |10%ld GP |02to build a pawn shop.^M|10The village has |15%ld |10GP.^M^M
+1389 Build a pawn shop?
+1390 The village now has a pawn shop!^M
+1391 |0A � |0COur ruler |0B%s |0Chave built a pawn shop for the village!^M^M
+1392 |02It will cost %ld GP to upgrade the pawn shop to level %d.^M|10The village has |15%ld |10GP.^M^M
+1393 Upgrade the pawn shop?
+1394 |0CThe pawn shop has been upgraded to level |0B%d^M
+1395 |0A � |0C%s upgraded the pawn shop to level |0B%d^M^M
+1396 Wizard shop is at max. level.^M
+1397 |02It will cost |10%ld GP |02to build a wizard's shop.^M|10The village has |15%ld |10GP.^M^M
+1398 Build a wizard's shop?
+1399 The village now has a wizard's shop!^M
+1400 |0A � |0COur ruler |0B%s |0Chave built a wizard's shop for the village!^M^M
+1401 |02It will cost %ld GP to upgrade the wizard's shop to level %d.^M|10The village has |15%ld |10GP.^M^M
+1402 |0SUpgrade the wizard's shop?
+1403 The wizard's shop has been upgraded to level %d^M
+1404 |0A � |0C%s upgraded the wizard's shop to level %d^M^M
+
+# wizard's shop stuff
+1420 ^M|07There is currently no wizard's shop in the village.^M%P
+1421 |0SWhich item to examine? |04(0=abort)
+1422 |07I only examine books and scrolls^M%P
+1423 It will cost you %ld gold to examine that item.^MYou have %ld gold^M^M
+1424 Examine it?
+1425 /hlp/wizard
+1426
+1427
+1428
+1429
+1430
+
+# managing empire stuff
+1440  |0BManaging Empire^M
+1441  |0CGold                   |0B%ld^M
+1442  |0CArmy Rating            |0B%d^M
+1443  |0CDeveloped Land         |0B%d units^M
+1444  |0CWorker Energy          |0B%d%%^M
+1445  |0CSecurity Level         |0B%d^M
+1446  |0CSpy Level              |0B%d^M
+1447 |07You may only donate to a village or an alliance's empire.^M%P
+1448 |07You need a barracks first!^M%P
+1449 |07You need an intelligence agency first!^M%P
+
+# donate to empire stuff
+1450 Donate Followers
+1451 Donate Footmen
+1452 Donate Axemen
+1453 Donate Knights
+1454 Take Followers
+1455 Take Footmen
+1456 Take Axemen
+1457 Take Knights
+1458 Quit
+1459 Redisplay Menu
+1460 View Stats
+1461 Donate Land
+1462 Take Land
+1463 Donate Gold
+1464 Take Gold
+
+# more empire stuff
+1470  |0CDevelopers Level       |0B%d^M
+1471  |0CDeveloped Land         |0B%d units^M
+1472  |0CWorker Energy          |0B%d%%^M^M
+1473  |0A(|0B%c|0A) |0C%-20s    |0F%d^M
+1474  |0A(|0B*|0A) |0CDestroy Buildings^M |0A(|0BV|0A) |0CView Stats^M |0A(|0BQ|0A) |0CQuit^M
+1475  |0CBuilding Type          |0B%s^M
+1476  |0CWorker Energy Used     |0B%d%%^M
+1477  |0CLand Occupied          |0B%d^M
+1478  |0CCost                   |0B%ld^M^M
+1479 You need more land.^M%P
+1480 You need more worker energy.^M%P
+1481 |0SBuild this?
+1482 |0B%s |0Chas been built!^M
+1483  |0BManage Army^M
+1484  |0CArmy Rating            |0B%d^M^M
+1485 |07A steel mill must first be built.^M%P
+1486 |07A steel mill and stables must first be built.^M%P
+1487  |0A(|0BV|0A) |0CView Stats^M |0A(|0BQ|0A) |0CQuit^M
+1488 |07Shops can only be built by the village.^M%P
+1489 |07You don't have any of that building to destroy.^M%P
+1490 Destroy this?
+1491 %s destroyed.  %d land and %ld gold gained.^M%%P
+1492 The village army can only handle 2 attacks per day.^M
+1493 You can only command 5 attacks per day.^M
+1494 |07You need more gold.^M%P
+1495
+1496
+
+1500  |0CFollowers              |0B%ld^M
+1501  |0CFootmen                |0B%ld^M
+1502  |0CAxemen                 |0B%ld^M
+1503  |0CKnights                |0B%ld^M
+1504  |0CGold                   |0B%ld^M
+1505  |0CDeveloped Land         |0B%d units^M
+1506 |0SHow many Followers will you donate?
+1507 |0SHow many Footmen will you donate?
+1508 |0SHow many Axemen will you donate?
+1509 |0SHow many Knights will you donate?
+1510 |0SHow many Followers will you take?
+1511 |0SHow many Footmen will you take?
+1512 |0SHow many Axemen will you take?
+1513 |0SHow many Knights will you take?
+1514 |0SHow much Land will you donate?
+1515 |0SHow much Land will you take?
+1516 |0SHow much Gold will you donate?
+1517 |0SHow much Gold will you take?
+1518 |07A steel mill must first be built.^M%P
+1519 |07A steel mill and stables must first be built.^M%P
+1520 |07You cannot take from the town's empire.^M%P
+1521 |07You must first build a steel mill to own axemen.^M%P
+1522 |07A steel mill and stables must first be built.^M%P
+1523 |07Please use the economics menu.^M%P
+1524
+
+1530 |0CIt will cost you |0B%ld |0Cgold per unit of land to develop.^M
+1531 |0SHow much land to develop?
+1532 |0CYou developed |0B%d |0Cunits of land for |0B%ld |0Cgold^M
+1533
+1534
+
+1550 |0B%s |0Cattacked %s's empire!^M^M The enemy lost the following:^M ^-
+1551 ^M You were ousted from rule!^M
+1552 ^M The following buildings were destroyed:^M
+1553  ^M They stole |0B%d |0Cland!^M
+1554  ^M They looted |0B%ld |0Cgold!^M
+1555
+1556
+1557
+1558
+
+1580 |0SWhat type of empire?^M|0A> |0F
+1581 |0SWhich village? (Enter=abort)^M|0A> |0F
+1582 |0SWhat is the goal? (Enter=abort).^M|0A> |0F
+1583 ^M|0SChoose this goal?
+1584 |04There is no ruler to oust.  The attack is aborted.^M
+1585 |04No alliances found!^M
+1586 |0SWhich alliance? |0F
+1587
+
+1590  |0A(|0BA|0A) |0CFootmen   %5ld    |14%5ld^M
+1591  |0A(|0BB|0A) |0CAxemen    %5ld    |14%5ld^M
+1592  |0A(|0BC|0A) |0CKnights   %5ld    |14%5ld^M
+1593  |0A(|0B]|0A) |0CSend All^M |0A(|0B[|0A) |0CSend None^M |0A(|0B0|0A) |0CDone^M
+1594 |0SBring how many Footmen?
+1595 |0SBring how many Axemen?
+1596 |0SBring how many Knights?
+1597
+
+1600 ^M|0CYou lost |0B%ld |0CFootmen, |0B%ld |0CAxemen, and |0B%ld |0CKnights^M
+1601 |0CYou killed |0B%ld |0CFootmen, |0B%ld |0CAxemen, and |0B%ld |0CKnights^M^M
+1602 |0CYou were unable to penetrate their walls!^M
+1603 |0CYou came out |0Bvictorious|0C!^M
+1604 You successfully ousted the ruler!^M
+1605 |0CYou stole |0B%ld |0Cgold^M
+1606 There was no gold to steal!^M
+1607 |0CYou stole |0B%d |0Cunit(s) of land^M
+1608 |0CThere was no land to steal.^M
+1609 You destroyed the following buildings:^M
+1610  %2d %s^M
+1611 You destroyed the following buildings:^M
+1612  %2d %s^M
+1613 |0CYour forces come out |0Bdefeated|0C!^M
+1614
+
+
+1630 |07You may only spy 10 times each day.^M%P
+1631 |0CIt will cost you |0B%ld |0Cgold to spy.  The empire has |0B%ld |0Cgold.^M|0SContinue?
+1632 |0CYour spy is |15successful!^M
+1633 |0CYour spy failed and was |12captured!^M
+1634 A spying attempt on the village's empire by %s failed.^M
+1635 A spying attempt on %s's empire failed.^M The spy was from %s.^M
+1636 A spying attempt by %s on your clan's empire failed.^M
+1637 Your spies sent to %s were successful and return with information:^M^MGold:  %ld^MLand:  %d^M^MTroops:  %ld footmen, %ld axemen, %ld knights^M^MArmy Speed: %d^MArmy Offense: %ld^MArmy Defense: %ld^MArmy Vitality: %ld^M^MBuildings:
+1638
+
+1650 |0A(|0BL|0A)|0Cist |0A(|0BQ|0A)|0Cuit |0A(|0BB|0A)|0Cuy e|0A(|0BX|0A)|0Camine|0E> |0F
+1651 |0SWhich item to examine? |04(0=abort)
+1652 You have no more room in your inventory!^M
+1653 |0SBuy which item? |04(0=abort)
+1654 |0SBuy for |0B%ld |0Sgold?
+1655 |07You cheapskate, you don't have the gold!^M
+1656 |0B%2d. |0C%-20s  ^-
+1657 |0A(|0BL|0A)|0Cist |0A(|0BQ|0A)|0Cuit |0A(|0BS|0A)|0Cell sell |0A(|0BA|0A)|0Cll e|0A(|0BX|0A)|0Camine|0E> |0F
+1658 |0SWhich item to examine? |04(0=abort)
+1659 |07I'm sorry, we cannot accept any more items.^M
+1660 |0SWhich item to sell? |04(0=abort)
+1661 |0BYou're still using it!^M
+1662 |0SSell it for |0B%ld |0Sgold?
+1663 |0CNo items for sale.^M
+
+1675 |0CYou find |0B%s|0C. |0STake it?
+
+1680 |0A � |0C%s attacked %s and %s.^M     ^-
+1681 They ousted our rulers!^M
+1682 They looted land.^M
+1683 They looted some gold.^M
+1684 They caused much damage.^M
+1685 |0A � |0C%s's army returns after finding no ruler to oust in %s.^M^M
+1686 but found no ruler to oust!^M
+1687 |0A � |0C%s's army returns after being unable to find the clan empire.^M^M
+1688 but found no empire!^M
+1689 and came out victorious!^M
+1690 |0A � |0C%s's army returns after successfully^M     ousting the ruler of %s^M^M
+1691 |0A � |0C%s's army returns successfully from %s^M     looting %d land from %s.^M^M
+1692 |0A � |0C%s's army returns successfully from %s^M     looting %ld gold from %s.^M^M
+1693 |0A � |0C%s's army returns successfully from %s^M     destroying %s's buildings.^M^M
+1694 and came out defeated.^M
+1695 |0A � |0C%s's army returns unsuccessfully from %s^M     after attacking %s.^M^M
+1696 |0CResults of %s's attack on %s have returned.^M Your troops attempted %s %s^M^M You killed the following:^M ^-
+1697 ^M The following have returned:^M  |0B%ld |0CFootmen, |0B%ld |0CAxemen, |0B%ld |0CKnights^M
+1698 ^M You stole |0B%d |0Cland.^M
+1699 ^M You found no land to steal!^M
+1700 ^M You stole |0B%ld |0Cgold.^M
+1701 ^M You found no gold to steal!^M
+
+1710 |0A � |0B%s|0C's reign as dictator continues.^M^M
+1711 |0A � |0B%s|0C is re-elected as the leader of town!^M^M
+1712 |0A � |0B%s|0C is elected as the new leader of town!^M^M
+1713 |0A � |0CShops brought in |0B%ld |0Cgold today!^M^M
+1714 |0A � |0C%s %s the conscription rate from |0B%d%% |0Cto |0B%d%%^M^M
+
+1715  |0CGold in Vaults                  |0B%ld^M
+1716  |0CConscription Rate               |0B%d^M
+1717  |0CSystem of Government            |0B%s^M
+1718 |07You cannot set conscription rate more than once a day.^M%P
+1719 |0SEnter conscription rate.
+1720 |07This town is under dictatorial rule.  Voting is disabled.^M%P
+1721 |0A � |0C%s has changed this town's government system to |0BDictatorship^M^M
+1722 |0A � |0C%s has changed this town's government system to |0BDemocracy^M^M
+1723 |0CCurrent Government:  |0B%s^M
+1724 |0SSwitch to Dictatorship?
+1725 |0SSwitch to Democracy?
+1726  |0CEmpire Statistics               |0B%s^M
+
+1730  |0LStats for the empire of |0M%s^M
+1731  |0LGold                            |0M%ld^M
+1732  |0LLand                            |0M%d units^M
+1733  |0LWorker Energy                   |0M%d%%^M
+1734  |0LArmy Statistics:  ^M
+1735  |0L- |0LFootmen: |0M%ld,
+1736  |0LAxemen: |0M%ld,
+1737  |0LKnights: |0M%ld,
+1738  |0LRating: |0M%d^M
+1739  |0L- |0LAvg. Speed: |0M%d,
+1740  |0LTotal Vitality: |0M%ld,
+1741  |0LOffense: |0M%ld,
+1742  |0LDefense: |0M%ld^M
+1743 ^M |0LBuildings:^M
+1744   |0MNone.^M
+1745  |0CSpeed: |0B%d, ^-
+1746 |0COffense: |0B%ld, ^-
+1747 |0CDefense: |0B%ld, ^-
+1748 |0CVitality: |0B%ld^M^M
+1749
+
+1760 |0CGame Start                 |0B%s^M
+1761 |0CElimination mode           |0B%s^M
+1762 |0CMax Permanent Clan members |0B%d^M
+1763 |0CClan Travel                |0B%s^M
+1764 |0CClan Empires are           |0B%s^M
+1765 |0CMine Fights per day        |0B%d^M
+1766 |0CClan Fights per day        |0B%d^M
+1767 |0CDays of Protection         |0B%d^M
+1768
+1769
+
+1770 |07Scores have not been generated yet.^M
+1771 ^M |0BName                                    |0ASymbol Score  Village^M
+1772  |0CTop 20 Clans in the league. |0B(as of %s)^M
+1773 |0C %-25s %s%s`0F %-6ld |0C%-20s^M
+1774
+1775
+1776
+
+1780  |0LDefault action in combat: |0M^-
+1781 ^M|0P(|0QC|0P)hange Default Action, |0Q[|0REnter=Quit|0Q] : |0R
+1782 |0EChoose a default action to be done in combat^M|0G> |0F
+
+#new stats lines
+1800  |0L%s ^-
+1801 |0LEquipment^M|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪� 哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+1802 |0L Level               |0M%d ^-
+1803 |0LWeapon    |0M%s^M
+1804 |0L Experience          |0M%ld (%ld req.)
+1805 |0LArmor     |0M%s^M
+1806 |0L Race/Class          |0M%s/%s
+1807 |0LShield    |0M%s^M
+1808 |0L Hitpoints           |0M%d/%d^M
+1809 |0L Skillpoints         |0M%d/%d^M
+1810  ^M|0L Statistics |0M(base values) plus modifiers   |0LSkills/Spells Known^M|0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪� 哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+1811 ^M|0L Default Action      |0M^-
+1812 |0D屯湍哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯蚟M
+1813  |0P[|0QC|0P]hange Default Action, |0Q[|0REnter|0Q]|0P=Quit> |0R^-
+1814 |0L Training Points     |0M%d^M
+1815
+
+1832 |07This secret only works on |12Japanese |07versions of this game.^M%P
+1835 |07The |15X |07warrior will let you in.^M%P
+
+1836 seineew era sremmargorp sbb
\ No newline at end of file
diff --git a/src/doors/clans-devkit/VILLAGE.HLP b/src/doors/clans-devkit/VILLAGE.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..6678c51e0b7cc2db544c3d1a3a5ad544ff35b44a
--- /dev/null
+++ b/src/doors/clans-devkit/VILLAGE.HLP
@@ -0,0 +1,46 @@
+Village Help file
+
+^Why Travel?
+ |0CThe main benefit of traveling is to allow you to find a better village
+ or to increase your clan size.  You may find another village with a lower
+ tax rate or a much stabler government.  You may find your clan prospers there
+ while in other villages, it is destroyed.  On the other hand, if you have a
+ powerful clan, traveling to other villages will allow you to vanquish more
+ enemies!
+
+ You may also find it useful to abandon a town if you are continually attacked
+ or your fort is being destroyed.
+^END
+
+^What ARE Other Villages?
+ |0COther villages are simply other BBSes which are running the game of Clans
+ and are connected with this BBS in an InterBBS league.  When you travel to
+ another village, your clan will be "moved" from here to the other BBS which
+ is running the game.  You will then be able to log into the other BBS and
+ your characters will be there*.
+
+|0B * If you travel today, your clan will arrive TOMORROW in the other town.
+  You should be able to call the other BBS the next day and play as you
+  would normally.
+
+|12 NOTE:  You must already have an account or else are going to have an account
+ on the other BBS before you can play there!  If you move your clan to another
+ BBS and find you have no access to that BBS, your clan will remain there!
+^END
+
+^Traveling
+ |0CIf you choose to travel to another village, your clan's data will be
+ received by the other board and you will be allowed to play there the NEXT
+ DAY and no sooner.  If you make a mistake, you can always log into this
+ BBS and choose to "call back" your clan to this board if they are already
+ gone.
+
+ To continue playing in this league, you MUST call the other BBS since
+ your player data will be there and not here. You can always travel back
+ to this BBS if you wish.  If your data isn't sent properly to the other
+ BBS, this BBS will update the files so that you are back in this
+ village.
+
+ |0B* Be sure you have an account on the other BBS before traveling to its
+   village!
+^END
diff --git a/src/doors/clans-devkit/WAR.HLP b/src/doors/clans-devkit/WAR.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..f79c0c48a0e31aa63d6622cfece0c3a9ed78bed0
--- /dev/null
+++ b/src/doors/clans-devkit/WAR.HLP
@@ -0,0 +1,115 @@
+^War Help
+|0CBy attacking another empire, you will be able to gain their gold or land,
+or else simply cause mass destruction to their buildings.
+^END
+
+^Barracks
+|0BBarracks
+
+|0CBarracks are required to train new troops.  Each barracks can train 20
+Footmen, 10 Axemen, and 5 Knights.
+
+^END
+
+^Walls
+|0BWalls
+
+|0CWalls are used to prevent enemy troops from gaining easy access into the
+empire.  However, they are easily destroyed in battle.
+
+^END
+
+^Towers
+|0BTowers
+
+|0CTowers complement walls and can often kill off some troops when defending.
+However, like walls, they are easily destroyed.
+
+^END
+
+^Steel Mill
+|0BSteel Mill
+
+|0CA steel mill is required to train axemen.  Only one is required.
+
+^END
+
+^Stables
+|0BStables
+
+|0CStables are required to hold horses used by knights.  Only one is required.
+
+^END
+
+^Intell. Agencies
+|0BIntelligence Agencies
+
+|0CAn intelligence agency is used to train spies.  The more agencies built,
+the higher the level of spies sent out.  Agencies should be built often as
+the enemy will be building up their security.
+
+^END
+
+^Security Centers
+|0BSecurity Centers
+
+|0CSecurity centers prevent spies from spying on your empire.  The more
+security centers you have the higher the level of spies required to spy on
+you.
+
+^END
+
+^Gymnasiums
+|0BGymnasiums
+
+|0CA gymnasium functions as a place to keep troops healthy.  Each gymnasium
+will increment the army rating daily by 2%.
+
+^END
+
+^Developer's Halls
+|0BDeveloper's Halls
+
+|0CDeveloper's are needed to develop barren land for construction.  The higher
+the number of these halls, the better your developers will become at
+developing land.  As they improve, the cost of developing land will drop.
+
+^END
+
+^Shops
+|0BShops
+
+|0CShops can only be built by the village.  Each shop brings in approximately
+1500 gold each.  The town starts out with 10 shops at the onset of the game.
+
+^END
+
+# Goals
+^0 Oust the Ruler of the Village
+|0BOust the Ruler
+
+|0CIf you wish to get rid of the current ruler of the village, attack with
+the intent of ousting them.
+^END
+
+^1 Capture Land
+|0BCapture Land
+
+|0CLand is needed to build new structures within your empire.  However, it
+costs gold to develop.  This goal allows you to loot some of an empire's
+unused land and destroy some of his buildings to loot his used land as well.
+^END
+
+^2 Capture Gold
+|0BCapture Gold
+
+|0CThis goal allows you to break into the empire's vaults and steal some
+of their gold.
+^END
+
+^3 Destroy Buildings
+|0BDestroy Buildings
+
+|0CWithout buildings, an empire cannot fend for itself.  This goal allows you
+to destroy some of their buildings.
+^END
diff --git a/src/doors/clans-devkit/WIZARD.HLP b/src/doors/clans-devkit/WIZARD.HLP
new file mode 100644
index 0000000000000000000000000000000000000000..95d65caa95a0cd6f409697fbc3776db140f8f58c
--- /dev/null
+++ b/src/doors/clans-devkit/WIZARD.HLP
@@ -0,0 +1,55 @@
+^Flame Scroll
+|0C This scroll allows the user to cast a fireball spell at an enemy.
+^END
+
+^Summon Scroll
+|0C This scroll allows the reader to summon undead beings to help the clan
+ out in battle.
+^END
+
+^Banish Scroll
+|0C When read, some of the enemy's undead beings will be banished from this
+ realm.
+^END
+
+^Summon Khaos
+|0C I do not recognize that scroll and its purpose eludes even me.
+^END
+
+^Summon Dragon
+|0C When read, this scroll will allow the reader to summon a Gold Dragon to
+ aid the clan in combat.
+^END
+
+^Ice Blast
+|0C This scroll allows the reader send a blast of energy in the form of ice
+ directed at an enemy.
+^END
+
+^Book of Stamina
+|0C The reader of this book will gain vitality in the form of HitPoints.
+^END
+
+^Book of Mana
+|0C The reader of this book will gain mana in the form of Skill Points.
+^END
+
+^Book of Healing
+|0C The reader of this book will learn to cast a Heal spell.
+^END
+
+^Book of Flames
+|0C The reader of this book will learn to cast a Fireball spell.
+^END
+
+^Book of the Dead I
+|0C The reader of this book will learn how to raise the undead.
+^END
+
+^Book of the Dead II
+|0C The reader of this book will learn how to banish the undead.
+^END
+
+^Book of Destruction
+|0C The reader of this book will learn how to cast a Rain of Terror spell.
+^END
diff --git a/src/doors/clans-devkit/chew.c b/src/doors/clans-devkit/chew.c
new file mode 100644
index 0000000000000000000000000000000000000000..f59feb2bfaf45b457fd139056daed4d9117e6a70
--- /dev/null
+++ b/src/doors/clans-devkit/chew.c
@@ -0,0 +1,822 @@
+/* Chew -- Program to make .GUM encrypted files */
+
+/*
+ * Compression code taken from SIXPACK.C by Philip G. Gage.
+ * For original source code either do a search for sixpack.c
+ * or go here:
+ * 
+ * http://www.ifi.uio.no/in383/src/ddj/sixpack/
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __MSDOS__
+#include <alloc.h>        /* Use <malloc.c> for Power C */
+#else /* !__MSDOS__ */
+# include <memory.h>
+# include "defines.h"
+# define farmalloc malloc  /* for flat memory models */
+# define farfree free      /* for flat memory models */
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <time.h>
+# include <errno.h>
+
+unsigned _dos_getftime (int, unsigned *, unsigned *);
+#endif /* __MSDOS__ */
+
+#ifdef __unix__
+#include <ctype.h>
+#include <unistd.h>
+#endif
+
+#define MAX_TOKEN_CHARS 32
+#define CODE1           0x7D
+#define CODE2           0x1F
+
+void ClearAll ( void );
+void AddGUM(FILE *fpGUM, char *pszFileName);
+void GetToken ( char *szString, char *szToken );
+void AddDir(FILE *fpGUM, char *pszDirName);
+
+#define TEXTSEARCH 1000   /* Max strings to search in text file */
+#define BINSEARCH   200   /* Max strings to search in binary file */
+#define TEXTNEXT     50   /* Max search at next character in text file */
+#define BINNEXT      20   /* Max search at next character in binary file */
+#define MAXFREQ    2000   /* Max frequency count before table reset */ 
+#define MINCOPY       3   /* Shortest string copy length */
+#define MAXCOPY      64   /* Longest string copy length */
+#define SHORTRANGE    3   /* Max distance range for shortest length copy */
+#define COPYRANGES    6   /* Number of string copy distance bit ranges */
+short copybits[COPYRANGES] = {4,6,8,10,12,14};   /* Distance bits */
+
+#define CODESPERRANGE (MAXCOPY - MINCOPY + 1)
+int copymin[COPYRANGES], copymax[COPYRANGES];
+int maxdistance, maxsize;
+int distance, insert = MINCOPY, dictfile = 0, binary = 0;
+
+#define NIL -1                    /* End of linked list marker */
+#define HASHSIZE 16384            /* Number of entries in hash table */
+#define HASHMASK (HASHSIZE - 1)   /* Mask for hash key wrap */
+short FAR *head;
+short FAR *tail;       /* Hash table */
+short FAR *succ;
+short FAR *pred;       /* Doubly linked lists */
+unsigned char *buffer;            /* Text buffer */
+
+/* Define hash key function using MINCOPY characters of string prefix */
+#define getkey(n) ((buffer[n] ^ (buffer[(n+1)%maxsize]<<4) ^ \
+                   (buffer[(n+2)%maxsize]<<8)) & HASHMASK)
+
+/* Adaptive Huffman variables */
+#define TERMINATE 256             /* EOF code */
+#define FIRSTCODE 257             /* First code for copy lengths */
+#define _MAXCHAR (FIRSTCODE+COPYRANGES*CODESPERRANGE-1)
+#define SUCCMAX (_MAXCHAR+1)
+#define TWICEMAX (2*_MAXCHAR+1)
+#define ROOT 1
+short left[_MAXCHAR+1], right[_MAXCHAR+1];  /* Huffman tree */
+short up[TWICEMAX+1], freq[TWICEMAX+1];
+
+/*** Bit packing routines ***/
+
+int input_bit_count = 0;           /* Input bits buffered */
+int input_bit_buffer = 0;          /* Input buffer */
+int output_bit_count = 0;          /* Output bits buffered */
+int output_bit_buffer = 0;         /* Output buffer */
+long bytes_in = 0, bytes_out = 0;  /* File size counters */
+
+long TotalBytes = 0;
+
+/* Write one bit to output file */
+void output_bit(output,bit)
+  FILE *output;
+  int bit;
+{
+  output_bit_buffer <<= 1;
+  if (bit) output_bit_buffer |= 1;
+  if (++output_bit_count == 8) {
+    putc(output_bit_buffer,output);
+    output_bit_count = 0;
+    ++bytes_out;
+  }
+}
+
+/* Read a bit from input file */
+int input_bit(input)
+  FILE *input;
+{
+  int bit;
+
+  if (input_bit_count-- == 0) {
+    input_bit_buffer = getc(input);
+    if (input_bit_buffer == EOF) {
+      printf(" UNEXPECTED END OF FILE\n");
+      exit(1);
+    }
+    ++bytes_in;
+    input_bit_count = 7;
+  }
+  bit = (input_bit_buffer & 0x80) != 0;
+  input_bit_buffer <<= 1;
+  return(bit);
+}
+
+/* Write multibit code to output file */
+void output_code(output,code,bits)
+  FILE *output;
+  int code,bits;
+{
+  int i;
+
+  for (i = 0; i<bits; i++) {
+    output_bit(output,code & 0x01);
+    code >>= 1;
+  }
+}
+
+/* Read multibit code from input file */
+int input_code(input,bits)
+  FILE *input;
+  int bits;
+{
+  int i, bit = 1, code = 0;
+
+  for (i = 0; i<bits; i++) {
+    if (input_bit(input)) code |= bit;
+    bit <<= 1;
+  }
+  return(code);
+}
+
+/* Flush any remaining bits to output file before closing file */
+void flush_bits(output)
+  FILE *output;
+{
+  if (output_bit_count > 0) {
+    putc((output_bit_buffer << (8-output_bit_count)),output);
+    ++bytes_out;
+  }
+}
+
+/*** Adaptive Huffman frequency compression ***/
+
+/* Data structure based partly on "Application of Splay Trees
+   to Data Compression", Communications of the ACM 8/88 */
+
+/* Initialize data for compression or decompression */
+void initialize()
+{
+  int i, j;
+
+  /* Initialize Huffman frequency tree */
+  for (i = 2; i<=TWICEMAX; i++) {
+    up[i] = i/2;
+    freq[i] = 1;
+  }
+  for (i = 1; i<=_MAXCHAR; i++) {
+    left[i] = 2*i;
+    right[i] = 2*i+1;
+  }
+
+  /* Initialize copy distance ranges */
+  j = 0;
+  for (i = 0; i<COPYRANGES; i++) {
+    copymin[i] = j;
+    j += 1 << copybits[i];
+    copymax[i] = j - 1;
+  }
+  maxdistance = j - 1;
+  maxsize = maxdistance + MAXCOPY;
+}
+
+/* Update frequency counts from leaf to root */
+void update_freq(a,b)
+  int a,b;
+{
+  do {
+    freq[up[a]] = freq[a] + freq[b];
+    a = up[a];
+    if (a != ROOT) {
+      if (left[up[a]] == a) b = right[up[a]];
+      else b = left[up[a]];
+    }
+  } while (a != ROOT);
+
+  /* Periodically scale frequencies down by half to avoid overflow */
+  /* This also provides some local adaption and better compression */
+  if (freq[ROOT] == MAXFREQ)
+    for (a = 1; a<=TWICEMAX; a++) freq[a] >>= 1;
+}
+
+/* Update Huffman model for each character code */
+void update_model(code)
+  int code;
+{
+  int a, b, c, ua, uua;
+
+  a = code + SUCCMAX;
+  ++freq[a];
+  if (up[a] != ROOT) {
+    ua = up[a];
+    if (left[ua] == a) update_freq(a,right[ua]);
+    else update_freq(a,left[ua]);
+    do {
+      uua = up[ua];
+      if (left[uua] == ua) b = right[uua];
+      else b = left[uua];
+
+      /* If high freq lower in tree, swap nodes */
+      if (freq[a] > freq[b]) {
+        if (left[uua] == ua) right[uua] = a;
+        else left[uua] = a;
+        if (left[ua] == a) {
+          left[ua] = b; c = right[ua];
+        } else {
+          right[ua] = b; c = left[ua];
+        }
+        up[b] = ua; up[a] = uua;
+        update_freq(b,c); a = b;
+      }
+      a = up[a]; ua = up[a];
+    } while (ua != ROOT);
+  }
+}
+
+/* Compress a character code to output stream */
+void compress(output,code)
+  FILE *output;
+  int code;
+{
+  int a, sp = 0;
+  int stack[50];
+
+  a = code + SUCCMAX;
+  do {
+    stack[sp++] = (right[up[a]] == a);
+    a = up[a];
+  } while (a != ROOT);
+  do {
+    output_bit(output,stack[--sp]);
+  } while (sp);
+  update_model(code);
+}
+
+/* Uncompress a character code from input stream */
+int uncompress(input)
+  FILE *input;
+{
+  int a = ROOT;
+
+  do {
+    if (input_bit(input)) a = right[a];
+    else a = left[a];
+  } while (a <= _MAXCHAR);
+  update_model(a-SUCCMAX);
+  return(a-SUCCMAX);
+}
+
+/*** Hash table linked list string search routines ***/
+
+/* Add node to head of list */
+void add_node(n)  
+  int n;
+{
+  int key;
+
+  key = getkey(n);
+  if (head[key] == NIL) {
+    tail[key] = n;
+    succ[n] = NIL;
+  } else {
+    succ[n] = head[key];
+    pred[head[key]] = n;
+  }
+  head[key] = n;
+  pred[n] = NIL;
+}
+
+/* Delete node from tail of list */
+void delete_node(n)
+  int n;
+{
+  int key;
+
+  key = getkey(n);
+  if (head[key] == tail[key])
+    head[key] = NIL;
+  else {
+    succ[pred[tail[key]]] = NIL;
+    tail[key] = pred[tail[key]];
+  }
+}
+
+/* Find longest string matching lookahead buffer string */
+int match(n,depth)
+  int n,depth;
+{
+  int i, j, index, key, dist, len, best = 0, count = 0;
+
+  if (n == maxsize) n = 0;
+  key = getkey(n);
+  index = head[key];
+  while (index != NIL) {
+    if (++count > depth) break;     /* Quit if depth exceeded */
+    if (buffer[(n+best)%maxsize] == buffer[(index+best)%maxsize]) {
+      len = 0;  i = n;  j = index;
+      while (buffer[i]==buffer[j] && len<MAXCOPY && j!=n && i!=insert) {
+        ++len;
+        if (++i == maxsize) i = 0;
+        if (++j == maxsize) j = 0;
+      }
+      dist = n - index;
+      if (dist < 0) dist += maxsize;
+      dist -= len;
+      /* If dict file, quit at shortest distance range */
+      if (dictfile && dist > copymax[0]) break;
+      if (len > best && dist <= maxdistance) {     /* Update best match */
+        if (len > MINCOPY || dist <= copymax[SHORTRANGE+binary]) {
+          best = len; distance = dist;
+        }
+      }
+    }
+    index = succ[index];
+  }
+  return(best);
+}
+
+/*** Finite Window compression routines ***/
+
+#define IDLE 0    /* Not processing a copy */
+#define COPY 1    /* Currently processing copy */
+
+/* Check first buffer for ordered dictionary file */
+/* Better compression using short distance copies */
+int dictionary()
+{
+  int i = 0, j = 0, k, count = 0;
+
+  /* Count matching chars at start of adjacent lines */
+  while (++j < MINCOPY+MAXCOPY) {
+    if (buffer[j-1] == 10) {
+      k = j;
+      while (buffer[i++] == buffer[k++]) ++count;
+      i = j;
+    }
+  }
+  /* If matching line prefixes > 25% assume dictionary */
+  if (count > (MINCOPY+MAXCOPY)/4) dictfile = 1;
+  return(0);
+}
+
+/* Encode file from input to output */
+int encode(input,output)
+  FILE *input, *output;
+{
+  int c, i, n=MINCOPY, addpos=0, len=0, full=0, state=IDLE, nextlen;
+
+  initialize();
+  head = farmalloc((unsigned long)HASHSIZE*sizeof(short));
+  tail = farmalloc((unsigned long)HASHSIZE*sizeof(short));
+  succ = farmalloc((unsigned long)maxsize*sizeof(short));
+  pred = farmalloc((unsigned long)maxsize*sizeof(short));
+  buffer = (unsigned char *) malloc(maxsize*sizeof(unsigned char));
+  if (head==NULL || tail==NULL || succ==NULL || pred==NULL || buffer==NULL) {
+    printf("Error allocating memory\n");
+    exit(1);
+  }
+
+  /* Initialize hash table to empty */
+  for (i = 0; i<HASHSIZE; i++) {
+    head[i] = NIL;
+  }
+
+  /* Compress first few characters using Huffman */
+  for (i = 0; i<MINCOPY; i++) {
+    if ((c = getc(input)) == EOF) {
+      compress(output,TERMINATE);
+      flush_bits(output);
+      return(bytes_in);
+    }
+    compress(output,c);  ++bytes_in;
+    buffer[i] = c;
+  }
+
+  /* Preload next few characters into lookahead buffer */
+  for (i = 0; i<MAXCOPY; i++) {
+    if ((c = getc(input)) == EOF) break;
+    buffer[insert++] = c;  ++bytes_in;
+    if (c > 127) binary = 1;     /* Binary file ? */
+  }
+  dictionary();  /* Check for dictionary file */
+
+  while (n != insert) {
+    /* Check compression to insure really a dictionary file */
+    if (dictfile && ((bytes_in % MAXCOPY) == 0))
+      if (bytes_in/bytes_out < 2)
+        dictfile = 0;     /* Oops, not a dictionary file ! */
+
+    /* Update nodes in hash table lists */
+    if (full) delete_node(insert);
+    add_node(addpos);
+
+    /* If doing copy, process character, else check for new copy */
+    if (state == COPY) {
+      if (--len == 1) state = IDLE;
+    } else {
+
+      /* Get match length at next character and current char */
+      if (binary) {
+        nextlen = match(n+1,BINNEXT);
+        len = match(n,BINSEARCH);
+      } else {
+        nextlen = match(n+1,TEXTNEXT);
+        len = match(n,TEXTSEARCH);
+      }
+
+      /* If long enough and no better match at next char, start copy */
+      if (len >= MINCOPY && len >= nextlen) {
+        state = COPY;
+
+        /* Look up minimum bits to encode distance */
+        for (i = 0; i<COPYRANGES; i++) {
+          if (distance <= copymax[i]) {
+            compress(output,FIRSTCODE-MINCOPY+len+i*CODESPERRANGE);
+            output_code(output,distance-copymin[i],copybits[i]);
+            break;
+          }
+        }
+      }
+      else   /* Else output single literal character */
+        compress(output,buffer[n]);
+    }
+
+    /* Advance buffer pointers */
+    if (++n == maxsize) n = 0;
+    if (++addpos == maxsize) addpos = 0;
+
+    /* Add next input character to buffer */
+    if (c != EOF) {
+      if ((c = getc(input)) != EOF) {
+        buffer[insert++] = c;  ++bytes_in;
+      } else full = 0;
+      if (insert == maxsize) {
+        insert = 0; full = 1;
+      }
+    }
+  }
+
+  /* Output EOF code and free memory */
+  compress(output,TERMINATE);
+  flush_bits(output);
+  farfree(head); farfree(tail); farfree(succ); farfree(pred);
+  free(buffer);
+
+  return 0;
+}
+
+int main ( int argc, char **argv )
+{
+    FILE *fpGUM;
+    FILE *fpList;
+#ifdef __unix__
+	FILE *fpAttr;
+	struct stat tStat;
+#endif
+    char szLine[255], szFileName[128], szGumName[128], szFileList[128];
+
+    if (argc == 3)
+    {
+        strcpy(szGumName, argv[1]);
+        strcpy(szFileList, argv[2]);
+    }
+    else {
+        strcpy(szGumName, "archive.gum");
+        strcpy(szFileList, "files.lst");
+    }
+
+    //initialize();
+
+    printf("CHEW v0.01\n\nChewing to %s\n\n", szGumName);
+
+    fpGUM = fopen(szGumName, "wb");
+    if (!fpGUM)
+    {
+        printf("Couldn't create %s file!\n", szGumName );
+        return(0);
+    }
+
+    fpList = fopen(szFileList, "r");
+    if (!fpList)
+    {
+        fclose(fpGUM);
+        printf("Couldn't read listing file: %s\n", szFileList);
+        return(0);
+    }
+
+#ifdef __unix__
+	fpAttr = fopen("UnixAttr.DAT", "wb");
+	if (!fpAttr)
+	{
+		printf("Couldn't create UnixAttr.DAT file\n");
+		return(0);
+	}
+#endif
+
+    for (;;)
+    {
+        if (fgets(szLine, 255, fpList) == NULL)
+            break;
+
+        GetToken(szLine, szFileName);
+
+        if (szLine[0] == 0 || szLine[0] == '#')
+            continue;
+
+        if (szFileName[0] == '/')
+        {
+            // directory to create
+            AddDir(fpGUM, szFileName);
+#ifdef __unix__
+			stat(szFileName, &tStat);
+			tStat.st_mode&=511;
+			fprintf(fpAttr, "%o %s\n", tStat.st_mode, szFileName+1);
+#endif		
+        }
+        else
+		{
+            AddGUM(fpGUM, szFileName);
+#ifdef __unix__
+			stat(szFileName, &tStat);
+			tStat.st_mode&=511;
+			fprintf(fpAttr, "%o %s\n", tStat.st_mode, szFileName);
+#endif	
+		}
+    }
+
+#ifdef __unix__
+	fclose(fpAttr);
+	AddGUM(fpGUM, "UnixAttr.DAT");
+	unlink("UnixAttr.DAT");
+#endif
+
+    fclose(fpGUM);
+    fclose(fpList);
+
+    //printf("output is %ld bytes\n", TotalBytes);
+	return(0);
+}
+
+void AddGUM(FILE *fpGUM, char *pszFileName)
+{
+    char szKey[80];
+/*    char acChunk[1024]; 
+    char acEncryptedChunk[1024]; */
+    char szEncryptedName[MAX_FILENAME_LEN];
+    char *pcFrom, *pcTo;
+    FILE *fpFromFile;
+    long lFileSize, Offset1, Offset2;
+    long lCompressSize;
+    int /*BytesRead,*/ iTemp;
+    unsigned date, time;
+
+    ClearAll();
+
+    for (iTemp = 0; iTemp < MAX_FILENAME_LEN; iTemp++)
+        szEncryptedName[iTemp] = 0;
+
+    /* encrypt the filename */
+    pcFrom = pszFileName;
+    pcTo = szEncryptedName;
+
+    printf("Adding file: %s ", pszFileName);
+
+    while (*pcFrom)
+    {
+        *pcTo = *pcFrom ^ CODE1;
+        pcFrom++;
+        pcTo++;
+    }
+    *pcTo = 0;
+    //printf("Encrypted name = %s\n", szEncryptedName);
+
+    /* make key using filename */
+    sprintf(szKey, "%s%x%x", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+    //printf("key = '%s%x%x'\n", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+
+    pcTo = szKey;
+    while (*pcTo)
+    {
+        *pcTo ^= CODE2;
+        pcTo++;
+    }
+
+
+    /* write it to file */
+    fwrite(&szEncryptedName, sizeof(szEncryptedName), sizeof(char), fpGUM);
+
+    /* write filesize to psi file */
+    fpFromFile = fopen(pszFileName, "rb");
+    if (!fpFromFile)
+    {
+        printf("\aCouldn't open \"%s\"\n", pszFileName);
+        exit(0);
+    }
+    fseek(fpFromFile, 0L, SEEK_END);
+    lFileSize = ftell(fpFromFile);
+    //printf(" (%ld bytes) ", lFileSize);
+    fseek(fpFromFile, 0L, SEEK_SET);
+    fwrite(&lFileSize, sizeof(long), 1, fpGUM);
+
+    // record this offset since we come back later to write the compressed
+    // size
+    Offset1 = ftell(fpGUM);
+    fwrite(&lCompressSize, sizeof(long), 1, fpGUM);
+
+    // write datestamp
+    _dos_getftime(fileno(fpFromFile), &date, &time);
+    fwrite(&date, sizeof(unsigned short), 1, fpGUM);
+    fwrite(&time, sizeof(unsigned short), 1, fpGUM);
+
+    //=== encode here
+    encode(fpFromFile, fpGUM);
+    //printf("Packed from %ld bytes to %ld bytes\n",bytes_in,bytes_out);
+    TotalBytes += bytes_out;
+    //=== end here
+
+    // we write the compressed size now
+    Offset2 = ftell(fpGUM);
+    fseek(fpGUM, Offset1, SEEK_SET);
+    lCompressSize = bytes_out;
+    fwrite(&lCompressSize, sizeof(long), 1, fpGUM);
+    fseek(fpGUM, Offset2, SEEK_SET);
+
+    bytes_in = 0; bytes_out = 0;
+
+    fclose(fpFromFile);
+    printf("Done.\n");
+
+}
+
+void GetToken ( char *szString, char *szToken )
+{
+	char *pcCurrentPos;
+	unsigned int uCount;
+
+	/* Ignore all of line after comments or CR/LF char */
+	pcCurrentPos=(char *)szString;
+	while(*pcCurrentPos)
+	{
+		if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r')
+		{
+			*pcCurrentPos='\0';
+			break;
+		}
+		++pcCurrentPos;
+	}
+
+	/* Search for beginning of first token on line */
+	pcCurrentPos = (char *)szString;
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* If no token was found, proceed to process the next line */
+	if(!*pcCurrentPos)
+	{
+		szToken[0] = 0;
+		szString[0] = 0;
+		return;
+	}
+
+	/* Get first token from line */
+	uCount=0;
+	while(*pcCurrentPos && !isspace(*pcCurrentPos))
+	{
+		if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+		++pcCurrentPos;
+	}
+	if(uCount<=MAX_TOKEN_CHARS)
+		szToken[uCount]='\0';
+	else
+		szToken[MAX_TOKEN_CHARS]='\0';
+
+	/* Find beginning of configuration option parameters */
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* Trim trailing spaces from setting string */
+	for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+	{
+		if(isspace(pcCurrentPos[uCount]))
+		{
+			pcCurrentPos[uCount]='\0';
+		}
+		else
+		{
+			break;
+		}
+	}
+}
+
+void ClearAll ( void )
+{
+    int iTemp;
+
+    for (iTemp = 0; iTemp < _MAXCHAR+1; iTemp++)
+        left[iTemp] = right[iTemp] = 0;
+    for (iTemp = 0; iTemp < TWICEMAX+1; iTemp++)
+        up[TWICEMAX+1] = freq[TWICEMAX+1] = 0;
+
+    input_bit_count = 0;
+    input_bit_buffer = 0;
+    output_bit_count = 0;
+    output_bit_buffer = 0;
+    bytes_in = 0;
+    bytes_out = 0;
+    dictfile = 0;
+    binary = 0;
+
+    for (iTemp = 0; iTemp < COPYRANGES; iTemp++)
+        copymin[COPYRANGES] = copymax[COPYRANGES] = 0;
+
+    maxdistance = maxsize = 0;
+    distance = 0; insert = MINCOPY;
+}
+
+void AddDir(FILE *fpGUM, char *pszDirName)
+{
+    char szKey[80];
+    char szEncryptedName[MAX_FILENAME_LEN];
+    char *pcFrom, *pcTo;
+    int iTemp;
+
+    for (iTemp = 0; iTemp < MAX_FILENAME_LEN; iTemp++)
+        szEncryptedName[iTemp] = 0;
+
+    /* encrypt the filename */
+    pcFrom = pszDirName;
+    pcTo = szEncryptedName;
+
+    printf("Adding directory: %s\n", pszDirName);
+
+    while (*pcFrom)
+    {
+        *pcTo = *pcFrom ^ CODE1;
+        pcFrom++;
+        pcTo++;
+    }
+    *pcTo = 0;
+    //printf("Encrypted name = %s\n", szEncryptedName);
+
+    /* make key using filename */
+    sprintf(szKey, "%s%x%x", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+    //printf("key = '%s%x%x'\n", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+
+    pcTo = szKey;
+    while (*pcTo)
+    {
+        *pcTo ^= CODE2;
+        pcTo++;
+    }
+
+    // write dir name to file as is
+    fwrite(szEncryptedName, sizeof(szEncryptedName), 1, fpGUM);
+}
+
+#ifndef __MSDOS__
+unsigned _dos_getftime(int handle, unsigned *datep, unsigned *timep)
+{
+	struct stat file_stats;
+	struct tm *file_datetime;
+	struct tm file_dt;
+
+	if (fstat(handle, &file_stats) != 0)
+	{
+		return EBADF;
+		fputs ("fstat failed", stderr);
+		fflush (stderr);
+		exit (1);
+	}
+
+	file_datetime = localtime(&file_stats.st_mtime);
+	if (!file_datetime)
+	{
+		fputs ("localtime failed", stderr);
+		fflush (stderr);
+		exit (1);
+	}
+	memcpy (&file_dt, file_datetime, sizeof(struct tm));
+
+	*datep = 0;
+	*datep = ((file_dt.tm_mday) & 0x1f);
+	*datep |= ((file_dt.tm_mon + 1) & 0x0f) << 5;
+	*datep |= ((file_dt.tm_year - 80) & 0x7f) << 9;
+
+	*timep = 0;
+	*timep = (((file_dt.tm_sec + 2) / 2) & 0x1f);
+	*timep |= ((file_dt.tm_min) & 0x3f) << 5;
+	*timep |= ((file_dt.tm_hour) & 0x1f) << 11;
+
+	return 0;
+}
+#endif /* !__MSDOS__ */
diff --git a/src/doors/clans-devkit/chew.txt b/src/doors/clans-devkit/chew.txt
new file mode 100644
index 0000000000000000000000000000000000000000..68f43b42bd70e7858bf0ea9cece2636eefebb321
--- /dev/null
+++ b/src/doors/clans-devkit/chew.txt
@@ -0,0 +1,69 @@
+
+About Chew
+----------
+I wrote this little app to generate so-called .gum files which are basically
+like any file archive such as .ZIP or .ARJ or whatever.  Why did I do this?
+Well, 'cause it seemed cool at the time to create an installation program
+that would use an archived file.  You have to admit that back in the MS-DOS
+days, it was pretty cool to down a file and only have a data file and an
+install app.  Archiving everything beforehand also worked to protect the
+data somewhat, meaning that when you installed, all the data was pretty
+much guaranteed to be the original data.
+
+Do you need it?
+---------------
+Probably not, but I left it in here for completeness.  If you want to use
+the install program, you'll definitely need to use Chew to create the
+proper GUM files for it to decompress.
+
+How to use it
+-------------
+To use chew, just run it like this:
+
+	chew [[destination.gum] [file archive list]]
+
+The destination.gum is the name of the archive to create, such as CLANS.GUM.
+For the most part, you'll want CLANS.GUM created if you're going to be using
+the install program.  The file archive list is *another file*, not an
+actual list of files, unlike, say, PKZIP.  The file is a regular text file
+that contains a filename on each line.  It's going to be case-sensitive
+for unix, so make sure you get it right.  Here's a sample archive list
+that I actually used.
+
+    files.lst
+    ---------
+    clans.exe
+    clans.exe
+    config.exe
+    reset.exe
+    clans.pak
+    clans.ini
+    quests.ini
+    quests.hlp
+    reset.hlp
+    clanad.ans
+    clans.cfj
+    news.txt
+    /Outbound
+    route.smp
+    worldndx.smp
+    upgrade.doc
+    clans.doc
+    whatsnew.095
+    runclans.bat
+    lockout.txt
+
+Like I said, each line is just a filename.  I believe it only works with files in the
+current directory, but it might work elsewhere as well.  I've never tried.  You might
+wonder what the /Outbound means.  It's not actually a file but a way of saying
+that when the archive is expanded (by the install app), a directory called Outbound
+must be created.
+
+Finally, if you leave out both the parameters above, the defaults of "archive.gum" and
+"files.lst" will be used.  You must either use both parameters or none, you can't 
+leave only one out.  Change the code if you don't like this. :-)
+
+Credit
+------
+As it says in the code, the compression technique was lifted off sixpack.c
+by Philp G. Gage.
\ No newline at end of file
diff --git a/src/doors/clans-devkit/clandev.txt b/src/doors/clans-devkit/clandev.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7b5df9f11568f948806b20ffd900f008b03eac3c
--- /dev/null
+++ b/src/doors/clans-devkit/clandev.txt
@@ -0,0 +1,1303 @@
+Author's Note
+-------------
+This is still the same v0.11 Dev Kit that I released long ago.  I've made a
+couple of updates, mainly to the webpage and email address.  For more information
+on what the utils included in the devkit do, see the appropriate .txt files.
+
+
+
+
+
+
+
+The Clans Development Kit v0.11 by Allen Ussher
+-------------------------------------------------------------------------------
+Clans web page: http://theclans.sourceforge.net
+email:          tigertigr@yahoo.ca
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[0.0]  Table of Contents
+-------------------------------------------------------------------------------
+
+Introduction
+============
+What Can You Develop? .................................................   0.1
+How Does the System Work? .............................................   0.2
+
+Event Files
+===========
+What Are They? ........................................................   1.1
+So How Do I Make an Event File?! ......................................   1.2
+Event File Command Reference ..........................................   1.3
+
+Monsters
+========
+What Are They? ........................................................   2.1
+How Do I Make Monsters? ...............................................   2.2
+Monster Field Reference ...............................................   2.3
+
+NPCs
+====
+What Are They? ........................................................   3.1
+How Do I Make NPCs? ...................................................   3.2
+Example NPC ...........................................................   3.3
+Quote Files ...........................................................   3.4
+Using Monster Files For Stats .........................................   3.5
+NPC Field Reference ...................................................   3.6
+
+Installing Add-Ons
+==================
+NPCs ..................................................................   4.1
+Quests ................................................................   4.2
+
+Miscellaneous Tools
+===================
+MAKEPAK.EXE and PAKfiles ..............................................   5.1
+CHEW.EXE and INSTALL.EXE ..............................................   5.2
+
+Miscellaneous
+=============
+Frequently Asked Questions ............................................   6.1
+Distributing Add-Ons ..................................................   6.2
+Spell Index ...........................................................   6.3
+Item Index ............................................................   6.4
+Monster Index .........................................................   6.5
+The End ...............................................................   6.6
+
+
+
+Introduction
+===============================================================================
+
+[0.1]  What Can You Develop?
+-------------------------------------------------------------------------------
+At the moment, you are limited to developing quests, NPCs, and monsters for
+The Clans. In the future, you may be able to develop items, mine events,
+classes, races, and possibly even the strings in the game. However, a system
+must be put into place first to prevent cheat packs from being created for the
+game.  It would be far too easy to distribute the item creator and have BBSes
+in leagues build up super items. Therefore, add-ons are being limited.
+
+Ok, so you can make quests for the game.  Quests are what you go on in the
+mines (G option).  They are fairly easy to make.  Simply create an event
+file (a script) and perhaps an NPC or two and often a monster file or two.
+Modify your QUESTS.INI file and sometimes the CLANS.INI file (to add on NPCs)
+and you're set.
+
+NPCs are the characters you encounter in the mines but usually on the street
+or other locales of the village.  Generally, NPCs are made up of stats (used
+if you want them to be able to join player clans) and of quotes (used for
+conversing with them).
+
+
+[0.2]  How Does The System Work?
+-------------------------------------------------------------------------------
+The Clans uses two INI files to allow sysops to add on modules to the game.
+
+CLANS.INI is the general INI file and allows the sysop to add on NPCs, races,
+classes, items, and spells (however, only NPCs can be developed by 3rd
+parties).  It also allows one to change the language file (the strings) used
+by the engine.
+
+QUESTS.INI is the file that the game uses to figure out which quests are
+available in the game and where to find them.
+
+When creating an add-on, you must specify instructions on how to install the
+add-on.  There may be an add-on installer created soon to make the process
+easier, but for now individual lines must be added to the INI files manually.
+(Instructions on what to add to the INI files come later.)
+
+
+Event Files
+===============================================================================
+NOTE:  Because you'll be creating modules, you'll often need to reset the game,
+run daily maintenance (forced), and log in and out of the game as you please.
+Because of this, I strongly recommend you install a fresh copy of the game and
+do all your editing there.  A slap upside the head is in order if you don't!
+(Administered by YOU, the reader.)
+
+[1.1]  What Are They?
+-------------------------------------------------------------------------------
+Event files are simple scripts which are used to construct "events" that are
+encountered through quests and mine events (ex: meeting the spirit knights).
+In essence, they are small "programs" that are run by the system using its
+own compiled language.
+
+To create an event file, you'll need to edit a text file which will contain
+the script (the commands used).  Then you'll need to compile the script using
+ECOMP.EXE.  Finally, you'll probably need to test out the script by actually
+running it in The Clans itself.
+
+
+[1.2]  So How Do I Make an Event File?!
+-------------------------------------------------------------------------------
+Example 1: Getting Started
+--------------------------
+Simple.  Run your favourite text editor and load up EVENT1.EVT.  It is the
+first example of event file you'll encounter through these docs.  It's the
+simplest one you'll ever see so you better savor the moment.
+
+See how simple this example is?  Just three lines.  The lines at the
+beginning of the event file (henceforth called EF) are simply comments.  To
+create a comment on a line, place a # as the first non-space character on
+the line and put whatever comments you like after it.
+
+Ok, we come upon a couple important things.  The first "real" command line
+says "Event SimpleEvent".  This line begins the block of code and ends with
+the "End" command.  Blocks are VITAL to event files.  They make it possible to
+jump from section to section of the script and help make things modular. To
+begin a block, use the Event command followed by the name you wish to use to
+reference the block.  Here, we used SimpleEvent.  We can really use anything
+we like.  The "End" command basically tells the system to stop running the
+script.  It's not really necessary here because the system would realize it's
+at the end of the script anyway because the end of the file is reached.
+However, if you added on another block, you'd need to stick in the End command
+or else the system might "fall through" to the next block and start executing
+lines you don't want executed!
+
+Look at the line that says:
+
+        Text "Hello World!
+
+That is an EF command!  It means output the string Hello World! onto the user's
+screen.
+
+Ok, let's compile it now to see if it really works.  (Ooh, this is getting
+oh-so exciting.)  To compile an EF, you need to run ECOMP.EXE.  Run it now on
+its own in DOS without any parameters to see how it works.  As you might have
+already guessed, the first parameter is the EF in text form and the second
+parameter is the compiled form of the EF.  The compiled form is used by the
+game.  You CANNOT run an uncompiled EF!  Usually, compiled EFs are denoted
+with a .E extension.  So, let's compile our first example.  Run this in DOS:
+
+        ECOMP EVENT1.EVT EVENT1.E
+
+
+When done, you should see the following on screen:
+
+ECOMP (dk0.10) by Allen Ussher
+
+  4:  Found event SimpleEvent
+Done!
+
+0 error(s)
+
+What does the 4:... mean?  It means on line 4, an event was found.  Now, how
+do we run it?  Running it is a little tricky.  To test it, we must add it onto
+the game as a quest.  To do this, add the following line to your QUESTS.INI
+file in your Clans directory:
+
+                Name            Event1 Test
+                File            EVENT1.E
+                Index           SimpleEvent
+                Known
+
+The game now recognizes the script as a quest.  Go into the game, and run this
+"quest" to see it in action.  Note what happens after you run it. (Disregard
+the "Help not found!" message.  This is normal.)  You can try to (G)o on
+another quest but it won't let you.  Ok, then run a forced maintenance on the
+game with this:
+
+        CLANS /M
+
+Now, go back into the game.  You should be able to run it again.
+
+Example 2: Blocks
+-----------------
+Ok, now let's try the second example, EVENT2.EVT.  Look at the file.  See how
+it is made up of three blocks of commands.  Compile it and run it the same way
+you did EVENT1.  Add the following to QUESTS.INI:
+
+                Name            Event2 Test Part 1
+                File            EVENT2.E
+                Index           FirstEvent
+                Known
+
+                Name            Event2 Test Part 2
+                File            EVENT2.E
+                Index           SecondEvent
+                Known
+
+
+See how the EF is made up.  There are three blocks, but the second one begins
+with the keyword Result instead of Event.  Result simply means it is not an
+event which is started on its own.  It is used for Jumping to.  However, Jumps
+can be made to regular Event blocks and not just Result blocks.  See also how
+to Jump command is used.  Pretty self-explanatory.  Now look at the 3rd block
+of code.  It is a totally different event.  What use is this?  If you ever
+create several quests, you can stuff 'em all in one file and distribute it
+all together as one!  Also notice how the Index used in the QUESTS.INI refers
+to the event block that is run.  And what is the Known keyword used for?  It
+makes it so that the player does not need to be "told" that the quest exists.
+You'll know what I mean if you've ever chatted with an NPC and "found out"
+about a quest.  The Known keyword bypasses that requirement.
+
+Example 3: Getting Options
+--------------------------
+Ok, onto another example.  Compile and run EVENT3.EVT.  You should know how
+it's done by now.  This is how you add quests onto QUESTS.INI:
+
+        Name    <put the name of the quest here -- you name it>
+        File    <the event file containing the commands>
+        Index   <name of the event block which starts off the quest>
+        [Known] (use this if you want users to already "know" of the quest)
+
+In this case (EVENT3), the Index is called Block1 so put that in the Index
+field.  The File is EVENT3.E (the compiled event file).
+
+Now EVENT3 is a bit more complex.  You should be used to seeing the blocks by
+now.  The first new thing you might notice is the Text keyword without any
+parameters.  This means output a carriage return/line feed. The next thing you
+see is a Prompt command.  This is identical to the Text keyword except it
+doesn't add a carriage return/line feed at the end.
+
+The next new thing is the Option command.  The Option command is used to get
+keyboard input from the user (one character).  This is useful when you wish to
+list choices for the user.  The format for an Option command is this:
+
+        Option <character to input> <which block to jump to>
+
+The character to input is any keyboard character that the user can type in.
+After typing it in, the event file is executed at the block specified.
+Instead of the block name, however, you can put NextLine and this will tell
+the system to execute the next line (following the Option keywords).  Again,
+this is very simple stuff.
+
+The last new command we encounter here is the Input command.  This command
+works similarly to the Option command except that the input method is
+different and the parameters have changed:
+
+        Input <which block to jump to> <quote to use>
+
+It's hard to explain how this works so you should just go run the event and
+see it in action.  Look at the whole EF now and follow it.
+
+Example 4: Fighting
+-------------------
+Now, let's look at EVENT4.EVT.  It is an example of how to do battles in the
+game.  The Index used for the QUESTS.INI file is "FightExample".
+
+Run it first to test it out.  I'll leave the installation to you.  After you
+have tested it out, and won the battle, you'll see that you have "completed"
+the quest.  This means that even if you run maintenance, you will no longer
+be able to run the quest.  This is achieved using the new keyword DoneQuest.
+This will set the quest as "completed" by the user so that he will no longer
+be able to run it.  Look at the EVENT4.EVT file and see where it is located.
+
+How do you fight monsters using the event file?  First of all, you'll need to
+"load up" the monsters into the game's memory.  To do this, you need to use
+the AddEnemy command:
+
+        AddEnemy <monster file name> <numeric index of monster in file>
+
+The monster file name is the file containing the monsters.  You'll learn how
+to create monsters in another section.  For now, we use the basic monsters in
+the game.  They are stored in the file called /m/Output.  The /m/Output file
+is contained in the CLANS.PAK.  (See the section on MAKEPAK.EXE and PAKfiles
+for info.)  The second parameter for this command is the numeric index of
+the monster.  Monsters in the file are listed and referred to using a numeric
+index.  0 is the first monster in the file, 1 is the next, and so on.  Again,
+see the section on monsters for info.  In our example, we use /m/Output and
+monster #1 (actually, the 2nd monster, since the 0th is the 1st).  We execute
+the AddEnemy command 4 times.  This will load up the same monster 4 times into
+the games monster buffer.  The monsters will not be fought, however, until the
+Fight command is reached.  So you can continue displaying text using the Text
+command and have Jumps and whatever and the monsters will still be in the
+monster buffer (until the event file ends).  Here is the format for the Fight
+command:
+
+        Fight <WinLabel> <LoseLabel> <RunLabel>
+
+The WinLabel is the name of the block to jump to after the user wins the
+battle.  The LoseLabel is where to jump when the user loses.  The RunLabel is
+where to go if the user runs.  Simple!  There are a couple more special
+features of this command, however.  As always, you can use NextLine to execute
+the command right after the Fight command instead of jumping to another block.
+However, you can also use the STOP label.  This will cause execution of the
+EF to end.  And if you don't want the user to run away, stick in NoRun where
+the label goes.  Here are some examples:
+
+        Fight NextLine STOP NoRun
+
+The above is probably what you'll use most often.  After the fight is won by
+the user, the next line will be run.  If the user loses, the EF will be
+stopped and the NoRun tells the game to not let the user run away in battle.
+
+        Fight WinSpot YouLose STOP
+
+The following will branch off to WinSpot if the user wins, YouLose if the user
+loses and finally cease execution of the EF if the user runs away.
+
+Example 5: Flags
+----------------
+Flags are probably the most confusing aspect of EFs.  Luckily, you will likely
+never use them!  So if you want, skip this section.
+
+Flags are basically, place-holders.  They are like variables in regular
+programming languages.  However, they are capable of only two states:  TRUE or
+FALSE.  The following categories of flags are available for use:
+
+  G flags -- global flags; shared by all users, never cleared
+  H flags -- daily global flags; cleared once a day during maintenance.
+  D flags -- daily player flags; individual flags differ for each user;
+             cleared each day during maintenance.
+  P flags -- player flags; individual flags differ for each user; never
+             cleared
+  T flags -- temporary flags; cleared each time an event file is run or each
+             time a quote file is run
+
+There are 64 flags in all for each category.  The first G flag is called G0,
+the 2nd is G1, the 3rd is G2, and so on until G63.  The same applies to all
+the other categories.  Other examples of flags:  P53, D21, H16, T44.  Flags
+are tested using {}'s.  You'll have to look at EVENT5.EVT for an example.
+{}'s are used in the following manner:
+
+        {acs goes here}<keyword goes here>
+
+For instance, to display "I see you have the heavenly sword!" only if the
+user's P1 flag is set, use this:
+
+        {P1}Text "I see you have the heavenly sword!
+
+P1 on its own is treated as a boolean variable.  If whatever is between the
+{}'s is TRUE, then the command following it is executed.
+
+To display "I see you do not have the heavenly sword!" if the user's P1 flag
+is NOT set, use this:
+
+        {!P1}Text "I see you do not have the heavenly sword!
+
+!P1 means NOT P1.  So if P1 is TRUE, NOT TRUE = FALSE.  And similarly, if P1
+is FALSE, NOT FALSE = TRUE.  Therefore "I see you do not have the heavenly
+sword!" is only displayed when the user's P1 flag is NOT set.
+
+So how do we go about setting and clearing flags?  Using the SetFlag and
+ClearFlag commands of course!
+
+        SetFlag   @#
+        ClearFlag @#
+
+@ represents which category of flag to set and # represents the corresponding
+flag in the category (from 0 to 63).  To set flag T5, use SetFlag T5.  To set
+flag G60, use SetFlag G60.  To clear flag P13, use ClearFlag P13.  You get the
+idea.
+
+You can also string 'em together and test a whole bunch using | for OR, & for
+AND.  If you want to see if the user has D10 set but NOT D4, use {D10 & !D4}.
+To see if either G3 or G9 is set use {G3 | G9}.  You can use ( and ) to group
+conditons.  Here is the ultimate and if you don't get it, sorry:
+
+        { (G12 & T2) | (H9 & !D1) }
+
+That will only be true if G12 and T2 or true OR H9 is set and
+D1 is not set. Trust me, you usually will NOT need more than one flag test but
+if you want to go crazy, be my guest.
+
+Some more ACS stuff:
+
+        $xxx    -- true if user has xxx gold or more in his pocket.  To have
+                   something occur if user has at least 100 gold, do this:
+
+                        {$100}Text "You rich snob!  I wish I had even 1 gold!
+
+        Qaa     -- true if user has completed quest aa.  To run something if
+                   user has completed quest #1:
+
+                        {Q1}Text "My, aren't we the questmaster?
+
+        ^       -- always true
+        %       -- always false
+        Ryy     -- true if a roll of 100 dice yields a value greater than or
+                   equal to yy.  If you want something to happen randomly
+                   with 50/100 odds (i.e. 1 out of 2) use this:
+
+                   {R50}Text "Something odd happened!
+
+                   This is very useful to make random events occur.  An
+                   imaginary dice is rolled each time a Rxx ACS is encountered
+                   and then it is tested against the xx value.
+
+        Lyy     -- user is at mine level yy
+
+        Kyy     -- user is at mine level yy or higher
+
+
+The rest is fairly self-explanatory.  Please peruse the EVENT5.EVT file for
+additional comments.
+
+* Useful Info
+When EFs are created they usually end in a .E extension or begin with a /e/
+for PAKfiles.
+
+
+And that concludes the tutorial. :)  The next section contains all the
+commands available in EFs.
+
+
+[1.3]  Event File Command Reference
+-------------------------------------------------------------------------------
+Here is a listing of the current keywords used in the event files and their
+meanings:
+
+        Event <event name>
+
+                -- used to start an event block
+
+        End
+
+                -- used to end an event
+
+        Jump <label>
+
+                -- used to jump to another event/result block
+
+        Result <event name>
+
+                -- similar to events but in the case of "random" events,
+                   they are not considered random events -- more on this later
+
+        Text "<string>
+
+                -- this displays text to the screen.  Using a blank string
+                   causes a carriage return to be displayed:
+
+                        Text
+
+        Prompt "<string>
+
+                -- displays text to screen but without the carriage return
+
+        Pause
+
+                -- displays <pause> and waits for keyboard input
+
+        Option # <event name>
+
+                -- when an option keyword is found, the program will
+                   scan for other Option keywords following it
+                   immediately and then go into input mode.  The only
+                   allowable inputs from the user will be the Option #'s
+                   used.  For instance, if you wanted to allow only Y or
+                   N to be input after a question, use this:
+
+                   Option Y YesEvent
+                   Option N NoEvent
+
+                   The program would then accept either the Y or N key
+                   to be input. The <event name> is the name of the
+                   event block to goto if that key was pressed.  (NOTE:
+                   Upon ending the event "jumped" to, the program will
+                   stop THERE.  It will not "return" to the original
+                   event which caused the jump to occur, so don't expect
+                   it to return.)
+
+                   * special <event name>'s:
+
+                   NextLine - causes the commands immediately following
+                              the Option keywords to be executed (see
+                              quests.txt for help)
+
+                   STOP -- causes execution of event block to stop.
+
+        AddEnemy FILENAME X
+
+                -- This will add Enemy #X to the queue of enemies to fight
+                   the next time that the Fight keyword is used.
+
+        Fight <WinLabel> <LoseLabel> <RunLabel>
+
+                -- This will cause the player to fight the queue of monsters
+                   that were added using AddEnemy.  For instance, if in the
+                   data file Monsters.MON you had monster #9 as Large Flea
+                   and you wanted the player to fight 3 of these creatures,
+                   you'd use this:
+
+                   # add 3 large fleas
+                   AddEnemy monsters.mon 9
+                   AddEnemy monsters.mon 9
+                   AddEnemy monsters.mon 9
+                   # fight them now
+                   Fight NextLine STOP STOP
+
+                   <WinLabel> is the label of the event block to branch
+                   off to if the player wins the battle, of course you
+                   may use the following again:
+
+                        NextLine  -- don't branch off; go to next line
+                        STOP      -- stop execution of script
+
+                   <LoseLabel> is the label of the event block to branch off
+                   to if the player *loses* the battle.  Usually, I set this
+                   to STOP meaning stop execution of the script.  Sometimes
+                   you might want to put something here like a short
+                   description of what happens after the clan loses the battle,
+                   but DO NOT use a Fight command if the clan loses because
+                   the clan is already dead!!
+
+                   <RunLabel>  You guessed it, this is the label of where to
+                   go if the clan runs away.  Now, sometimes you don't want
+                   the clan to be able to run away.  Say they're fighting
+                   some big-ass creature and cannot escape, you'd use a label
+                   of NoRun to tell the game that the clan cannot run away.
+                   Otherwise, use a regular label as for <WinLabel> and
+                   <LoseLabel>.
+
+        Chat NPCIndex
+
+                -- chat with NPC with NPCIndex.  See the section on NPCs for
+                   info on creating NPCs.
+
+        TellQuest QuestIndex
+
+                -- A player will normally not know of any quests (except
+                   those flagged as "Known" in QUESTS.INI so they have
+                   to find out about them from someone.  You "tell" them
+                   about a quest using this command.  After telling them
+                   about quest QuestIndex, they'll be able to access the
+                   quest in the quest menu.  See my NPCQUOTE.TXT file to
+                   see it in action (even if it is a quote file and not
+                   an event file).  It's easy to use.
+
+        DoneQuest
+
+                -- When an End keyword is encountered in a quest script, the
+                   quest is not officially completed.  The End is used in a
+                   quest to signify the end of the script and not the
+                   completion of the quest.  To make it so that the user has
+                   completed the quest and cannot go on it again the next day,
+                   use this command.   Example:
+
+                                [... stuff goes here ...]
+                                Text "Congratulations, you've completed the
+                                Text "quest!
+                                DoneQuest
+                                End
+
+        AddNews "<string>
+
+                -- This adds the string to the news file
+
+        Display "<filename>
+
+                -- Displays the ANSI or ASCII file.
+
+
+        SetFlag @X
+
+                -- This sets the flag @X (@ = either T, P, D, G or H
+                -- see section on Flags & ACS
+                   Example to set flag T3:
+
+                        SetFlag T3
+
+        ClearFlag @X
+
+                -- This clears flag @X
+                -- see section on Flags & ACS
+                   Example to clear flag P9:
+
+                        ClearFlag P9
+
+        Heal [option]
+
+                -- this heals all living members of the clan
+                -- use a blank [option] to heal their HP, use heal SP to heal
+                   their skill points.  This heals HP:
+
+                        Heal
+
+                   This heals SP:
+
+                        Heal SP
+
+        TakeGold <amount>
+
+                -- decreases user's pocket gold by amount specified, it does
+                   NOT check for negatives so be careful with this.  You may
+                   want to use a {$xxx} first.
+
+        GiveGold <amount>
+
+                -- Gives the user a certain amount of gold.  Be sure not to
+                   give 'em TOO MUCH gold.  I usually give between 300 and 1000
+                   gold.
+
+        GiveXP <amount>
+
+                -- Gives all clan members (living) the amount of XP specified.
+                   A good amount is between 1 and 10 XP.
+
+        GiveItem <item name>
+
+                -- Gives the item to the clan.  See the Item Index for a
+                   listing of the items available to give.
+
+        GiveFight X
+
+                -- Gives X more monster fights to the clan.
+
+        GiveFollowers X
+
+                -- Gives X more followers to the clan.
+
+        GivePoints X
+
+                -- Gives X points to the clan.  Don't give them more than 75
+                   points at any time!
+
+
+Monsters
+===============================================================================
+
+[2.1]  What Are They?
+-------------------------------------------------------------------------------
+Monsters are those creatures that you fight in combat.  Did I really need to
+explain that? :)  Hope not.
+
+
+[2.2]  How Do I Make Monsters?
+-------------------------------------------------------------------------------
+Monsters are made using a text file (like MONSTERS.TXT) and then compiling it
+into a data file (usually ends in .MON, but it doesn't matter).  So, make your
+monster file however you want (modify MONSTERS.TXT if you like) and compile it
+like so:
+
+	MCOMP <MONSTERS.TXT> <output.mon>
+
+To make a monsters file called test.mon, use this
+
+	MCOMP monsters.txt test.mon
+
+*See MONSTERS.TXT and the next section for info on making these files.  Of
+course, you can name the .TXT file anything.  If you made MYMON.TXT, compile
+it like this:
+
+        MCOMP MYMON.TXT MYMON.MON
+
+MYMON.MON can also be any valid filename.
+
+
+[2.3]  Monster Field Reference
+-------------------------------------------------------------------------------
+Please refer to MONSTERS.TXT for examples.
+
+Name          [name of monster, max of 19 chars]
+HP            [hp of monster]
+SP            [skill points of monster]
+Difficulty    [level of monster, 1 is lowest]
+Agility       [agility]
+Difficulty    [difficulty]
+Dexterity     [dexterity]
+Strength      [strength]
+Wisdom        [wisdom]
+ArmorStr      [armorstr]
+Spell         [spell he knows, see the Spell Index for a list]
+[you can list lots of spells like this:
+
+ Spell        1
+ Spell        2
+ Spell        5
+ Spell        7
+]
+
+
+NPCs
+===============================================================================
+
+[3.1]  What Are They?
+-------------------------------------------------------------------------------
+NPCs are the characters you encounter by hitting the / key in the game's menus
+and sometimes in random encounters in the mines and other times in quests.
+You will usually chat with them and sometimes have them join your clan.
+
+
+[3.2]  How Do I Make NPCs?
+-------------------------------------------------------------------------------
+NPCs are compiled usually to a file ending with the .NPC extension.  To
+make an NPC file, create a text file similar to NPCS.TXT and use MakeNPC
+to compile it:
+
+        MakeNPC [infile.txt] [outfile.npc]
+
+To add your new NPCs to the game, add this line to your CLANS.INI file:
+
+        NpcFile [yourfile].npc
+
+*NPCs are those characters that you chat with in The Clans (/ option in
+menus).  They can also join your clan.  See NPCS.TXT for an example NPC
+file.  You should name your NPC files something unique (i.e. not CLANS.NPC)
+and end it with .NPC.  However, if using a PAKfile (see section 5.1) then
+remember to name it properly.  If you name the file /npc/MyGuys in your
+PAKfile called ADDON.PAK, use this:
+
+        NpcFile @ADDON.PAK/npc/MyGuys
+
+
+[3.3]  Example NPC
+-------------------------------------------------------------------------------
+I'll go through one example in NPCS.TXT, The Knight.  As you can see from the
+example (open up NPCS.TXT and look at it if you're not already doing so) the
+data for this NPC is comprised of several lines.  This is how NPCs are set up.
+The first line, the Index line, must always come first.  The Index is
+basically a tagword used for referencing this NPC in event files (using the
+Chat command).  It MUST be unique.  If you created an NPC and used an Index
+of simply "Charles" and another person created an NPC with an Index of
+"Charles" as well and they were both installed on the same system, there would
+be a conflict.  The first "Charles" to be found by the game would be used and
+this would be a problem for the other add-on.  So, one way to make your Index
+names unique is to start them off with your initials.  For me that would be AU
+so I might use AUKnight for The Knight's Index.  However, in this example, I
+used the underscore (_) to start off the NPC's Index.  I use this for all my
+NPCs to differentiate them from other people's NPCs.  I suggest you find a
+unique naming system of your own to prevent conflicts from occurring.
+
+The next line contains the actual name of the NPC.
+
+Next is the QuoteFile's name.  See the next section on making
+QuoteFiles.  They contain all the quotes that the character can say.  They
+must be compiled like EFs and are actually compiled using ECOMP.EXE as well.
+
+The following line is the NPCDAT line.  This is used to reference the NPC's
+actual character data (used when the NPC joins clans).  The character data is
+held in monster files.  The monster files are made up several monsters in
+sequential order and the 0th monster being the first one in the file.  For
+this example, NPCDAT is followed by 0 meaning that the 0th monster is the one
+which has the stats for this character.  The next line is the MonFile line.
+This is the name of the monster file used for the data for NPCDAT.  Here,
+NPC.MON is used so the first monster appearing there (the 0th one) will be
+used for the NPC's stats.
+
+What follows is the Loyalty line.  This is used to see if the NPC is loyal to
+the clan it belongs to at the time.  10 means the NPC is always loyal and 0
+means it is never loyal.  A higher loyalty means the NPC will be less likely
+to disclose information on the clan it is in.  10 means it NEVER will and 0
+means it ALWAYS will.
+
+The next few lines are Topics used for chatting with the NPC.  KnownTopics are
+topics that are already known when the player meets the NPC and starts
+chatting.  The regular Topics are not known and must be found out by the user
+(through the TellTopic command in the QuoteFile).  The IntroTopic line is the
+first quote shown to the user.
+
+
+[3.4]  Quote Files
+-------------------------------------------------------------------------------
+The example used for this section is NPCQUOTE.TXT.  It is an uncompiled
+QuoteFile (QF).  QFs must be compiled using ECOMP.EXE.  QFs are made the exact
+same way as EFs except that they use the keyword Topic instead of Event or
+Result.  Each topic corresponds to the listing of topics that appears in the
+raw NPC data file (ex: NPCS.TXT).
+
+There are three new commands in the QuoteFiles, however.
+
+        TellTopic <topic name>
+
+TellTopic is used to make known a topic which was previously unknown (i.e.
+created using the Topic keyword instead of the KnownTopic keyword).
+
+        EndChat
+
+EndChat is used to end the discussion altogether.  The user will be kicked
+back into the chatting menu and be able to choose another NPC to chat with.
+
+        JoinClan
+
+When executed, the NPC will join the clan using the stats specified with the
+NPCDAT and MonFile keywords.  Also, if the NPC is already in a clan, he will
+decline.
+
+* Useful Info
+When QFs are created they usually end in a .Q extension or begin with a /q/
+for PAKfiles.
+
+
+
+[3.5]  Using Monster Files for Stats
+-------------------------------------------------------------------------------
+(This section needs work.)
+Create a file similar to NPC-MON.TXT.  Compile using MCOMP.EXE as you would a
+normal monster file.  Reference the file using the MonFile keyword and the
+actual stats within the file using the NPCDAT keyword.
+
+[3.6]  NPC Field Reference
+-------------------------------------------------------------------------------
+Please see NPCS.TXT for examples.  NPC-MON.TXT is the uncompiled NPC "Monster
+file" which contains the NPCs' stats.
+
+
+Index         [index, ONE WHOLE WORD, 19 chars or less, MUST COME FIRST]
+              The index must ALWAYS appear first and then the following info
+              can be in any order.  The Index is a special tagword used to
+              reference this NPC in the game.  For instance, if you use a
+              Chat [index] command in an event file, that [index] you used
+              is compared with the indexes in this file until the it finds
+              the character.  So, to chat with The Knight, use Chat _Knight1
+              You SHOULD use some sort of naming convention since other
+              people will make NPC data files to distribute and may end up
+              using the same Index names (which causes problems when
+              referencing).  I use underscores (_) so nobody confuses mine
+              with theirs.  One suggestion is to have your initials start
+              off the NPC Index.  For me, that is AU, so for the Knight I'd
+              have AUKnight.
+
+Name          [19 chars or less]
+QuoteFile     [12 chars or less, quote filename, such as NPCQUOTE.Q]
+MonFile       [12 chars or less, .MON file used to hold NPC monsters.
+              NPC attributes such as Dexterity, Agility, etc. are held in
+              files similar to the ones used for monster combat (.MON
+              files).  See NPC-MON.TXT for an example .MON file.
+              DO NOT USE NPC.MON, that is the one used for my NPCs, use your
+              own. :)  You might use JOE.MON for instance to hold YOUR NPC
+              data.
+NPCDat        [Which monster is he in the .MON file?  0 means first monster,
+              and so on.  Again, see NPC-MON.TXT for an example.]
+Loyalty       [How loyal is this NPC, 10 means most loyal and 0 means least.
+              This is used to see if the NPC chats about his Clan if asked
+              to join the clan but he is already in a clan]
+OddsOfSeeing  [Between 0 and 100.  100% means you'll see this NPC every
+              day in the place where he wanders and 0 means never see him.
+              In between are values used for randomness.  10 means you'll
+              see him 10% of the time.  To reiterate, each day the NPCs which
+              are in town will be chosen using these values and an imaginary
+              100-sided dice.  100% means the NPC will appear every day but
+              50% means it'll appear 50% of the time.]
+Wander        [Name of menu you must go into to chat with this NPC.  Valid
+              menus:
+
+                      Street          -- main menu of The Clans
+                      Church
+                      Market
+                      Town Hall
+                      Training Hall
+                      Mine
+              ]
+IntroTopic    [Name of Topic NPC will chat about when first chatting with
+              him.]
+Topic         [Topic] [Topic Name]
+
+              This will add a topic the NPC will to the list of valid topics.
+              Topic is always used to store a topic as "unknown" and is used
+              in conjunction with TellTopic [Topic] to make the topic known.
+              [Topic] is the name of the Topic as it appears in the Quote
+              File and [Topic Name] is what it will look like to the user
+              chatting with him.
+KnownTopic    [Topic] [Topic Name]
+
+              Same as Topic but these topics are already "known" and don't
+              require TellTopic to be used.
+MaxTopics     [Num topics user is allowed to chat about.  Optional]
+HereNews      [Displays string in news file when this character appears in
+              the game that day.]
+
+
+
+
+Installing Add-Ons
+===============================================================================
+
+[4.1]  NPCs
+-------------------------------------------------------------------------------
+Adding add-on NPCs to a pre-existing game is simple.  All you need to do is
+instruct the sysop to add one line to his CLANS.INI file:
+
+        NpcFile MYNPCS.NPC
+
+Of course, replace MYNPCS.NPC with whatever file you used to hold the NPCs.
+If you used a PAK file called MYPAK.PAK to hold a file called /npc/Mine, then
+use this:
+
+        NpcFile @MYPAK.PAK/npc/Mine
+
+
+[4.2]  Quests
+-------------------------------------------------------------------------------
+Adding quests is a bit more difficult but if the sysop knows how to cut and
+paste, it's really simple.  Ask the sysop to add on to their QUESTS.INI file
+lines such as the following:
+
+                Name            Bathtub o' Blood
+                File            BLOOD.E
+                Index           Blood
+                Known
+
+See the section on event files (and quests) for information on the make-up of
+these blocks.
+
+Then, you'll probably want to create a description of your quest to display
+when it is chosen in the game (this will avert those "Help not found!"
+messages).  Here's a template of a quest's description that follows the above
+example:
+
+        ^Bathtub o' Blood
+        |12Bathtub o' Blood
+        |06----------------
+        |04Go on a rampage killing everything in sight.
+
+        |12Difficulty: Hard and BLOODY!
+        ^END
+
+This section goes into the QUESTS.HLP file.  Again, you'll likely make it up,
+place it in your installation docs and ask the sysop to cut and paste it into
+his QUESTS.HLP file.  The format is simple.  The first line with the ^ has the
+title of the quest (literally, the Name that is seen in QUESTS.INI).  And then
+you simply place all the text you wish between that line and the ^END line.
+
+Here's another example for the QUESTS.INI but this one assumes the quest
+appears in BOB.PAK and in the file named /e/Bob:
+
+                Name            Bathtub o' Blood
+                File            @BOB.PAK/e/Bob
+                Index           Blood
+                Known
+
+
+Miscellaneous Tools
+===============================================================================
+
+[5.1]  MAKEPAK.EXE and PAKfiles
+-------------------------------------------------------------------------------
+Before making a quest, you should be aware, that there may be a few files that
+must be created for the quest.  An NPC file, a monster file, and the actual
+compiled event file are what you'd normally find.  To help reduce clutter, a
+system was created to place several files in one large file called a PAKfile.
+MAKEPAK.EXE is used to create a PAKfile.
+
+When files are PAKed together, they are referenced differently in event files,
+NPC files, and INI files.  PAK files are created in the following manner:
+
+        1. Create a file listing all the files that will go into the PAKfile.
+           The file will comprise of two columns.  The first column contains
+           the files as they are named in DOS.  The second column contains the
+           files as they are named in the PAKfile.  The PAKfile file names
+           MUST begin with a forward slash (/).  For an example of a PAKfile
+           file listing, see PAK.LST.  As you can see, the file names on the
+           right side all begin with the / character and often are named using
+           a directory-like hierarchy.  However, it matters not what you name
+           the PAKfile file names (2nd column files).  For all that matters,
+           you could name a file /@!BLAH!@ if you wanted.  As long as it
+           begins with a / it'll work.  Just look at the example for a bunch
+           of wacky names at the end.  HOWEVER, please be aware that PAKfile
+           names cannot exceed 29 characters in length!  And of course, the
+           files on left column must be exist to be PAKed!
+
+        2. Next, you need to actually run MAKEPAK.EXE.  This is run in the
+           following manner:
+
+                MAKEPAK [.pak file name] [PAK file list]
+
+           So, to create a PAKfile called AI.PAK using the PAK file list
+           called PAK.LST:
+
+                MAKEPAK AI.PAK PAK.LST
+
+           After the program is run, all the files listed in PAK.LST will
+           be PAKed into the file AI.PAK and be ready to be accessed by
+           The Clans.
+
+
+Now that we have the PAK file, you need to know how to access the files in it!
+Remember that we needed to name PAK files with the / as the first character?
+This is important.  When files in The Clans are referenced with the /
+character, the CLANS.PAK file is searched and the file is found there.
+However, we need a way to differentiate between a file named /Event.E that
+exists in CLANS.PAK from a file named /Event.E that exists in ADDON.PAK.  This
+is achieved through the @ character.  Yes, it's not used just for email
+addresses any more!  To access the file /Event.E that exists in ADDON.PAK,
+we'd use the following string:
+
+        @ADDON.PAK/Event.E
+
+To access the file called /Event.E in CLANS.PAK, we do the same thing:
+
+        @CLANS.PAK/Event.E
+
+Actually, by default, if a PAKfile name is omitted, the game will use
+CLANS.PAK.  So, we could actually use the following to access /Event.E in
+CLANS.PAK:
+
+        /Event.E
+
+So what does this all boil down to?  ** WHENEVER ACCESSING PAKfile FILES
+(these terms are getting confusing) ALWAYS USE THE @ CHARACTER UNLESS YOU
+REALLY WISH TO USE THE FILE IN CLANS.PAK!!! ***  So, if you PAK an ANSI into
+your PAKfile called DRAGON.PAK, and the ANSI is called /ans/Welcome, access it
+using this string:
+
+        @DRAGON.PAK/ans/Welcome
+
+DO NOT use /ans/Welcome (without the @DRAGON.PAK) or else the game will search
+CLANS.PAK and come up empty handed.
+
+If any of this is confusing, that's fine.  You can come back and read this
+over later when you need to make a PAKfile.
+
+[5.2]  CHEW.EXE and INSTALL.EXE
+-------------------------------------------------------------------------------
+When you wish to distribute your add-on, you may wish to use my installation
+program that is provided with The Clans.  Since everyone who has installed
+already has the INSTALL.EXE program in their Clans directory, you will not
+need to add it onto your archive.  Simply explain in a readme file within your
+archive that the sysop will need to unzip the contents of the file into the
+Clans directory.  This is necessary anyway since quests will go into that
+directory.
+
+To use the INSTALL program, you will need to create a GUM file.  A GUM file is
+a compressed file containing many files (similar to a ZIP file or an ARJ)
+file.  To create a GUM file, you'll first need to create a file containing a
+list of all the files that will go into the GUM file.  This file is named
+FILES.LST (you can't use any other name).  So create a text file called
+FILES.LST and in it, place the names of all the files that will go into the
+GUM archive, one file per line.  Here is an example of such a listing:
+
+        MYQUEST.TXT
+        MYQUEST.PAK
+        SYSOP.DOC
+
+Then all you need to do is run CHEW.EXE with the name of the GUM file to
+create following it.  For instance, to create a GUM file called MYQUEST.GUM,
+you'd run it like this:
+
+        CHEW MYQUEST.GUM
+
+(If you're wondering the significance of the terms of GUM and CHEW, there is
+none.  They sounded good, ok? ;-)  This will create the MYQUEST.GUM file
+containing all the files listed in FILES.LST.  If you do not specify a GUM
+file to create, ARCHIVE.GUM will be created by default.
+
+Now that you have a GUM file, you'll need to make an INI file useable by the
+INSTALL program.  You can take a look at CLANDEV.INI (the INI file used by the
+dev. kit) and INSTALL.INI (Clans's install INI file).  EXAMPLE.INI is provided
+as an example and template.
+
+The first few lines of the INI file can simply be comments.
+
+The line that begins with a ! is used to specify the name of the GUM file to
+use when extracting files.
+
+Lines beginning with a colon (:) are treated as displayable sections.  When
+the user types in "read whatsnew", the section which starts with :whatsnew is
+displayed.  The section ends when another section beginning with another colon
+begins (the lined sections are merely used for readability).
+
+The EXAMPLE.INI lays out all the sections and you are encouraged to try it out
+by typing INSTALL EXAMPLE in DOS.
+
+The section :install.files is a listing of all the files that are in the
+archive and how to treat them if there is an existing file.  The first
+character is used to determine how the file is dealt with and the second
+parameter is the actual file name.  However, if any files are left out of the
+list but still exist in the GUM file, the user will queried if he wishes to
+extract them if a file with the same name exists.
+
+Note the following things in the file:
+
+        * the :title section is displayed first and used as a header
+        * the :goodbye section is displayed when the program is exited
+        * :install is displayed before the user chooses to install
+        * :upgrade is displayed before the user chooses to upgrade
+        * NO BLANK LINES may be used in the :install.files and :upgrade.files
+          sections.
+
+Remember, to use your INSTALL INI file, you'll need to use INSTALL.EXE and run
+it with the INI file name as the parameter.  For instance, if you created an
+INI file called MYQUEST.INI, you may install it using INSTALL MYQUEST (the
+.INI can be omitted).
+
+
+Miscellaneous
+===============================================================================
+
+[6.1]  Frequently Asked Questions
+-------------------------------------------------------------------------------
+[Q]  Is it possible for NPCs to hold items?
+[A]  Nope, not yet.
+
+[Q]  Can NPC's retain stats?
+[A]  No.
+
+[Q]  What is the meaning of life?
+[A]  Seek within.
+
+Ask me a question and I'll probably put it in this section (unless it's a
+question like "Can I borrow 5 bucks?"  No, you can't.)
+
+
+[6.2]  Distributing Add-Ons
+-------------------------------------------------------------------------------
+Now that you've created an add-on, go and distribute it!  You should send it
+to me first so I can test it out but that's not really necessary any more.
+If you have a web page up with your add-ons, email me and I'll link it from my
+page.
+
+
+[6.3]  Spell Index
+-------------------------------------------------------------------------------
+Here is a listing of all the spells currently available.  This listing is
+useful for monster creation.
+
+        1. Partial Heal                 15. Lightning Bolt
+        2. Heal                         16. Backstab
+        3. Slow                         17. FireBreath
+        4. Strength                     18. Bloodlust
+        5. Ropes                        19. Fear
+        6. Raise Undead                 20. Light Blow
+        7. Banish Undead                21. Hurricane Kick
+        8. Mystic Fireball              22. Divine Warrior
+        9. Dragon's Uppercut            23. Blind Eye
+       10. Summon Dead Warrior          24. FireBreath
+       11. Heavy Blow                   25. Rain of Terror
+       12. Death and Decay              26. Summon Khaos
+       13. Mystic Bond                  27. Summon Dragon
+       14. Holy Heal                    28. Ice Blast
+
+[6.4]  Item Index
+-------------------------------------------------------------------------------
+Here is a listing of all the items currently available.  This listing is
+useful if you wish to give item using the GiveItem command in an EF.
+
+        Shortsword              Hero's Armor
+        Broadsword              Rags
+        Axe                     Wooden Shield
+        Mace                    Iron Shield
+        Dagger                  Platinum Shield
+        Staff                   Crystal Shield
+        Wand                    Hero's Shield
+        Battle Axe              Silver Mace
+        Morning Star            Lion's Shield
+        Scythe                  Battle Axe
+        Boomerang               Flame Scroll
+        Falcon's Sword          Summon Scroll
+        Bloody Club             Banish Scroll
+        Death Axe               Summon Khaos
+        Spirit Blade            Summon Dragon
+        Wizard's Staff          Ice Blast
+        Cloth Robe              Book of Stamina
+        Leather Armor           Book of Mana
+        Chainmail Armor         Book of Healing
+        Platemail Armor         Book of Flames
+        Wooden Armor            Book of the Dead I
+        Cloth Tunic             Book of the Dead II
+        Kai Tunic               Book of Destruction
+
+[6.5]  Monster Index
+-------------------------------------------------------------------------------
+Here is a listing of all the monsters appearing in the file
+@CLANS.PAK/m/Eva (i.e. /m/Eva).  These are used for events and can be used by
+you if you wish.
+
+        0. Ghoul                        19. Man
+        1. Ghoul                        20. Man
+        2. Mad Scientist                21. Hellhound
+        3. Mad Gardener                 22. Hellhound
+        4. Orc                          23. Beast
+        5. Small Gnome                  24. gardener
+        6. Wolf Master                  25. guard
+        7. Wolf                         26. guard
+        8. Thief                        27. Businessman
+        9. Thief                        28. Thief
+       10. Thief                        29. Thief
+       11. Spirit Knight                30. Large Thief
+       12. Spirit Knight                31. Wyvern
+       13. Orc                          32. Hellhound
+       14. Orc                          33. Green Slyme
+       15. Orc                          34. Skeletal Fiend
+       16. Orc                          35. Golden Dragon
+       17. Orc                          36. Ghoul
+       18. Orc Guard
+
+To use these monsters with the AddEnemy command, use the monster file name of
+/m/Eva and follow it with the index of the monster.  For instance, to access
+the Wyvern (#31), use the following line:
+
+        AddEnemy /m/Eva 31
+
+Here are all the monsters in the mines (/m/Output):
+
+ 0. Mangy dog           63. Minotaur            126. Goblin
+ 1. Cave Dweller        64. Green Slyme         127. Troll
+ 2. Witch               65. Blue Slyme          128. Large Rat
+ 3. Giant Rat           66. Red Slyme           129. Large Spider
+ 4. Ogre                67. Troglodyte          130. Large Millipede
+ 5. Zombie              68. Serpent             131. Dark Elf
+ 6. Evil Wizard         69. Dark Mage           132. Spiked Demon
+ 7. Troll               70. Ranger              133. Skeleton
+ 8. Ratman              71. Shadow              134. Bats
+ 9. Rockman             72. Shadow Wolf         135. Caveman
+10. Beast               73. Shadow Knight       136. Mummy
+11. Grue                74. Silver Knight       137. Serpent
+12. Demon               75. Hell Hound          138. Rabid Dog
+13. Bad Boy             76. Witch               139. Ugly Man
+14. Evil Priest         77. Wyvern              140. Critter
+15. Thief               78. Fimir               141. Blue Jelly
+16. Drunken Fool        79. Demon               142. Fire Elemental
+17. Beggar              80. Orc                 143. Sprite
+18. Orc                 81. Goblin              144. Slyme
+19. Warrior             82. Gargoyle            145. Giant Maggot
+20. Dark Elf            83. Martial Artist      146. Undead Warrior
+21. Goblin              84. Small Dragon        147. Death Soldier
+22. Orc                 85. Ogre                148. Undertaker
+23. Werewolf            86. Orc                 149. Wild Man
+24. Spirit              87. Ogre                150. Dark Monk
+25. Serpent             88. Dark Knight         151. Thief
+26. Bum                 89. Wolf                152. Small Dragon
+27. Freak               90. Minotaur            153. Sorcerer
+28. Assassin            91. Blood Fiend         154. Spirit
+29. Nosferatu           92. Old Hag             155. Evil Bard
+30. Hellcat             93. Lunatic             156. Rock Beast
+31. Ugly Hag            94. Ogre                157. Brakarak
+32. Wolf                95. Boulder Beast       158. Emerald Wizard
+33. Death Knight        96. Dark Nun            159. Amundsen
+34. Shadowspawn         97. Large Spider        160. Dark Demon
+35. Hound               98. Giant Ant           161. Diablo
+36. Hobgoblin           99. Dark Knight         162. Dark Wizard
+37. Lunatic             100. Spirit             163. Slyme
+38. Giant Spider        101. Gargoyle           164. Casba Dragon
+39. Ghoul               102. Demon              165. Caveman
+40. Tarantula           103. Goblin             166. Skeletal Fiend
+41. Manticore           104. LizardMan          167. Doom Ninja
+42. Wight               105. Red Devil          168. Doom Wolf
+43. Giant Ant           106. Satyr              169. Doom Knight
+44. Wildman             107. Ghoul              170. Doom Wizard
+45. Old Hag             108. Vampire            171. Orc Knight
+46. Ninja               109. Centaur            172. Wild Dog
+47. Wildman             110. Giant Millipede    173. Fire Fiend
+48. Dark Elf            111. Werewolf           174. Green Demon
+49. Wing-Eye            112. Beast              175. Orange Demon
+50. Shadow Knight       113. Loomer             176. Violet Demon
+51. Giant Maggot        114. Black Goo          177. Red Demon
+52. Wraith              115. Golem              178. Doom Wolf
+53. Skeleton            116. Minotaur           179. Doom Knight
+54. Fire Imp            117. Cyclops            180. Hell Hound
+55. Rock Grub           118. Evil Bard          181. Hell Knight
+56. Dark Soldier        119. Evil Farmer        182. Red Dragon
+57. Lizardman           120. Murderer           183. Green Dragon
+58. Vampire             121. Giant
+59. Boulder Beast       122. Sorcerer
+60. Giant Centipede     123. Wyvern
+61. Chaos Lord          124. Warrior
+62. Skeleton            125. Black Moon Warrior
+
+
+[6.6]  The End
+-------------------------------------------------------------------------------
+This document and its accompanying files are by no means complete.  More work
+is required and I won't know what to improve unless you tell me!  Emails are
+welcome.
+
+Thanks to everyone for making this door game popular (more so than I could
+ever imagine).  And especially to those who continually bombard my emailbox
+with bug reports. :)
diff --git a/src/doors/clans-devkit/classes.dat b/src/doors/clans-devkit/classes.dat
new file mode 100644
index 0000000000000000000000000000000000000000..26b222544891816dee0256b4af1963bf299f634b
Binary files /dev/null and b/src/doors/clans-devkit/classes.dat differ
diff --git a/src/doors/clans-devkit/defines.h b/src/doors/clans-devkit/defines.h
new file mode 100644
index 0000000000000000000000000000000000000000..76e0929dff443dff40c2be16a6646827b04ea9c2
--- /dev/null
+++ b/src/doors/clans-devkit/defines.h
@@ -0,0 +1,227 @@
+#ifndef THE_CLANS__DEFINES___H
+#define THE_CLANS__DEFINES___H 1
+
+#define VERSION                 "v0.96b1"
+
+#define NTRUE			581 					// "True" used for reg info
+#define NFALSE			0
+// results of fighting
+#define FT_RAN			0
+#define FT_WON			1
+#define FT_LOST 		2
+
+#define MAX_ITEMSTAKEN	2		// allow this many items to be stolen in combat
+
+
+#define MAX_SPELLS              40
+#define NUM_ATTRIBUTES          6
+
+#define TRUE                    1
+#define FALSE                   0
+
+#define MAIL_OTHER              0           // type of mailers
+#define MAIL_BINKLEY            1
+
+#define MAX_TOKEN_CHARS         32
+#define MAX_MEMBERS             20
+#define MAX_USERS               500
+#define MAX_TOPUSERS            20
+
+#define SPECIAL_CODE    '%'
+
+#define STR_YESNO	" |0A(|0BYes|0C/no|0A) |0F"
+#define STR_NOYES	" |0A(|0Cyes/|0BNo|0A) |0F"
+#define YES 		1
+#define NO			0
+
+#define MAX_PCLASSES	15
+
+// INI Specific data
+#define MAX_NPCFILES	32
+#define MAX_SPELLFILES	8
+#define MAX_RACEFILES	8
+#define MAX_CLASSFILES	8
+#define MAX_VILLFILES	8
+#define MAX_ITEMFILES	8
+#define MAX_CLANCOMBAT	20
+
+#define MAX_LEVELS      100
+#define MAX_ITEMS_HELD	30
+
+#define MAX_BUILDINGS 32
+
+#define MAX_ITEMS		60
+#define I_ITEM			0
+#define I_WEAPON		1
+#define I_ARMOR 		2
+#define I_SHIELD		3
+#define I_SCROLL		4
+#define I_BOOK			5
+#define I_OTHER 		6
+
+// display types for GetStringChoice
+#define DT_WIDE     0
+#define DT_LONG 		1
+
+// XOR Values
+#define XOR_VILLAGE   (char)9
+#define XOR_GAME      (char)9
+#define XOR_USER      (char)9
+#define XOR_PC        (char)9
+#define XOR_MSG       (char)69
+#define XOR_ITEMS     (char)23
+#define XOR_ALLIES    (char)0xA3
+#define XOR_TRADE     (char)0x2B
+#define XOR_IBBS      (char)0x8A
+#define XOR_PACKET    (char)0x47
+#define XOR_IPS       (char)0x94
+#define XOR_TRAVEL    (char)0x3B
+#define XOR_ULIST     (char)0xCE
+#define XOR_DISBAND   (char)0x79
+
+#define ATTR_AGILITY      0
+#define ATTR_DEXTERITY    1
+#define ATTR_STRENGTH     2
+#define ATTR_WISDOM       3
+#define ATTR_ARMORSTR     4
+#define ATTR_CHARISMA     5
+
+#define SF_HEAL                 1
+#define SF_DAMAGE               2
+#define SF_MODIFY               4
+#define SF_INCAPACITATE         8
+#define SF_RAISEUNDEAD          16
+#define SF_BANISHUNDEAD         32
+
+#define MAX_ALLIES		5						// player may be in 5 alliances
+#define MAX_ALLIANCES 16
+#define MAX_ALLIANCEMEMBERS 20
+#define MAX_ALLIANCEITEMS	30
+
+/* interBBS stuff */
+#define WS_STAYING              0           /* they're staying */
+#define WS_LEAVING              1           /* they're leaving */
+#define WS_GONE                 2           /* they're leaving */
+
+// Village types
+#define V_ALL         0
+#define V_WOODLAND		1
+#define V_COASTAL     2
+#define V_WASTELAND 	3
+
+// gov't system
+#define GS_DEMOCRACY	0
+#define GS_DICTATOR 	1
+
+#define NUM_BUILDINGTYPES	10
+
+#define B_BARRACKS		0
+#define B_WALL			1
+#define B_TOWER 		2
+#define B_STEELMILL 	3
+#define B_STABLES		4
+#define B_AGENCY		5
+#define B_SECURITY		6
+#define B_GYM			7
+#define B_DEVELOPERS	8
+#define B_BUSINESS		9
+
+
+#define MAX_QUESTS		64
+#define MAX_OPTIONS 	16
+#define MAX_QUOTES		64
+#define MAX_TOPICS		10
+
+
+#define NPCS_NOTHERE	0	// status of NPC, not here -- i.e. not in town
+#define NPCS_HERE		1
+
+#define MAX_CHATSPERDAY 4
+#define MAX_MONSTERS	255 					// Number of monsters in .MON file
+
+
+/* IBBS Stuff */
+#define MAX_IBBSNODES   50
+
+
+#define WN_NONE 		0						// not a wanderer
+#define WN_CHURCH		1
+#define WN_STREET		2
+#define WN_MARKET		3
+#define WN_TOWNHALL 5
+#define WN_THALL		6
+#define WN_MINE 		8
+
+#define MAX_NPCS		16
+
+// empire owner types
+#define EO_VILLAGE		0
+#define EO_ALLIANCE 	1
+#define EO_CLAN 		2
+
+
+#define MAX_PAWNLEVEL	5
+#define MAX_WIZARDLEVEL 5
+#define MAX_MARKETLEVEL 5
+#define MAX_CHURCHLEVEL 5
+#define MAX_THALLLEVEL	4
+
+#define MAX_PACKETAGE   2       // number of days before a packet is old
+#define MAX_BACKUPAGE   4       // number of days before a backup packet is old
+
+#define MQ_AVERAGE      0
+#define MQ_GOOD         1
+#define MQ_VERYGOOD     2
+#define MQ_EXCELLENT    3
+
+// uncomment for Turbo C++
+// typedef char BOOL;
+#ifdef __unix__
+# define BOOL char			// Stops OpenDoor.h from re-defining it.
+# define FAR
+# define _INT16	short
+# define _STRCASECMP strcasecmp
+#elif defined(_MSC_VER)
+# define _INT16 short int
+# ifndef FAR
+#  define FAR
+# endif
+# define _STRCASECMP stricmp
+#else
+# define FAR far
+# define _INT16 int
+# define _STRCASECMP stricmp
+#endif
+
+typedef char __BOOL;
+
+#ifdef __GNUC__
+# define PACKED __attribute__ ((packed))
+#elif defined(_MSC_VER)
+# pragma warning(disable:4103)
+# pragma pack(1)
+#endif
+
+#ifndef PACKED
+# define PACKED
+#endif
+
+#ifdef _MSC_VER
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# define delay(x) Sleep(x)
+# define sleep(x) Sleep((x * 1000))
+# define RANDOM(x) ((x) == 0 ? 0 : (rand() % (x)))
+#endif
+
+enum Status { Dead, Unconscious, RanAway, Here };
+enum PlayerStats { stAgility, stDexterity, stStrength, stWisdom, stArmorStr };
+enum action { acAttack, acRun, acCast, acRead, acSkip, acNone };
+typedef _INT16 action;
+
+_INT16	_argc;
+char	**_argv;
+
+#define MAX_FILENAME_LEN        13
+
+#endif /* THE_CLANS__DEFINES___H */
diff --git a/src/doors/clans-devkit/ecomp.c b/src/doors/clans-devkit/ecomp.c
new file mode 100644
index 0000000000000000000000000000000000000000..fce9473f4f712097c47d4d0cebe58bde23710c60
--- /dev/null
+++ b/src/doors/clans-devkit/ecomp.c
@@ -0,0 +1,588 @@
+// Event Compiler for The Clans
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __MSDOS__
+#include <malloc.h>
+#endif /* __MSDOS__ */
+#include <string.h>
+#include <ctype.h>
+#include "defines.h"
+
+#define MAX_TOKEN_CHARS     32
+#define MAX_EVA_WORDS       34
+
+
+char *papszEvaKeyWords[MAX_EVA_WORDS] =
+{
+    "Event",
+    "Result",
+    "Text",
+    "Option",
+    "End",
+    "FalseFlag",
+    "Prompt",
+    "Fight",
+    "TellQuest",
+    "DoneQuest",
+    "AddNews",
+    "AddEnemy",
+    "ResetEnemies",
+    "Chat",
+    "SetFlag",
+    "ClearFlag",
+    "Jump",
+    "Heal",
+    "TakeGold",
+    "GiveGold",
+    "GiveXP",
+    "GiveItem",
+    "Pause",
+    "GiveFight",
+    "GiveFollowers",
+    "GivePoints",
+    "EndQ",
+    "Topic",
+    "TellTopic",
+    "JoinClan",
+    "EndChat",
+    "Input",
+    "Display",
+    "GetKey"
+};
+
+void ParseLine ( char *szString );
+void GetToken ( char *szString, char *szToken );
+void Strip ( char *szString );
+
+int main ( int argc, char *argv[] )
+{
+    FILE *fpEvent, *fpOut;
+    char szLine[255], *pcCurrentPos, szString[255], *pcBrace, szLegal[255],
+        szLabel[30], szLabel1[30], szLabel2[30], szLabel3[30];
+    char szToken[MAX_TOKEN_CHARS + 1], *Buffer, DataLength, cKey, cTemp;
+    int iKeyWord, NumEvents = -1, BufferPtr, CurLine;
+    BOOL EventInBuffer, NoMatch, CommentOn;
+    struct __attribute__((packed)) EventHeader {
+        char szName[30];
+        long EventSize;
+        BOOL Event;             // 1 = Event, 0 = Result
+    } PACKED EventHeader;
+    int Errors = 0;
+
+    printf("ECOMP (dk0.10) by Allen Ussher\n\n");
+
+    if (argc != 3)
+    {
+        printf("Format: ecomp eventfile.txt outfile.[e/q]\n");
+        exit(0);
+    }
+
+    fpEvent = fopen(argv[1], "r");
+    if (!fpEvent)
+    {
+        printf("Error opening file\n");
+        return(1);
+    }
+
+    fpOut = fopen(argv[2], "wb");
+    if (!fpOut)
+    {
+        printf("Error opening fileout\n");
+        fclose(fpEvent);
+        return(1);
+    }
+
+    // allocate memory for our huge buffer
+    Buffer = malloc(32000);
+    if (!Buffer)
+    {
+        printf("Error allocating mem\n");
+        exit(0);
+    }
+    BufferPtr = 0;          // which element are we currently pointing to?
+    EventInBuffer = FALSE;  // true if carrying event in our buffer
+
+    CurLine = 0;
+    CommentOn = FALSE;
+    for (;;)
+    {
+		/* read in a line */
+		if (fgets(szLine, 155, fpEvent) == NULL) break;
+
+        CurLine++;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+        ParseLine(pcCurrentPos);
+
+        //printf("%3d:  Processing %s\n", CurLine, pcCurrentPos);
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+
+        // see if line starts with {}'s
+		if (*pcCurrentPos == '{')
+		{
+            pcBrace = strchr(pcCurrentPos, '}');
+
+			strcpy(szLegal, (pcCurrentPos+1));
+			szLegal[ (pcBrace - pcCurrentPos) - 1 ] = 0;
+
+            // use this legal string later
+
+			// make "{xxx}yyy" into "yyy"
+			strcpy(pcCurrentPos, (pcBrace+1) );
+
+            //printf("legal is %s\nstring is %s\n", szLegal, pcCurrentPos);
+            // printf("%3d: {} used: %s\n", CurLine, szLegal);
+		}
+        else
+            szLegal[0] = 0;     // no legal string
+
+        GetToken(pcCurrentPos, szToken);
+
+        // if comment, comment on
+        if (strcmp(szToken, ">>") == 0)
+        {
+            CommentOn = !CommentOn;
+
+            if (CommentOn)
+                printf("%3d: comment begins\n", CurLine);
+            else
+                printf("%3d: comment ends\n", CurLine);
+            continue;
+        }
+
+        if (CommentOn)
+            continue;
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+        NoMatch = TRUE;
+		for(iKeyWord = 0; iKeyWord < MAX_EVA_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+			if(_STRCASECMP(szToken, papszEvaKeyWords[iKeyWord]) == 0)
+			{
+                NoMatch = FALSE;
+				/* Process token */
+				switch (iKeyWord)
+				{
+                    case 0 :    // Event
+						++NumEvents;
+
+                        // if NumEvents > 0, write old event to file
+                        if (EventInBuffer)
+                        {
+                            Buffer[BufferPtr++] = 26;
+                            Buffer[BufferPtr++] = 0;    // no szLegal either
+                            Buffer[BufferPtr++] = 0;
+
+                            // write to buffer
+                            EventInBuffer = FALSE;
+
+                            EventHeader.EventSize = BufferPtr;
+                            fwrite(&EventHeader, sizeof(struct EventHeader), 1, fpOut);
+                            fwrite(Buffer, BufferPtr, 1, fpOut);
+
+                            BufferPtr = 0;
+                        }
+
+                        // initialize this new event
+                        EventInBuffer = TRUE;
+
+                        EventHeader.Event = TRUE;
+                        memset(EventHeader.szName, 0, 30);
+                        strcpy(EventHeader.szName, pcCurrentPos);
+                        printf("%3d: Found event %s\n", CurLine, pcCurrentPos);
+						break;
+                    case 1 :    // Result
+                    case 27:    // Topic
+						++NumEvents;
+
+                        // if NumEvents > 0, write old event to file
+                        if (EventInBuffer)
+                        {
+                            Buffer[BufferPtr++] = 26;
+                            Buffer[BufferPtr++] = 0;    // no szLegal either
+                            Buffer[BufferPtr++] = 0;
+
+
+                            // write to buffer
+                            EventInBuffer = FALSE;
+
+                            EventHeader.EventSize = BufferPtr;
+                            fwrite(&EventHeader, sizeof(struct EventHeader), 1, fpOut);
+                            fwrite(Buffer, BufferPtr, 1, fpOut);
+
+                            BufferPtr = 0;
+                        }
+
+                        // initialize this new event
+                        EventInBuffer = TRUE;
+
+                        EventHeader.Event = FALSE;
+                        memset(EventHeader.szName, 0, 30);
+                        strcpy(EventHeader.szName, pcCurrentPos);
+
+						break;
+                    case 2 :    // Text
+                    case 6 :    // Prompt
+                    case 10 :   // AddNews
+                    case 32 :   // Display
+                        // put command in buffer
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+                        if (*pcCurrentPos == 0)
+                        {
+                            // no text, data length is 1 -- just a '\0'
+                            DataLength = 1;
+                            Buffer[ BufferPtr++ ] = DataLength;
+                            Buffer[ BufferPtr++ ] = 0;
+                        }
+                        else
+                        {
+                            /* must skip the " which starts the line */
+                            DataLength = strlen(&pcCurrentPos[1]) + 1;
+
+                            Buffer[ BufferPtr++ ] = DataLength;
+                            strcpy(&Buffer[ BufferPtr ], &pcCurrentPos[1]);
+                            BufferPtr += (strlen(&pcCurrentPos[1]) + 1);
+                        }
+						break;
+                    case 3  :   // Option
+                    case 33  :  // GetKey
+                        // put command in buffer
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+                        if (pcCurrentPos[0] == '~')
+                            cKey = 13;  // Enter
+                        else
+                            cKey = pcCurrentPos[0];
+
+                        GetToken(&pcCurrentPos[1], szLabel);
+
+                        DataLength = sizeof(char) + strlen(szLabel) + sizeof(char);
+
+                        Buffer[ BufferPtr++ ] = DataLength;
+                        Buffer[ BufferPtr++ ] = cKey;
+                        strcpy(&Buffer[ BufferPtr ], szLabel);
+                        BufferPtr += (strlen(szLabel) + sizeof(char));
+
+                        //printf("%3d:  option:  %c - %s\n", CurLine, cKey, szLabel);
+                        break;
+                    case 7  :   // Fight
+                        // put command in buffer
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+
+						GetToken(pcCurrentPos, szLabel1);
+						GetToken(pcCurrentPos, szLabel2);
+						GetToken(pcCurrentPos, szLabel3);
+
+                        // write datalength
+                        Buffer[ BufferPtr++ ] = strlen(szLabel1) + strlen(szLabel2) +
+                            strlen(szLabel3) + sizeof(char) * 3;
+
+                        // write to file the 3 labels
+                        Buffer[ BufferPtr++ ] = strlen(szLabel1) + 1;
+                        strcpy(&Buffer[ BufferPtr ], szLabel1);
+                        BufferPtr += (strlen(szLabel1) + 1);
+
+                        Buffer[ BufferPtr++ ] = strlen(szLabel2) + 1;
+                        strcpy(&Buffer[ BufferPtr ], szLabel2);
+                        BufferPtr += (strlen(szLabel2) + 1);
+
+                        Buffer[ BufferPtr++ ] = strlen(szLabel3) + 1;
+                        strcpy(&Buffer[ BufferPtr ], szLabel3);
+                        BufferPtr += (strlen(szLabel3) + 1);
+                        break;
+                    case 8  :   // TellQuest
+                    case 13 :   // Chat
+                    case 14 :   // SetFlag
+                    case 15 :   // ClearFlag
+                    case 16 :   // Jump
+                    case 17 :   // Heal
+                    case 18 :   // TakeGold
+                    case 19 :   // GiveGold
+                    case 20 :   // GiveXP
+                    case 21 :   // GiveItem
+                    case 23 :   // GiveFight
+                    case 24 :   // GiveFollowers
+                    case 25 :   // GivePoints
+                    case 28 :   // TellTopic
+                        // put command in buffer
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+                        DataLength = strlen(pcCurrentPos) + 1;
+
+                        Buffer[ BufferPtr++ ] = DataLength;
+                        strcpy(&Buffer[ BufferPtr ], pcCurrentPos);
+                        BufferPtr += (strlen(pcCurrentPos) + 1);
+						break;
+                    case 4  :   // End
+                    case 9  :   // DoneQuest
+                    case 22 :   // Pause
+                    case 29 :   // JoinClan
+                    case 30 :   // EndChat
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+                        // no datalength, so put 0
+                        Buffer[ BufferPtr++ ] = 0;
+                        break;
+                    case 11 :   // AddEnemy
+                        // put command in buffer
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+                        // get monster filename
+                        GetToken(pcCurrentPos, szLabel);        // filename
+                        cTemp = atoi(pcCurrentPos);             // # of beast
+                        //printf("%3d:  addenemy %s %d\n", CurLine, szLabel, cTemp);
+
+                        DataLength = strlen(szLabel) + 2;
+
+                        Buffer[ BufferPtr++ ] = DataLength;
+                        strcpy(&Buffer[ BufferPtr ], szLabel);
+                        BufferPtr += (strlen(szLabel) + 1);
+                        Buffer[ BufferPtr++ ] = cTemp;
+                        break;
+                    case 26 :   // EndQ
+                        if (EventInBuffer)
+                        {
+                            // put an EndQ command there
+                            Buffer[BufferPtr++] = 26;
+                            Buffer[BufferPtr++] = 0;    // no szLegal either
+                            Buffer[BufferPtr++] = 0;
+
+                            // write to buffer
+                            EventInBuffer = FALSE;
+
+                            EventHeader.EventSize = BufferPtr;
+                            fwrite(&EventHeader, sizeof(struct EventHeader), 1, fpOut);
+                            fwrite(Buffer, BufferPtr, 1, fpOut);
+                        }
+                        break;
+                    case 31 :   // Input
+                        // put command in buffer
+                        Buffer[ BufferPtr++ ] = iKeyWord;
+
+                        // put szLegal in buffer
+                        Buffer[ BufferPtr ] = strlen(szLegal) + 1;
+                        BufferPtr++;
+                        strcpy(&Buffer[BufferPtr], szLegal);
+                        BufferPtr += ( strlen(szLegal) + 1 );
+
+                        GetToken(pcCurrentPos, szLabel);
+                        strcpy(szString, pcCurrentPos);
+
+                        DataLength = strlen(szLabel) + strlen(szString) + 2*sizeof(char);
+
+                        Buffer[ BufferPtr++ ] = DataLength;
+
+                        // write length of szLabel
+                        Buffer[ BufferPtr++ ] = strlen(szLabel) + sizeof(char);
+
+                        // write label
+                        strcpy(&Buffer[ BufferPtr ], szLabel);
+                        // increment pointer
+                        BufferPtr += (strlen(szLabel) + sizeof(char));
+
+                        Buffer[ BufferPtr++ ] = strlen(szString) + sizeof(char);
+                        strcpy(&Buffer[ BufferPtr ], szString);
+                        BufferPtr += (strlen(szString) + sizeof(char));
+
+                        //printf("%3d:  option:  %c - %s\n", CurLine, cKey, szLabel);
+                        break;
+				}
+				break;
+			}
+		}
+        if (NoMatch)
+        {
+            printf("%3d:  Invalid command %s\n", CurLine, szToken);
+            Errors++;
+        }
+    }
+
+    // if event in memory, flush it to file
+    if (EventInBuffer)
+    {
+        Buffer[BufferPtr++] = 26;
+        Buffer[BufferPtr++] = 0;    // no szLegal either
+        Buffer[BufferPtr++] = 0;
+
+        // write to buffer
+        EventInBuffer = FALSE;
+
+        EventHeader.EventSize = BufferPtr;
+        fwrite(&EventHeader, sizeof(struct EventHeader), 1, fpOut);
+        fwrite(Buffer, BufferPtr, 1, fpOut);
+
+        BufferPtr = 0;
+    }
+    free(Buffer);
+
+    fclose(fpOut);
+    fclose(fpEvent);
+
+    printf("Done!\n\n%d error(s)\n\n", Errors);
+	return(0);
+}
+
+void ParseLine ( char *szString)
+{
+	char *pcCurrentPos;
+    BOOL MetQuote = FALSE;
+
+	pcCurrentPos = szString;
+
+	while(*pcCurrentPos)
+	{
+        if (*pcCurrentPos == '"')
+            MetQuote = !MetQuote;
+
+		if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+		   || *pcCurrentPos == '#')
+		{
+            if (!MetQuote)
+            {
+                *pcCurrentPos='\0';
+                break;
+            }
+		}
+		++pcCurrentPos;
+	}
+
+	pcCurrentPos = szString;
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	strcpy(szString, pcCurrentPos);
+
+	// parse second time to get rid of comment's end
+    Strip(szString);
+}
+
+void GetToken ( char *szString, char *szToken )
+{
+	char *pcCurrentPos;
+	unsigned int uCount;
+
+	/* Ignore all of line after comments or CR/LF char */
+	pcCurrentPos=(char *)szString;
+	while(*pcCurrentPos)
+	{
+		if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r')
+		{
+			*pcCurrentPos='\0';
+			break;
+		}
+		++pcCurrentPos;
+	}
+
+	/* Search for beginning of first token on line */
+	pcCurrentPos = (char *)szString;
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* If no token was found, proceed to process the next line */
+	if(!*pcCurrentPos)
+	{
+		szToken[0] = 0;
+		szString[0] = 0;
+		return;
+	}
+
+	/* Get first token from line */
+	uCount=0;
+	while(*pcCurrentPos && !isspace(*pcCurrentPos))
+	{
+		if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+		++pcCurrentPos;
+	}
+	if(uCount<=MAX_TOKEN_CHARS)
+		szToken[uCount]='\0';
+	else
+		szToken[MAX_TOKEN_CHARS]='\0';
+
+	/* Find beginning of configuration option parameters */
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* Trim trailing spaces from setting string */
+	for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+	{
+		if(isspace(pcCurrentPos[uCount]))
+		{
+			pcCurrentPos[uCount]='\0';
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	strcpy(szString, pcCurrentPos);
+}
+
+void Strip ( char *szString )
+{
+    char NewString[255], *pcCh;
+
+	pcCh = szString;
+
+	/* get rid of spacing */
+	while ( isspace(*pcCh))
+		pcCh++;
+
+	strcpy(NewString, pcCh);
+
+	/* get rid of trailing spaces */
+	pcCh = &NewString[ strlen(NewString) - 1];
+
+	while (isspace(*pcCh))
+		pcCh--;
+
+	pcCh++;
+	*pcCh = 0;
+
+	strcpy(szString, NewString);
+
+}
diff --git a/src/doors/clans-devkit/ecomp.txt b/src/doors/clans-devkit/ecomp.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e41dcb2f20fae6eb0122f761e496dae9f8930765
--- /dev/null
+++ b/src/doors/clans-devkit/ecomp.txt
@@ -0,0 +1,16 @@
+What's this now?
+----------------
+ecomp is used to generate event files.  See clandev.txt for info on
+event files and creating them.
+
+How to use it
+-------------
+For more information on how to run ecomp, see clandev.txt.  But if
+you're too lazy to load up the file, here's how to run ecomp quickly:
+
+       ecomp source-event.txt destination-event.e
+
+It's standard procedure to name "compiled" events as .e files, but
+it's just a standard.  You can name them whatever.  Additionally,
+source event files /were/ called .evt for some reason, but I recommend
+just naming them .txt for simplicity.
diff --git a/src/doors/clans-devkit/install.c b/src/doors/clans-devkit/install.c
new file mode 100644
index 0000000000000000000000000000000000000000..a4d2951dffe9efbc8089c9046cc0584e5d1c8bde
--- /dev/null
+++ b/src/doors/clans-devkit/install.c
@@ -0,0 +1,1965 @@
+// ONE TO USE!!
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef __MSDOS__
+# include <dos.h>
+# include <conio.h>
+#elif defined(_WIN32)
+# include <windows.h>
+# include <conio.h>
+# include <sys/utime.h>
+# include <direct.h> /* mkdir */
+#elif defined(__unix__)
+# include <curses.h>
+# include <sys/time.h>
+# include <unistd.h>
+#endif /* __MSDOS__ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include "defines.h" /* _STRCASECMP */
+
+#ifndef __MSDOS__
+#define far 
+#endif /* !__MSDOS__ */
+
+#define STARTROW    9           // start at row 5
+#ifdef __MSDOS__
+#define COLOR	0xB800
+#define MONO	0xB000
+#endif /* __MSDOS__ */
+#define CODE1           0x7D
+#define CODE2           0x1F
+#define MAX_FILES   75          // say 75 files is most in .GUM file for now
+
+#define SKIP        0           // skip if file exists
+#define OVERWRITE   1           // always overwrite
+#define QUERY       2           // ask user if he wishes to overwrite
+
+#define ALWAYS  2
+#define TRUE    1
+#define FALSE   0
+#define MAX_TOKEN_CHARS 32
+
+
+
+#define TEXTSEARCH 1000   /* Max strings to search in text file */
+#define BINSEARCH   200   /* Max strings to search in binary file */
+#define TEXTNEXT     50   /* Max search at next character in text file */
+#define BINNEXT      20   /* Max search at next character in binary file */
+#define MAXFREQ    2000   /* Max frequency count before table reset */ 
+#define MINCOPY       3   /* Shortest string copy length */
+#define MAXCOPY      64   /* Longest string copy length */
+#define SHORTRANGE    3   /* Max distance range for shortest length copy */
+#define COPYRANGES    6   /* Number of string copy distance bit ranges */
+short copybits[COPYRANGES] = {4,6,8,10,12,14};   /* Distance bits */
+
+#define CODESPERRANGE (MAXCOPY - MINCOPY + 1)
+int copymin[COPYRANGES], copymax[COPYRANGES];
+int maxdistance, maxsize;
+int distance, insert = MINCOPY, dictfile = 0, binary = 0;
+
+#define NIL -1                    /* End of linked list marker */
+#define HASHSIZE 16384            /* Number of entries in hash table */
+#define HASHMASK (HASHSIZE - 1)   /* Mask for hash key wrap */
+short far *head, far *tail;       /* Hash table */
+short far *succ, far *pred;       /* Doubly linked lists */
+unsigned char *buffer;            /* Text buffer */
+
+/* Define hash key function using MINCOPY characters of string prefix */
+#define getkey(n) ((buffer[n] ^ (buffer[(n+1)%maxsize]<<4) ^ \
+                   (buffer[(n+2)%maxsize]<<8)) & HASHMASK)
+
+/* Adaptive Huffman variables */
+#define TERMINATE 256             /* EOF code */
+#define FIRSTCODE 257             /* First code for copy lengths */
+#define _MAXCHAR (FIRSTCODE+COPYRANGES*CODESPERRANGE-1)
+#define SUCCMAX (_MAXCHAR+1)
+#define TWICEMAX (2*_MAXCHAR+1)
+#define ROOT 1
+short left[_MAXCHAR+1], right[_MAXCHAR+1];  /* Huffman tree */
+short up[TWICEMAX+1], freq[TWICEMAX+1];
+
+/*** Bit packing routines ***/
+
+int input_bit_count = 0;           /* Input bits buffered */
+int input_bit_buffer = 0;          /* Input buffer */
+int output_bit_count = 0;          /* Output bits buffered */
+int output_bit_buffer = 0;         /* Output buffer */
+long bytes_in = 0, bytes_out = 0;  /* File size counters */
+
+
+
+void GetGumName ( void );
+void ListFiles ( void );
+void kputs ( char *szString );
+int GetGUM(FILE *fpGUM);
+void install ( void );
+char get_answer( char *szAllowableChars );
+BOOL FileExists ( char *szFileName );
+void InitFiles ( char *szFileName );
+int WriteType ( char *szFileName );
+void Extract ( char *szExtractFile, char *szNewName );
+void upgrade( void );
+void ClearAll ( void );
+__inline void get_screen_dimension (int *lines, int *width);
+void gotoxy (int x, int y);
+
+#ifdef __MSDOS__
+char far *VideoMem;
+long y_lookup[25];
+#endif /* __MSDOS__ */
+int Overwrite = FALSE;
+char szGumName[25], szIniName[25];
+
+struct FileInfo
+{
+    char szFileName[14];
+    int WriteType;
+} FileInfo[MAX_FILES];
+
+#ifdef __unix__
+#define MKDIR(dir)              mkdir(dir,0777)
+short curses_color(short color);
+#else
+#define MKDIR(dir)              mkdir(dir)
+#endif
+
+#ifndef __MSDOS__
+unsigned short _dos_setftime (int, unsigned short, unsigned short);
+#endif /* !__MSDOS__ */
+
+void reset_attribute (void)
+{
+#ifdef __MSDOS__
+	textattr (7);
+#elif defined(_WIN32)
+	SetConsoleTextAttribute (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		(WORD)(FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED));
+#elif defined(__unix__)
+	attrset(A_NORMAL|COLOR_PAIR(0));
+	refresh();
+#endif
+}
+
+/* Write one bit to output file */
+void output_bit(output,bit)
+  FILE *output;
+  int bit;
+{
+  output_bit_buffer <<= 1;
+  if (bit) output_bit_buffer |= 1;
+  if (++output_bit_count == 8) {
+    putc(output_bit_buffer,output);
+    output_bit_count = 0;
+    ++bytes_out;
+  }
+}
+
+/* Read a bit from input file */
+int input_bit(input)
+  FILE *input;
+{
+  int bit;
+
+  if (input_bit_count-- == 0) {
+    input_bit_buffer = getc(input);
+    if (input_bit_buffer == EOF) {
+      printf(" UNEXPECTED END OF FILE\n");
+	  reset_attribute ();
+      exit(1);
+    }
+    ++bytes_in;
+    input_bit_count = 7;
+  }
+  bit = (input_bit_buffer & 0x80) != 0;
+  input_bit_buffer <<= 1;
+  return(bit);
+}
+
+/* Write multibit code to output file */
+void output_code(output,code,bits)
+  FILE *output;
+  int code,bits;
+{
+  int i;
+
+  for (i = 0; i<bits; i++) {
+    output_bit(output,code & 0x01);
+    code >>= 1;
+  }
+}
+
+/* Read multibit code from input file */
+int input_code(input,bits)
+  FILE *input;
+  int bits;
+{
+  int i, bit = 1, code = 0;
+
+  for (i = 0; i<bits; i++) {
+    if (input_bit(input)) code |= bit;
+    bit <<= 1;
+  }
+  return(code);
+}
+
+/* Flush any remaining bits to output file before closing file */
+void flush_bits(output)
+  FILE *output;
+{
+  if (output_bit_count > 0) {
+    putc((output_bit_buffer << (8-output_bit_count)),output);
+    ++bytes_out;
+  }
+}
+
+/*** Adaptive Huffman frequency compression ***/
+
+/* Data structure based partly on "Application of Splay Trees
+   to Data Compression", Communications of the ACM 8/88 */
+
+/* Initialize data for compression or decompression */
+void initialize()
+{
+  int i, j;
+
+  /* Initialize Huffman frequency tree */
+  for (i = 2; i<=TWICEMAX; i++) {
+    up[i] = i/2;
+    freq[i] = 1;
+  }
+  for (i = 1; i<=_MAXCHAR; i++) {
+    left[i] = 2*i;
+    right[i] = 2*i+1;
+  }
+
+  /* Initialize copy distance ranges */
+  j = 0;
+  for (i = 0; i<COPYRANGES; i++) {
+    copymin[i] = j;
+    j += 1 << copybits[i];
+    copymax[i] = j - 1;
+  }
+  maxdistance = j - 1;
+  maxsize = maxdistance + MAXCOPY;
+}
+
+/* Update frequency counts from leaf to root */
+void update_freq(a,b)
+  int a,b;
+{
+  do {
+    freq[up[a]] = freq[a] + freq[b];
+    a = up[a];
+    if (a != ROOT) {
+      if (left[up[a]] == a) b = right[up[a]];
+      else b = left[up[a]];
+    }
+  } while (a != ROOT);
+
+  /* Periodically scale frequencies down by half to avoid overflow */
+  /* This also provides some local adaption and better compression */
+  if (freq[ROOT] == MAXFREQ)
+    for (a = 1; a<=TWICEMAX; a++) freq[a] >>= 1;
+}
+
+/* Update Huffman model for each character code */
+void update_model(code)
+  int code;
+{
+  int a, b, c, ua, uua;
+
+  a = code + SUCCMAX;
+  ++freq[a];
+  if (up[a] != ROOT) {
+    ua = up[a];
+    if (left[ua] == a) update_freq(a,right[ua]);
+    else update_freq(a,left[ua]);
+    do {
+      uua = up[ua];
+      if (left[uua] == ua) b = right[uua];
+      else b = left[uua];
+
+      /* If high freq lower in tree, swap nodes */
+      if (freq[a] > freq[b]) {
+        if (left[uua] == ua) right[uua] = a;
+        else left[uua] = a;
+        if (left[ua] == a) {
+          left[ua] = b; c = right[ua];
+        } else {
+          right[ua] = b; c = left[ua];
+        }
+        up[b] = ua; up[a] = uua;
+        update_freq(b,c); a = b;
+      }
+      a = up[a]; ua = up[a];
+    } while (ua != ROOT);
+  }
+}
+
+/* Compress a character code to output stream */
+void compress(output,code)
+  FILE *output;
+  int code;
+{
+  int a, sp = 0;
+  int stack[50];
+
+  a = code + SUCCMAX;
+  do {
+    stack[sp++] = (right[up[a]] == a);
+    a = up[a];
+  } while (a != ROOT);
+  do {
+    output_bit(output,stack[--sp]);
+  } while (sp);
+  update_model(code);
+}
+
+/* Uncompress a character code from input stream */
+int uncompress(input)
+  FILE *input;
+{
+  int a = ROOT;
+
+  do {
+    if (input_bit(input)) a = right[a];
+    else a = left[a];
+  } while (a <= _MAXCHAR);
+  update_model(a-SUCCMAX);
+  return(a-SUCCMAX);
+}
+
+/*** Hash table linked list string search routines ***/
+
+/* Add node to head of list */
+void add_node(n)  
+  int n;
+{
+  int key;
+
+  key = getkey(n);
+  if (head[key] == NIL) {
+    tail[key] = n;
+    succ[n] = NIL;
+  } else {
+    succ[n] = head[key];
+    pred[head[key]] = n;
+  }
+  head[key] = n;
+  pred[n] = NIL;
+}
+
+/* Delete node from tail of list */
+void delete_node(n)
+  int n;
+{
+  int key;
+
+  key = getkey(n);
+  if (head[key] == tail[key])
+    head[key] = NIL;
+  else {
+    succ[pred[tail[key]]] = NIL;
+    tail[key] = pred[tail[key]];
+  }
+}
+
+/* Find longest string matching lookahead buffer string */
+int match(n,depth)
+  int n,depth;
+{
+  int i, j, index, key, dist, len, best = 0, count = 0;
+
+  if (n == maxsize) n = 0;
+  key = getkey(n);
+  index = head[key];
+  while (index != NIL) {
+    if (++count > depth) break;     /* Quit if depth exceeded */
+    if (buffer[(n+best)%maxsize] == buffer[(index+best)%maxsize]) {
+      len = 0;  i = n;  j = index;
+      while (buffer[i]==buffer[j] && len<MAXCOPY && j!=n && i!=insert) {
+        ++len;
+        if (++i == maxsize) i = 0;
+        if (++j == maxsize) j = 0;
+      }
+      dist = n - index;
+      if (dist < 0) dist += maxsize;
+      dist -= len;
+      /* If dict file, quit at shortest distance range */
+      if (dictfile && dist > copymax[0]) break;
+      if (len > best && dist <= maxdistance) {     /* Update best match */
+        if (len > MINCOPY || dist <= copymax[SHORTRANGE+binary]) {
+          best = len; distance = dist;
+        }
+      }
+    }
+    index = succ[index];
+  }
+  return(best);
+}
+
+/*** Finite Window compression routines ***/
+
+#define IDLE 0    /* Not processing a copy */
+#define COPY 1    /* Currently processing copy */
+
+/* Check first buffer for ordered dictionary file */
+/* Better compression using short distance copies */
+void dictionary()
+{
+  int i = 0, j = 0, k, count = 0;
+
+  /* Count matching chars at start of adjacent lines */
+  while (++j < MINCOPY+MAXCOPY) {
+    if (buffer[j-1] == 10) {
+      k = j;
+      while (buffer[i++] == buffer[k++]) ++count;
+      i = j;
+    }
+  }
+  /* If matching line prefixes > 25% assume dictionary */
+  if (count > (MINCOPY+MAXCOPY)/4) dictfile = 1;
+}
+
+/* Decode file from input to output */
+void decode(input,output)
+  FILE *input,*output;
+{
+  int c, i, j, k, dist, len, n = 0, index;
+  int poll = 0;
+
+  initialize();
+  buffer = (unsigned char *) malloc(maxsize*sizeof(unsigned char));
+  if (buffer == NULL) {
+    printf("Error allocating memory\n");
+	reset_attribute ();
+    exit(1);
+  }
+  while ((c = uncompress(input)) != TERMINATE) {
+    poll++;
+    if (poll == 2400)
+    {
+        poll = 0;
+        kputs(".");
+    }
+    if (c < 256) {     /* Single literal character ? */
+      putc(c,output);
+      ++bytes_out;
+      buffer[n++] = c;
+      if (n == maxsize) n = 0;
+    } else {            /* Else string copy length/distance codes */
+      index = (c - FIRSTCODE)/CODESPERRANGE;
+      len = c - FIRSTCODE + MINCOPY - index*CODESPERRANGE;
+      dist = input_code(input,copybits[index]) + len + copymin[index];
+      j = n; k = n - dist;
+      if (k < 0) k += maxsize;
+      for (i = 0; i<len; i++) {
+        putc(buffer[k],output);  ++bytes_out;
+        buffer[j++] = buffer[k++];
+        if (j == maxsize) j = 0;
+        if (k == maxsize) k = 0;
+      }
+      n += len;
+      if (n >= maxsize) n -= maxsize;
+    }
+  }
+  free(buffer);
+}
+
+void Display( char *szFileName )
+{
+    FILE *fpInput;
+    char szString[300];
+    BOOL FileFound = FALSE, Done = FALSE;
+    int CurLine;
+
+    fpInput = fopen(szIniName, "r");
+    if (!fpInput)   return;
+
+    // search for filename
+    for (;;)
+    {
+        if (!fgets(szString, 300, fpInput))
+            break;
+
+        // get rid of \n and \r
+		while (szString[ strlen(szString) - 1] == '\n' || szString[ strlen(szString) - 1] == '\r')
+			szString[ strlen(szString) - 1] = 0;
+
+        if (szString[0] == ':' && _STRCASECMP(szFileName, &szString[1]) == 0)
+        {
+            FileFound = TRUE;
+            break;
+        }
+    }
+
+    if (FileFound == FALSE)
+    {
+        fclose(fpInput);
+
+        // search dos for file
+        fpInput = fopen(szFileName, "r");
+        if (!fpInput)
+        {
+            kputs("|04File to display not found\n");
+            return;
+        }
+    }
+    // print file
+    CurLine = 0;
+    while (!Done)
+    {
+        if (!fgets(szString, 300, fpInput))
+            break;
+
+        if (szString[0] == ':')
+            break;
+
+        kputs(szString);
+        CurLine++;
+
+        if (CurLine == (25-STARTROW-1))
+        {
+            CurLine = 0;
+            kputs("[more]");
+            if (toupper(getch()) == 'Q')
+                Done = TRUE;
+            kputs("\r       \r");
+        }
+    }
+
+    fclose(fpInput);
+}
+
+#ifdef _WIN32
+void display_win32_error (void)
+{
+	LPVOID msg;
+
+	FormatMessageA (
+		FORMAT_MESSAGE_FROM_SYSTEM|
+		FORMAT_MESSAGE_ALLOCATE_BUFFER|
+		FORMAT_MESSAGE_IGNORE_INSERTS,
+		NULL,
+		GetLastError(),
+		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		(LPSTR)&msg,
+		0,
+		NULL);
+
+	fprintf (stderr, "System Error: %s\n", (LPSTR)msg);
+	fflush (stderr);
+
+	LocalFree (msg);
+}
+#endif
+
+void ScrollUp ( void )
+{
+#ifdef __MSDOS__
+	asm {
+		mov al,1	// number of lines
+        mov ch,STARTROW // starting row
+		mov cl,0	// starting column
+		mov dh, 24	// ending row
+		mov dl, 79	// ending column
+		mov bh, 7	// color
+		mov ah, 6
+		int 10h 	// do the scroll
+	}
+#elif defined(_WIN32)
+	HANDLE handle_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	SMALL_RECT scroll_rect;
+	COORD top_left = { 0, 0 };
+	CHAR_INFO char_info;
+
+	GetConsoleScreenBufferInfo(handle_stdout, &screen_buffer);
+	scroll_rect.Top = 1;
+	scroll_rect.Left = 0;
+	scroll_rect.Bottom = screen_buffer.dwSize.Y;
+	scroll_rect.Right = screen_buffer.dwSize.X;
+
+	char_info.Attributes = screen_buffer.wAttributes;
+	char_info.Char.UnicodeChar = (TCHAR)' ';
+
+	if (!ScrollConsoleScreenBuffer(handle_stdout,
+		&scroll_rect, NULL, top_left, &char_info))
+	{
+		display_win32_error ();
+		reset_attribute ();
+		exit (0);
+	}
+#elif defined (__unix__)
+	int sizey, sizex;
+	int x,y;
+	chtype this;
+	
+	get_screen_dimension(&sizey, &sizex);
+
+	for(y=STARTROW;y<sizey;y++) {
+		for(x=0;x<sizex;x++) {
+			this=mvinch(y+1,x);
+			mvaddch(y,x,this);
+		}
+	}
+	scrollok(stdscr,FALSE);
+	gotoxy(0, sizey-1);
+	clrtobot();
+	refresh();
+#else
+#pragma message ("ScrollUp() Undefined")
+#endif
+}
+
+void get_xy (int *x, int *y)
+{
+#ifdef __MSDOS__
+	struct text_info TextInfo;
+
+	gettextinfo(&TextInfo);
+	*x = TextInfo.curx-1;
+	*y = TextInfo.cury-1;
+#elif defined(_WIN32)
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+
+	GetConsoleScreenBufferInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&screen_buffer);
+	*x = screen_buffer.dwCursorPosition.X;
+	*y = screen_buffer.dwCursorPosition.Y;
+#elif defined(__unix__)
+	getyx(stdscr,*y,*x);
+#else
+	*x = 0;
+	*y = 0;
+#endif
+}
+
+void get_screen_dimension (int *lines, int *width)
+{
+#ifdef __MSDOS__
+	/* default to 80x25 */
+	*lines = 25;
+	*width = 80;
+#elif defined(_WIN32)
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	GetConsoleScreenBufferInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&screen_buffer);
+	*lines = screen_buffer.dwSize.Y;
+	*width = screen_buffer.dwSize.X;
+#elif defined(__unix__)
+	getmaxyx(stdscr,*lines,*width);
+#else
+	*lines = 0;
+	*width = 0;
+#endif
+}
+
+void put_character (int x, int y, char ch, unsigned short int attribute)
+{
+#ifdef __MSDOS__
+	VideoMem[(long) (y_lookup[(long) y]+ (long) (x<<1)) ] = (unsigned char)ch;
+	VideoMem[(long) (y_lookup[(long) y]+ (long) (x<<1) + 1L)] = (unsigned char)attribute;
+#elif defined(_WIN32)
+	DWORD bytes_written;
+	COORD cursor_pos;
+	HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+
+	cursor_pos.X = x;
+	cursor_pos.Y = y;
+
+	SetConsoleCursorPosition (stdout_handle, cursor_pos);
+
+	SetConsoleTextAttribute (
+	  stdout_handle,
+	  attribute);
+	WriteConsole (
+	  stdout_handle,
+	  &ch,
+	  1,
+	  &bytes_written,
+	  NULL);
+#elif defined(__unix__)
+	short fg;
+	int   attrs=A_NORMAL;
+	
+	pair_content(attribute,&fg,NULL);
+	if (attribute & 8)  {
+		attrs |= A_BOLD;
+	}
+	if (attribute & 128)
+		attrs |= A_BLINK;
+	attrset(attrs);
+	mvaddch(y, x, ch|COLOR_PAIR(attribute+1));
+#else
+	/* Ignore Attribute */
+#endif
+}
+
+#ifdef _WIN32
+void gotoxy (int x, int y)
+{
+	COORD cursor_pos;
+	HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+
+	cursor_pos.X = x;
+	cursor_pos.Y = y;
+
+	SetConsoleCursorPosition (stdout_handle, cursor_pos);
+}
+
+void clrscr (void)
+{
+  HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+  CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+  COORD top_left = { 0, 0 };
+  DWORD cells_written;
+
+  GetConsoleScreenBufferInfo (std_handle, &screen_buffer);
+
+  FillConsoleOutputCharacter (
+    std_handle,
+    (TCHAR)' ',
+    screen_buffer.dwSize.X * screen_buffer.dwSize.Y,
+    top_left,
+    &cells_written);
+
+  FillConsoleOutputAttribute (
+    std_handle,
+    (WORD)7,
+    screen_buffer.dwSize.X * screen_buffer.dwSize.Y,
+    top_left,
+    &cells_written);
+
+  SetConsoleCursorPosition (
+    std_handle,
+    top_left);
+}
+#endif /* _WIN32 */
+
+#ifdef __unix__
+void gotoxy (int x, int y)
+{
+	move(y, x);
+	refresh();
+}
+
+void clrscr (void)
+{
+	clear();
+}
+#endif /* __unix__ */
+
+void kputs ( char *szString )
+{
+    char number[3];
+	int cur_char, attr;
+	char foreground, background, cur_attr;
+	int i, j,  x,y;
+	static char o_fg = 7, o_bg = 0;
+	int scr_lines, scr_width;
+
+	get_xy (&x, &y);
+	get_screen_dimension (&scr_lines, &scr_width);
+
+	cur_attr = o_fg | o_bg;
+	cur_char=0;
+
+    for (;;)
+    {
+		if (x == scr_width)
+		{
+			x = 0;
+			y++;
+
+			if (y == scr_lines)
+			{
+				/* scroll line up */
+				ScrollUp();
+				y = scr_lines - 1;
+                break;
+			}
+		}
+		if (y == scr_lines)
+		{
+			/* scroll line up */
+			ScrollUp();
+			y = scr_lines - 1;
+		}
+        if (szString[cur_char] == 0)
+			break;
+        if (szString[cur_char] == '\b')
+		{
+			x--;
+			cur_char++;
+			continue;
+		}
+        if (szString[cur_char] == '\r')
+		{
+			x = 0;
+			cur_char++;
+			continue;
+		}
+        if (szString[cur_char]=='|')    {
+            if ( isdigit(szString[cur_char+1]) && isdigit(szString[cur_char+2]) )  {
+                number[0]=szString[cur_char+1];
+                number[1]=szString[cur_char+2];
+				number[2]=0;
+
+				attr=atoi(number);
+				if (attr>15)	{
+					background=attr-16;
+					o_bg = background << 4;
+					attr = o_bg | o_fg;
+					cur_attr = attr;
+				}
+				else	{
+					foreground=attr;
+					o_fg=foreground;
+					attr = o_fg | o_bg;
+					cur_attr = attr;
+				}
+				cur_char += 3;
+			}
+			else	{
+				put_character (x, y, szString[cur_char], cur_attr);
+
+				cur_char++;
+			}
+		}
+        else if (szString[cur_char] == '\n')  {
+			y++;
+			if (y == scr_lines)
+			{
+				/* scroll line up */
+				ScrollUp();
+				y = scr_lines - 1;
+			}
+			cur_char++;
+			x = 0;
+		}
+        else if (szString[cur_char] == 9)  {  /* tab */
+			cur_char++;
+			for (i=0;i<8;i++)	{
+				j = i + x;
+				if (j > scr_width) break;
+				put_character (j, y, ' ', cur_attr);
+			}
+			x += 8;
+		}
+		else	{
+			put_character (x, y, szString[cur_char], cur_attr);
+
+			cur_char++;
+			x++;
+		}
+	}
+
+    if (x == scr_width)
+    {
+        x = 0;
+        y++;
+
+        if (y == scr_lines)
+        {
+            /* scroll line up */
+            ScrollUp();
+            y = scr_lines - 1;
+        }
+    }
+	gotoxy(x,y);
+#ifdef __unix__
+	refresh();
+#endif
+}
+
+void kcls ( void )
+{
+#ifdef __MSDOS__
+    asm {
+        mov al,0    // number of lines
+        mov ch,STARTROW // starting row
+		mov cl,0	// starting column
+		mov dh, 24	// ending row
+		mov dl, 79	// ending column
+		mov bh, 7	// color
+		mov ah, 6
+		int 10h 	// do the scroll
+	}
+#elif defined(_WIN32)
+	HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+	COORD top_corner;
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	DWORD display_len, written;
+
+	top_corner.X = 0;
+	top_corner.Y = STARTROW;
+
+	GetConsoleScreenBufferInfo (stdout_handle, &screen_buffer);
+
+	display_len = (screen_buffer.dwSize.Y - STARTROW) *
+		          (screen_buffer.dwSize.X);
+
+	FillConsoleOutputCharacter (
+		stdout_handle,
+		(TCHAR)' ',
+		display_len,
+		top_corner,
+		&written);
+
+	FillConsoleOutputAttribute (
+		stdout_handle,
+		(WORD)(FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED),
+		display_len,
+		top_corner,
+		&written);
+#elif defined(__unix__)
+	move(STARTROW,0);
+	attrset(A_NORMAL|COLOR_PAIR(0));
+	clrtobot();
+	refresh();
+#else
+	/* No Function */
+#endif
+}
+
+void GetToken ( char *szString, char *szToken )
+{
+	char *pcCurrentPos;
+	unsigned int uCount;
+
+	/* Ignore all of line after comments or CR/LF char */
+	pcCurrentPos=(char *)szString;
+	while(*pcCurrentPos)
+	{
+		if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r')
+		{
+			*pcCurrentPos='\0';
+			break;
+		}
+		++pcCurrentPos;
+	}
+
+	/* Search for beginning of first token on line */
+	pcCurrentPos = (char *)szString;
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* If no token was found, proceed to process the next line */
+	if(!*pcCurrentPos)
+	{
+		szToken[0] = 0;
+		szString[0] = 0;
+		return;
+	}
+
+	/* Get first token from line */
+	uCount=0;
+	while(*pcCurrentPos && !isspace(*pcCurrentPos))
+	{
+		if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+		++pcCurrentPos;
+	}
+	if(uCount<=MAX_TOKEN_CHARS)
+		szToken[uCount]='\0';
+	else
+		szToken[MAX_TOKEN_CHARS]='\0';
+
+	/* Find beginning of configuration option parameters */
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* Trim trailing spaces from setting string */
+	for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+	{
+		if(isspace(pcCurrentPos[uCount]))
+		{
+			pcCurrentPos[uCount]='\0';
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	strcpy(szString, pcCurrentPos);
+}
+
+void GetLine ( char *InputStr, int MaxChars )
+{
+	int CurChar;
+	unsigned char InputCh;
+	char Spaces[85] = "                                                                                     ";
+	char BackSpaces[85] = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+    char TempStr[100], szString[100];
+
+	Spaces[MaxChars] = 0;
+	BackSpaces[MaxChars] = 0;
+
+    CurChar = strlen(InputStr);
+
+    kputs(Spaces);
+    kputs(BackSpaces);
+    kputs(InputStr);
+
+    for(;;)
+	{
+        InputCh = getch();
+
+		if (InputCh == '\b')
+		{
+			if (CurChar>0)
+			{
+				CurChar--;
+                kputs("\b \b");
+			}
+		}
+		else if (InputCh == '\r')
+		{
+            kputs("|16\n");
+			InputStr[CurChar]=0;
+			break;
+		}
+		else if (InputCh== '' || InputCh == '\x1B')  // ctrl-y
+		{
+			InputStr [0] = 0;
+			strcpy(TempStr, BackSpaces);
+			TempStr[ CurChar ] = 0;
+            kputs(TempStr);
+			Spaces[MaxChars] = 0;
+			BackSpaces[MaxChars] = 0;
+            kputs(Spaces);
+            kputs(BackSpaces);
+			CurChar = 0;
+		}
+		else if (InputCh >= '')
+			continue;
+		else if (InputCh == 0)
+			continue;
+		else if (iscntrl(InputCh))
+			continue;
+		else	/* valid character input */
+		{
+            if (CurChar == MaxChars)
+                continue;
+
+			InputStr[CurChar++]=InputCh;
+			InputStr[CurChar] = 0;
+            sprintf(szString, "%c", InputCh);
+            kputs(szString);
+		}
+	}
+}
+
+char far *vid_address ( void )
+{
+#ifdef __MSDOS__
+	int tmp1, tmp2;
+	long VideoType; 				/* B800 = color monitor */
+
+	asm {
+		mov bx,0040h
+		mov es,bx
+		mov dx,es:63h
+		add dx,6
+		mov tmp1, dx		   // move this into status port
+	};
+    VideoType = COLOR;
+
+	asm {
+		mov bx,es:10h
+		and bx,30h
+		cmp bx,30h
+		jne FC1
+    };
+    VideoType = MONO;
+
+FC1:
+
+    if (VideoType == MONO)
+		return ( ( void far * ) 0xB0000000L) ;
+	else
+		return ( ( void far * ) 0xB8000000L) ;
+#else
+	return NULL;
+#endif
+}
+
+
+void SystemInit ( void )
+{
+#ifdef __MSDOS__
+    int iTemp;
+
+    VideoMem = vid_address();
+    for (iTemp = 0; iTemp < 25;  iTemp++)
+        y_lookup[ iTemp ] = iTemp * 160;
+#endif /* __MSDOS__ */
+#ifdef __unix__
+	short fg;
+	short bg;
+	short pair=0;
+
+	// Initialize Curses lib.
+	initscr();
+	cbreak();
+	noecho();
+	nonl();
+//	intrflush(stdscr, FALSE);
+	keypad(stdscr, TRUE);
+	scrollok(stdscr,FALSE);
+	start_color();
+	clear();
+	refresh();
+
+	// Set up color pairs
+	for(bg=0;bg<8;bg++)  {
+		for(fg=0;fg<16;fg++) {
+			init_pair(++pair,curses_color(fg),curses_color(bg));
+		}
+	}
+
+#endif
+    GetGumName();
+}
+
+#ifdef __unix__
+short curses_color(short color)
+{
+	switch(color)
+	{
+		case 0 :
+			return(COLOR_BLACK);
+		case 1 :
+			return(COLOR_BLUE);
+		case 2 :
+			return(COLOR_GREEN);
+		case 3 :
+			return(COLOR_CYAN);
+		case 4 :
+			return(COLOR_RED);
+		case 5 :
+			return(COLOR_MAGENTA);
+		case 6 :
+			return(COLOR_YELLOW);
+		case 7 :
+			return(COLOR_WHITE);
+		case 8 :
+			return(COLOR_BLACK);
+		case 9 :
+			return(COLOR_BLUE);
+		case 10 :
+			return(COLOR_GREEN);
+		case 11 :
+			return(COLOR_CYAN);
+		case 12 :
+			return(COLOR_RED);
+		case 13 :
+			return(COLOR_MAGENTA);
+		case 14 :
+			return(COLOR_YELLOW);
+		case 15 :
+			return(COLOR_WHITE);
+	}
+	return(0);
+}
+#endif /* __unix__ */
+
+int main ( int argc, char **argv )
+{
+    char szInput[46], szToken[46], szString[128], szToken2[20];
+
+    if (argc != 2)
+    {
+        strcpy(szIniName, "install.ini");
+    }
+    else
+    {
+        strcpy(szIniName, argv[1]);
+
+        if (!strchr(szIniName, '.'))
+            strcat(szIniName, ".ini");
+    }
+
+    SystemInit();
+    clrscr();
+
+    gotoxy(1, 1);
+    Display("TITLE");
+    gotoxy(1, STARTROW+1);
+
+    Display("WELCOME");
+
+    for(;;)
+    {
+        kputs("|14> |07");
+
+        // get input
+        szInput[0] = 0;
+        GetLine(szInput, 45);
+
+        GetToken(szInput, szToken);
+
+        if (szToken[0] == 0)
+            continue;
+
+        if (_STRCASECMP(szToken, "quit") == 0 || _STRCASECMP(szToken, "q") == 0)
+            break;
+        else if (_STRCASECMP(szToken, "install") == 0)
+            install();
+        else if (_STRCASECMP(szToken, "upgrade") == 0)
+            upgrade();
+        else if (_STRCASECMP(szToken, "read") == 0)
+            Display(szInput);
+        else if (_STRCASECMP(szToken, "list") == 0)
+            ListFiles();
+        else if (_STRCASECMP(szToken, "about") == 0)
+            Display("About");
+        else if (_STRCASECMP(szToken, "extract") == 0)
+        {
+            GetToken(szInput, szToken2);
+            Extract(szToken2, szInput);
+        }
+        else if (_STRCASECMP(szToken, "cls") == 0)
+        {
+            kcls();
+            gotoxy(1, STARTROW+1);
+        }
+        else if (szToken[0] == '?' || _STRCASECMP(szToken, "help") == 0)
+            Display("Help");
+        else
+        {
+            sprintf(szString, "|04%s not a valid command!\n", szToken);
+            kputs(szString);
+        }
+    }
+
+    kcls();
+    gotoxy(1, STARTROW+1);
+    Display("Goodbye");
+	return(0);
+}
+
+int GetGUM(FILE *fpGUM)
+{
+    char szKey[80];
+    char szEncryptedName[MAX_FILENAME_LEN], cInput;
+    char *pcFrom, *pcTo, szFileName[MAX_FILENAME_LEN], szString[128];
+    FILE *fpToFile;
+    long lFileSize, lCompressSize;
+    long ByteCount;
+    unsigned short date, time;
+
+    ClearAll();
+
+    /* read in filename */
+    if (!fread(&szEncryptedName, sizeof(szEncryptedName), sizeof(char), fpGUM))
+        return FALSE;
+
+    /* then decrypt it */
+    pcFrom = szEncryptedName;
+    pcTo = szFileName;
+    while (*pcFrom)
+    {
+        *pcTo = *pcFrom ^ CODE1;
+        pcFrom++;
+        pcTo++;
+    }
+    *pcTo = 0;
+    sprintf(szString, "|14%-*s |06", MAX_FILENAME_LEN, szFileName);
+    kputs(szString);
+
+    /* make key using filename */
+    sprintf(szKey, "%s%x%x", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+    // printf("key = '%s%x%x'\n", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+
+    pcTo = szKey;
+    while (*pcTo)
+    {
+        *pcTo ^= CODE2;
+        pcTo++;
+    }
+
+    // if dirname, makedir
+    if (szFileName[0] == '/')
+    {
+		sprintf(szString, "dir |14%-*s\n", MAX_FILENAME_LEN, szFileName);
+        kputs(szString);
+
+        MKDIR(&szFileName[1]
+		
+		);
+        return TRUE;
+    }
+
+    /* get filesize from psi file */
+    fread(&lFileSize, sizeof(long), 1, fpGUM);
+    ByteCount = lFileSize;
+
+    fread(&lCompressSize, sizeof(long), 1, fpGUM);
+
+    // get datestamp
+    fread(&date, sizeof(unsigned short), 1, fpGUM);
+    fread(&time, sizeof(unsigned short), 1, fpGUM);
+
+    // get type of input depending on WriteType
+    if (FileExists(szFileName) && WriteType(szFileName) == OVERWRITE)
+    {
+        // continue -- overwrite file
+        kputs("|07- updating - |06");
+    }
+    else if (WriteType(szFileName) == SKIP && FileExists(szFileName) )
+    {
+        // skip file
+        kputs("|07- skipping (no update required)\n");
+        fseek(fpGUM, lCompressSize, SEEK_CUR);
+        return 1;
+    }
+    // else, normal file, do normally
+    // if file exists, ask user if he wants to overwrite it
+    else if (FileExists(szFileName) && Overwrite != ALWAYS)
+    {
+        kputs("|03exists.  overwrite? (yes/no/rename/always) :");
+
+        cInput = get_answer("YNAR");
+
+        if (cInput == 'A')
+        {
+            Overwrite = ALWAYS;
+        }
+        else if (cInput == 'R')
+        {
+            kputs("\n|03enter new file name: ");
+            GetLine(szFileName, MAX_FILENAME_LEN);
+        }
+        else if (cInput == 'N')
+        {
+            // skip file
+            fseek(fpGUM, lCompressSize, SEEK_CUR);
+            return 1;
+        }
+    }
+
+    /* open file to write to */
+    fpToFile = fopen(szFileName, "wb");
+    if (!fpToFile)
+    {
+        sprintf(szString, "|04Couldn't open %s\n", szFileName);
+        kputs(szString);
+        return FALSE;
+    }
+
+    // === decode here
+    decode(fpGUM, fpToFile);
+
+    fclose(fpToFile);
+
+    fpToFile = fopen(szFileName, "r+b");
+    _dos_setftime(fileno(fpToFile), date, time);
+    fclose(fpToFile);
+
+
+
+    sprintf(szString, "%ldb ", lFileSize);
+    kputs(szString);
+    kputs("|15done.\n");
+
+    return TRUE;
+}
+
+void install ( void )
+{
+    FILE *fpGUM;
+#ifdef __unix__
+	FILE *fpAttr;
+	mode_t	tMode;
+	char szFileName[MAX_FILENAME_LEN];
+#endif
+    char cInput;
+
+    Display("Install");
+
+    // make sure he wants to
+    kputs("\n|07Are you sure you wish to run the install now? (y/n):");
+    cInput = get_answer("YN");
+
+    if (cInput == 'N')
+    {
+        kputs("\n|04Installation aborted.\n");
+        return;
+    }
+
+    InitFiles("INSTALL.FILES");
+    Overwrite = FALSE;
+
+    fpGUM = fopen(szGumName, "rb");
+    if (!fpGUM)
+    {
+		printf("Can't find -%s-\n",szGumName);
+        kputs("|04No .GUM to blowup!\n");	
+        return;
+    }
+
+    while (GetGUM(fpGUM))
+        ;
+
+#ifdef __unix__
+	fpAttr = fopen("UnixAttr.DAT", "r");
+	if (fpAttr)
+	{
+		while(fscanf(fpAttr, "%o %s\n", &tMode, szFileName) != EOF)
+		{
+			chmod(szFileName, tMode);
+		}
+		fclose(fpAttr);
+		unlink("UnixAttr.DAT");
+	}
+#endif
+
+    fclose(fpGUM);
+
+    Display("InstallDone");
+}
+
+void upgrade( void )
+{
+    FILE *fpGUM;
+#ifdef __unix__
+	FILE *fpAttr;
+	mode_t	tMode;
+	char szFileName[MAX_FILENAME_LEN];
+#endif
+    char cInput;
+
+    Display("Upgrade");
+
+    // make sure he wants to
+    kputs("\n|07Are you sure you wish to upgrade? (y/n):");
+    cInput = get_answer("YN");
+
+    if (cInput == 'N')
+    {
+        kputs("\n|04Upgrade aborted.\n");
+        return;
+    }
+
+    InitFiles("UPGRADE.FILES");
+    Overwrite = FALSE;
+
+    fpGUM = fopen(szGumName, "rb");
+    if (!fpGUM)
+    {
+        kputs("|04No .GUM to blowup!\n");
+        return;
+    }
+
+    while (GetGUM(fpGUM))
+        ;
+
+#ifdef __unix__
+	fpAttr = fopen("UnixAttr.DAT", "r");
+	if (fpAttr)
+	{
+		while(fscanf(fpAttr, "%o %s\n", &tMode, szFileName) != EOF)
+		{
+			chmod(szFileName, tMode);
+		}
+		fclose(fpAttr);
+		unlink("UnixAttr.DAT");
+	}
+#endif
+
+    fclose(fpGUM);
+
+    Display("UpgradeDone");
+}
+
+char get_answer( char *szAllowableChars )
+{
+    char cKey, szString[20];
+    unsigned int iTemp;
+
+    for (;;)
+    {
+        cKey = getch();
+
+        /* see if allowable */
+        for (iTemp = 0; iTemp < strlen(szAllowableChars); iTemp++)
+        {
+            if (toupper(cKey) == toupper(szAllowableChars[iTemp]))
+                break;
+        }
+
+        if (iTemp < strlen(szAllowableChars))
+            break;  /* found allowable key */
+    }
+    sprintf(szString, "%c\n", cKey);
+    kputs(szString);
+
+    return (toupper(cKey));
+}
+
+BOOL FileExists ( char *szFileName )
+{
+    FILE *fp;
+
+    fp = fopen(szFileName, "r");
+    if (!fp)
+    {
+        return FALSE;
+    }
+
+    fclose(fp);
+    return TRUE;
+}
+
+void InitFiles ( char *szFileName )
+{
+    // init files to be installed
+
+    FILE *fpInput;
+    char szString[128];
+    BOOL FileFound = FALSE, Done = FALSE;
+    int CurFile;
+
+    for (CurFile = 0; CurFile < MAX_FILES; CurFile++)
+        FileInfo[CurFile].szFileName[0] = 0;
+
+    fpInput = fopen(szIniName, "r");
+    if (!fpInput)
+    {
+        kputs("|06usage:   |14install <inifile>\n");
+		reset_attribute ();
+        exit(0);
+        return;
+    }
+
+    // search for filename
+    for (;;)
+    {
+        if (!fgets(szString, 128, fpInput))
+            break;
+
+        // get rid of \n and \r
+		while (szString[ strlen(szString) - 1] == '\n' || szString[ strlen(szString) - 1] == '\r')
+			szString[ strlen(szString) - 1] = 0;
+
+        if (szString[0] == ':' && _STRCASECMP(szFileName, &szString[1]) == 0)
+        {
+            FileFound = TRUE;
+            break;
+        }
+    }
+
+    if (FileFound == FALSE)
+    {
+        fclose(fpInput);
+        return;
+    }
+
+    // found file list, retrieve filenames and file types
+    CurFile = 0;
+    while (!Done && CurFile < MAX_FILES)
+    {
+        if (!fgets(szString, 128, fpInput))
+            break;
+
+        // get rid of \n and \r
+		while (szString[ strlen(szString) - 1] == '\n' || szString[ strlen(szString) - 1] == '\r')
+			szString[ strlen(szString) - 1] = 0;
+
+        if (szString[0] == ':')
+            break;
+
+        // found another filename, copy it over
+        // x filename
+        // 0123456789...
+        strcpy(FileInfo[CurFile].szFileName, &szString[2]);
+        FileInfo[CurFile].WriteType = QUERY;
+
+        if (szString[0] == 'o')
+            FileInfo[CurFile].WriteType = OVERWRITE;
+        else if (szString[0] == 's')
+            FileInfo[CurFile].WriteType = SKIP;
+
+        CurFile++;
+    }
+
+    fclose(fpInput);
+}
+
+int WriteType ( char *szFileName )
+{
+    int CurFile;
+
+    // search for file
+    for (CurFile = 0; CurFile < MAX_FILES; CurFile++)
+    {
+        if (_STRCASECMP(FileInfo[CurFile].szFileName, szFileName) == 0)
+        {
+            // found file
+            return (FileInfo[CurFile].WriteType);
+        }
+    }
+
+    // if not found, return query
+    return QUERY;
+}
+
+void Extract ( char *szExtractFile, char *szNewName )
+{
+    char szKey[80];
+    char szEncryptedName[MAX_FILENAME_LEN], cInput;
+    char *pcFrom, *pcTo, szFileName[MAX_FILENAME_LEN], szString[128];
+    FILE *fpToFile, *fpGUM;
+    long lFileSize, lCompressSize;
+    long ByteCount;
+    unsigned short date, time;
+
+    ClearAll();
+
+    fpGUM = fopen(szGumName, "rb");
+    if (!fpGUM)
+    {
+        kputs("|04No .GUM to blowup!\n");
+        return;
+    }
+
+    for (;;)
+    {
+        /* read in filename */
+        if (!fread(&szEncryptedName, sizeof(szEncryptedName), sizeof(char), fpGUM))
+        {
+            kputs("|04file not found!\n");
+            fclose(fpGUM);
+            return;
+        }
+
+        /* then decrypt it */
+        pcFrom = szEncryptedName;
+        pcTo = szFileName;
+        while (*pcFrom)
+        {
+            *pcTo = *pcFrom ^ CODE1;
+            pcFrom++;
+            pcTo++;
+        }
+        *pcTo = 0;
+
+        /* make key using filename */
+        sprintf(szKey, "%s%x%x", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+        // printf("key = '%s%x%x'\n", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+
+        pcTo = szKey;
+        while (*pcTo)
+        {
+            *pcTo ^= CODE2;
+            pcTo++;
+        }
+
+        // file, do following
+        if (szFileName[0] != '/')
+        {
+            /* get filesize from psi file */
+            fread(&lFileSize, sizeof(long), 1, fpGUM);
+            ByteCount = lFileSize;
+
+            fread(&lCompressSize, sizeof(long), 1, fpGUM);
+
+            // get datestamp
+            fread(&date, sizeof(unsigned), 1, fpGUM);
+            fread(&time, sizeof(unsigned), 1, fpGUM);
+        }
+        else
+        {
+            // was a dir
+            lFileSize = 0;
+            lCompressSize = 0;
+        }
+
+        // same file? -- if so, keep going, if not, skip
+        if ( _STRCASECMP(szExtractFile, szFileName) == 0)
+        {
+            break;
+        }
+        else
+        {
+            // skip it
+            fseek(fpGUM, lCompressSize, SEEK_CUR);
+        }
+    }
+
+    if (*szNewName != 0)
+        strcpy(szFileName, szNewName);
+
+    // if dirname, makedir
+    if (szFileName[0] == '/')
+    {
+		sprintf(szString, "|14%-*s\n", MAX_FILENAME_LEN, szFileName);
+        kputs(szString);
+
+        MKDIR(&szFileName[1]);
+        fclose(fpGUM);
+        return;
+    }
+
+    if (FileExists(szFileName))
+    {
+        kputs("|03exists.  overwrite? (yes/no/rename/always) :");
+
+        cInput = get_answer("YNAR");
+
+        if (cInput == 'A')
+        {
+            Overwrite = ALWAYS;
+        }
+        else if (cInput == 'R')
+        {
+            kputs("\n|03enter new file name: ");
+            GetLine(szFileName, MAX_FILENAME_LEN);
+        }
+        else if (cInput == 'N')
+        {
+            // skip file
+            fseek(fpGUM, lCompressSize, SEEK_CUR);
+            fclose(fpGUM);
+            return;
+        }
+    }
+
+    /* open file to write to */
+    fpToFile = fopen(szFileName, "wb");
+    if (!fpToFile)
+    {
+        sprintf(szString, "|04Couldn't write to %s\n", szFileName);
+        kputs(szString);
+        return;
+    }
+
+    sprintf(szString, "|06Extracting %s\n", szFileName);
+    kputs(szString);
+
+    //== decode it here
+    decode(fpGUM, fpToFile);
+
+    fclose(fpToFile);
+    fclose(fpGUM);
+
+    fpToFile = fopen(szFileName, "r+b");
+    _dos_setftime(fileno(fpToFile), date, time);
+    fclose(fpToFile);
+
+    sprintf(szString, "(%ld bytes) ", lFileSize);
+    kputs(szString);
+    kputs("|15Done.\n");
+}
+
+void ListFiles ( void )
+{
+    char szKey[80];
+    char szEncryptedName[MAX_FILENAME_LEN];
+    char *pcFrom, *pcTo, szFileName[MAX_FILENAME_LEN], szString[128];
+    FILE *fpGUM;
+    long lFileSize, TotalBytes = 0, lCompressSize;
+    int FilesFound = 0;
+    unsigned short date, time;
+    BOOL Done = FALSE;
+
+    fpGUM = fopen(szGumName, "rb");
+    if (!fpGUM)
+    {
+        kputs("|04No .GUM to blowup!\n");
+        return;
+    }
+
+    while (!Done)
+    {
+        /* read in filename */
+        if (!fread(&szEncryptedName, sizeof(szEncryptedName), sizeof(char), fpGUM))
+        {
+            // done
+            fclose(fpGUM);
+            sprintf(szString, "\n|14%ld total bytes\n\n", TotalBytes);
+            kputs(szString);
+            break;
+        }
+
+        /* then decrypt it */
+        pcFrom = szEncryptedName;
+        pcTo = szFileName;
+        while (*pcFrom)
+        {
+            *pcTo = *pcFrom ^ CODE1;
+            pcFrom++;
+            pcTo++;
+        }
+        *pcTo = 0;
+
+        /* make key using filename */
+        sprintf(szKey, "%s%x%x", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+        // printf("key = '%s%x%x'\n", szEncryptedName, szEncryptedName[0], szEncryptedName[1]);
+
+        pcTo = szKey;
+        while (*pcTo)
+        {
+            *pcTo ^= CODE2;
+            pcTo++;
+        }
+
+        if (szFileName[0] == '/')
+        {
+            sprintf(szString, "|15%14s  |06-- |07      directory  ",
+                szFileName);
+            kputs(szString);
+
+            lCompressSize = 0L;
+            lFileSize = 0L;
+        }
+        else
+        {
+
+            /* get filesize from psi file */
+            fread(&lFileSize, sizeof(long), 1, fpGUM);
+            fread(&lCompressSize, sizeof(long), 1, fpGUM);
+
+            // get datestamp
+            fread(&date, sizeof(unsigned short), 1, fpGUM);
+            fread(&time, sizeof(unsigned short), 1, fpGUM);
+
+            // show dir like DOS :)
+            sprintf(szString, "|15%14s  |06-- |07%9ld bytes  ",
+                szFileName, lFileSize);
+            kputs(szString);
+        }
+        FilesFound++;
+
+        if ( (FilesFound % 2) == 0)
+            kputs("\n");
+
+        if (FilesFound % (2*(25-STARTROW)-4) == 0 && FilesFound)
+        {
+            kputs("[more]");
+            if (toupper(getch()) == 'Q')
+                Done = TRUE;
+            kputs("\r       \r");
+        }
+
+        fseek(fpGUM, lCompressSize, SEEK_CUR);
+
+        TotalBytes += lFileSize;
+    }
+
+    if ( (FilesFound % 2) != 0)
+        kputs("\n");
+
+    fclose(fpGUM);
+}
+
+void GetGumName ( void )
+{
+    // init files to be installed
+    FILE *fpInput;
+    char szString[128];
+    int CurFile;
+
+    for (CurFile = 0; CurFile < MAX_FILES; CurFile++)
+        FileInfo[CurFile].szFileName[0] = 0;
+
+    fpInput = fopen(szIniName, "r");
+    if (!fpInput)
+    {
+        // no ini file
+        kputs("|06usage:   |14install <inifile>\n");
+		reset_attribute ();
+        exit(0);
+    }
+
+    // search for filename
+    for (;;)
+    {
+        if (!fgets(szString, 128, fpInput))
+        {
+            kputs("\n|12Couldn't get GUM filename\n");
+			reset_attribute ();
+            exit(0);
+            break;
+        }
+
+        // get rid of \n and \r
+		while (szString[ strlen(szString) - 1] == '\n' || szString[ strlen(szString) - 1] == '\r')
+			szString[ strlen(szString) - 1] = 0;
+
+        if (szString[0] == '!')
+        {
+            strcpy(szGumName, &szString[1]);
+            break;
+        }
+    }
+
+    fclose(fpInput);
+}
+
+void ClearAll ( void )
+{
+    int iTemp;
+
+    for (iTemp = 0; iTemp < _MAXCHAR+1; iTemp++)
+        left[iTemp] = right[iTemp] = 0;
+    for (iTemp = 0; iTemp < TWICEMAX+1; iTemp++)
+        up[TWICEMAX+1] = freq[TWICEMAX+1] = 0;
+
+    input_bit_count = 0;
+    input_bit_buffer = 0;
+    output_bit_count = 0;
+    output_bit_buffer = 0;
+    bytes_in = 0;
+    bytes_out = 0;
+    dictfile = 0;
+    binary = 0;
+
+    for (iTemp = 0; iTemp < COPYRANGES; iTemp++)
+        copymin[COPYRANGES] = copymax[COPYRANGES] = 0;
+
+    maxdistance = maxsize = 0;
+    distance = 0; insert = MINCOPY;
+}
+
+#ifndef __MSDOS__
+unsigned short _dos_setftime (int handle, unsigned short date, unsigned short time)
+{
+	struct tm dos_dt;
+	time_t file_dt;
+#ifdef _WIN32
+	struct _utimbuf tm_buf;
+#elif defined(__unix__)
+	struct timeval tmv_buf;
+#endif
+
+	memset (&dos_dt, 0, sizeof(struct tm));
+	dos_dt.tm_year = ((date & 0xfe00) >> 9) + 80;
+	dos_dt.tm_mon  = ((date & 0x01e0) >> 5) + 1;
+	dos_dt.tm_mday =  (date & 0x001f);
+	dos_dt.tm_hour =  (time & 0xf800) >> 11;
+	dos_dt.tm_min  =  (time & 0x07e0) >> 5;
+	dos_dt.tm_sec  =  (time & 0x001f) * 2;
+
+	file_dt = mktime (&dos_dt);
+
+#ifdef _WIN32
+	tm_buf.actime = tm_buf.modtime = file_dt;
+	return (_futime (handle, &tm_buf));
+#elif defined(__unix__)
+	tmv_buf.tv_sec = file_dt;
+	tmv_buf.tv_usec = file_dt * 1000;
+	return (futimes (handle, &tmv_buf));
+#else
+#error "_dos_setftime needs a setting function, compilation aborted"
+#endif
+}
+#endif
diff --git a/src/doors/clans-devkit/keywords.h b/src/doors/clans-devkit/keywords.h
new file mode 100644
index 0000000000000000000000000000000000000000..acee7403e66247f47f916d4c1b9661e3dc068ad0
--- /dev/null
+++ b/src/doors/clans-devkit/keywords.h
@@ -0,0 +1,191 @@
+#define MAX_KEY_WORDS   15
+#define MAX_TOKEN_CHARS 32
+
+char *papszKeyWords[MAX_KEY_WORDS] =
+{
+    "SysopName",
+    "BBSName",
+    "UseLog",
+    "ScoreANSI",
+    "ScoreASCII",
+    "Node",
+    "DropDirectory",
+    "UseFOSSIL",
+    "SerialPortAddr",
+    "SerialPortIRQ",
+    "BBSId",
+    "NetmailDir",
+    "InboundDir",
+    "MailerType",
+    "InterBBS"
+};
+
+#define MAX_IM_WORDS    22
+#define I_ITEM          0
+#define I_WEAPON        1
+#define I_ARMOR         2
+#define I_SHIELD        3
+
+char *papszItemKeyWords[MAX_IM_WORDS] =
+{
+    "Name",
+    "Type",
+    "Special",
+    "Agility",
+    "Dexterity",
+    "Strength",
+    "Wisdom",
+    "ArmorStr",
+    "Charisma",
+    "Cost",
+    "DiffMaterials",
+    "Stats",
+    "Requirements",
+    "Penalties",
+    "Energy",
+    "Uses",
+    "Spell",
+    "Level",
+    "Village",
+    "RandLevel",
+    "HPAdd",
+    "SPAdd"
+};
+
+#define MAX_PC_WORDS    12
+
+char *papszPCKeyWords[MAX_PC_WORDS] =
+{
+    "Name",
+    "HP",
+    "Agility",
+    "Dexterity",
+    "Strength",
+    "Wisdom",
+    "ArmorStr",
+    "Weapon",
+    "Shield",
+    "Armor",
+    "Item",
+    "ClanName"
+};
+
+#define MAX_PCLASS_WORDS    11
+
+char *papszPClassKeyWords[MAX_PCLASS_WORDS] =
+{
+    "Name",
+    "Agility",
+    "Dexterity",
+    "Strength",
+    "Wisdom",
+    "ArmorStr",
+    "Charisma",
+    "MaxHP",
+    "Gold",
+    "MaxMP",
+    "Spell"
+};
+
+
+
+#define MAX_SPELL_WORDS     24
+
+char *papszSpellKeyWords[MAX_SPELL_WORDS] =
+{
+    "Name",
+    "Agility",
+    "Dexterity",
+    "Strength",
+    "Wisdom",
+    "ArmorStr",
+    "Charisma",
+    "Value",
+    "Flag",
+    "HealStr",
+    "DamageStr",
+    "ModifyStr",
+    "SP",
+    "Friendly",
+    "NoTarget",
+    "Level",
+    "WearoffStr",
+    "Energy",
+    "StatusStr",
+    "OtherStr",
+    "UndeadName",
+    "StrengthCanReduce",
+    "WisdomCanReduce",
+    "MultiAffect"
+};
+
+#define MAX_NDX_WORDS   10
+
+char *papszNdxKeyWords[MAX_NDX_WORDS] =
+{
+    "BBSName",
+    "VillageName",
+    "Address",
+    "ConnectType",
+    "MailType",
+    "BBSId",
+    "Status",
+    "WorldName",
+    "LeagueId",
+    "Host"
+};
+
+#define MAX_RT_WORDS    4
+
+char *papszRouteKeyWords[MAX_RT_WORDS] =
+{
+    "ROUTE",
+    "CRASH",
+    "HOLD",
+    "NORMAL"
+};
+
+#define MAX_COMLINE_WORDS    20
+
+char *papszComLineKeyWords[MAX_COMLINE_WORDS] =
+{
+    "L",
+    "Local",
+    "M",
+    "Maint",
+    "FM",
+    "FMaint",
+    "ForceMaint",
+    "O",
+    "Outbound",
+    "I",
+    "Inbound",
+    "F",
+    "Fullmode",
+    "T",
+    "TimeSlicer",
+    "N",
+    "?",
+    "H",
+    "Help",
+    "Reset"
+};
+
+#define MAX_NPC_WORDS   13
+
+char *papszNPCKeyWords[MAX_NPC_WORDS] =
+{
+    "Name",
+    "Loyalty",
+    "KnownTopic",
+    "Topic",
+    "Wander",
+    "NPCDAT",
+    "MaxTopics",
+    "OddsOfSeeing",
+    "IntroTopic",
+    "HereNews",
+    "QuoteFile",
+    "MonFile",
+    "Index"
+};
diff --git a/src/doors/clans-devkit/langcomp.c b/src/doors/clans-devkit/langcomp.c
new file mode 100644
index 0000000000000000000000000000000000000000..5bde2187aae6c339857482a3c13403bab5cb63cf
--- /dev/null
+++ b/src/doors/clans-devkit/langcomp.c
@@ -0,0 +1,256 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+// Compiles the language file
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "defines.h"
+#include <string.h>
+
+void Convert ( char *Dest, char *From );
+
+struct LanguageHeader
+{
+    char Signature[30];         // "The Clans Language File v1.0"
+
+    unsigned _INT16 StrOffsets[2000];  // offsets for up to 500 strings
+    unsigned _INT16 NumBytes;          // how big is the bigstring!?
+
+    char *BigString;        // All 500 strings jumbled together into
+                                // one
+} PACKED Language;
+
+int main ( int argc, char *argv[])
+{
+    FILE *fFrom, *fTo;
+    _INT16 iTemp, CurString;
+    char TempString[800], String[800], FromFile[30], ToFile[30];
+
+    printf("The Clans Language File Compiler v.1.0 (c) copyright 1997 Allen Ussher\n\n");
+
+    if (argc != 2)
+    {
+        printf("Format:  Langcomp <Language>\n");
+        exit(0);
+    }
+
+    strcpy(FromFile, argv[1]);
+
+    for (iTemp = strlen(FromFile); iTemp>0; iTemp--)
+        if (FromFile[iTemp] == '.')
+            break;
+
+    if (iTemp == 0)
+    {
+        strcpy(ToFile, FromFile);
+        strcat(ToFile, ".xl");
+        strcat(FromFile, ".txt");
+    }
+    else
+    {
+        FromFile[iTemp] = 0;
+        strcpy(ToFile, FromFile);
+        strcat(ToFile, ".xl");
+        FromFile[iTemp] = '.';
+    }
+
+    fFrom = fopen(FromFile, "r");
+    if (!fFrom)
+    {
+        printf("Error opening %s\n", FromFile);
+        exit(0);
+    }
+
+    // initialize the big string
+    strcpy(Language.Signature, "The Clans Language File v1.0\x1A");
+    for (iTemp = 0;  iTemp < 2000; iTemp++)
+        Language.StrOffsets[iTemp] = 0;
+    Language.NumBytes = 0;
+
+    Language.BigString = malloc(64000);
+    if (!Language.BigString)
+    {
+        printf("Couldn't allocate enough memory to run!");
+        fclose(fFrom);
+        exit(0);
+    }
+
+    // just to ensure it works out, make the first string in BigString = ""
+    Language.BigString[0] = 0;
+    Language.NumBytes = 1;
+
+    // read through line by line
+    for (;;)
+    {
+        if (!fgets(TempString, 800, fFrom)) break;
+
+        if (TempString[0] == '#')   continue;       // skip if comment line
+        if (TempString[0] == ' ')   continue;       // skip if comment line
+
+        // break down string
+        // get rid of \n and \r
+		while (TempString[ strlen(TempString) - 1] == '\n' || TempString[ strlen(TempString) - 1] == '\r')
+			TempString[ strlen(TempString) - 1] = 0;
+
+        // convert @@ at end to \n
+        if (TempString[ strlen(TempString) - 2] == '@' &&
+            TempString[ strlen(TempString) - 1] == '@')
+        {
+            TempString[ strlen(TempString) - 2] = 0;
+            strcat(TempString, "\n");
+        }
+
+        CurString = atoi(TempString);
+        if (CurString == 0) continue;
+
+        // convert string's special language codes
+        Convert(String, &TempString[5]);
+        // strcpy(String, &TempString[5]);
+
+        Language.StrOffsets[CurString] = Language.NumBytes;
+        strcpy( &Language.BigString[ Language.NumBytes ], String);
+        Language.NumBytes += (strlen(String)+1); // must also include zero byte
+        //Language.BigString[ Language.NumBytes ] = 0;
+        //Language.NumBytes++;
+
+        //sprintf(String, "%04d %s", CurString, &Language.BigString[ Language.StrOffsets[CurString] ]);
+        //String[50] = 0;
+        //strcat(String, "\r");
+        //puts(String);
+    }
+
+    fclose(fFrom);
+
+    // now write it to the file
+    fTo = fopen(ToFile, "wb");
+    if (!fTo)
+    {
+        printf("Error opening %s\n", ToFile);
+        free(Language.BigString);
+        exit(0);
+    }
+
+    fwrite(&Language, sizeof(Language), 1, fTo);
+    fwrite(Language.BigString, Language.NumBytes, 1, fTo);
+
+    fclose(fTo);
+
+    free(Language.BigString);
+
+    printf("Done!\n\n%u bytes were used.  (max 64000).\n", Language.NumBytes);
+	return(0);
+}
+
+/* IMPORTANT!!!!   Format of the compiled language (*.XL)
+
+
+    struct
+    {
+        char Signature[30];         // "X-Engine Language File v1.0"
+
+        long StrOffsets[2000];       // offsets for up to 500 strings
+
+        char far *BigString;        // All 500 strings jumbled together into
+                                    // one
+    } LanguageHeader;
+*/
+
+void Convert ( char *Dest, char *From )
+{
+    _INT16 dCurChar = 0, fCurChar = 0;
+
+    Dest[dCurChar] = 0;    // make it 0 length
+
+    while (From[fCurChar])
+    {
+        if (From[fCurChar] == '^')
+        {
+            if (From[fCurChar+1] == 'M')
+            {
+                Dest[dCurChar] = '\n';
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == '[')
+            {
+                Dest[dCurChar] = 27;
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == '-')
+            {
+                Dest[dCurChar] = 0;
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == 'H')
+            {
+                Dest[dCurChar] = '\b';
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == 'N')
+            {
+                Dest[dCurChar] = '\r';
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == 'G')
+            {
+                Dest[dCurChar] = 7;
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else
+            {
+                Dest[dCurChar] = From[fCurChar];
+                dCurChar++;
+                fCurChar++;
+            }
+        }
+        /*
+        else if (From[fCurChar] == '&' && (isalnum(From[fCurChar+1]) || From[fCurChar+1] == '-') )
+        {
+            // &s turns to %s
+            Dest[dCurChar] = '%';
+            dCurChar++;
+            fCurChar++;
+        }
+        else if (From[fCurChar] == '%' && (isalpha(From[fCurChar+1]) || From[fCurChar+1] == '!') )
+        {
+            // % codes turn to &
+            Dest[dCurChar] = '&';
+            dCurChar++;
+            fCurChar++;
+        }
+        */
+        else
+        {
+            Dest[dCurChar] = From[fCurChar];
+
+            fCurChar++;
+            dCurChar++;
+        }
+    }
+
+    Dest[dCurChar] = 0;
+
+}
diff --git a/src/doors/clans-devkit/langcomp.txt b/src/doors/clans-devkit/langcomp.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1e01efd6d0959951e8892c32f22c2ca0420c7096
--- /dev/null
+++ b/src/doors/clans-devkit/langcomp.txt
@@ -0,0 +1,23 @@
+What's this one do?
+-------------------
+langcomp is used to compile language (strings.txt) files.  The strings.txt
+file should be in the data directory of the source code you downloaded.
+
+You run it like
+---------------
+This...
+
+	langcomp <strings>
+
+Just use "strings" and it'll look for the file called strings.txt and
+generate a strings.xl language file.  That's it.  The Clans uses strings.xl
+in the .pak file, so that's what you'll likely want.  Another example:
+If you run "langcomp blah", it'll look for blah.txt and generate blah.xl.
+I know, it's not consistent with the other utils, but who the hell cares.
+
+64000b Limit
+------------
+Yeah, there's a 64000 byte limit on the compiled strings file mainly
+because under the memory model I used, that was the largest size of
+data I could use with malloc (approximately).  I doubt that limit
+exists with other systems and compilers, though.
\ No newline at end of file
diff --git a/src/doors/clans-devkit/makenpc.c b/src/doors/clans-devkit/makenpc.c
new file mode 100644
index 0000000000000000000000000000000000000000..5b8f23dab93de36b00de54c20130092cbaeb14d1
--- /dev/null
+++ b/src/doors/clans-devkit/makenpc.c
@@ -0,0 +1,370 @@
+// MakeNPC
+
+#include <stdio.h>
+#include <time.h>
+#ifdef __MSDOS__
+#include <malloc.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/*
+typedef char               BOOL;           // Boolean value, at least 1 bit. 
+-- BOOL is defined by 'defines.h' 
+*/
+#include "structs.h"
+#include "keywords.h"
+
+/* Defined in 'defines.h'
+#define TRUE    1
+#define FALSE   0
+*/
+
+// areas to wander
+#define WN_NONE     0       // not a wanderer
+#define WN_CHURCH   1
+#define WN_STREET   2
+#define WN_MARKET   3
+#define WN_TOWNHALL 5
+#define WN_THALL    6
+#define WN_REBEL    7
+#define WN_MINE     8
+
+#define NPCS_NOTHERE    0   // status of NPC, not here -- i.e. not in town
+#define NPCS_HERE       1
+
+int TotalItems, TotalRaces, TotalClasses, TotalSpells;
+
+void GetToken ( char *szString, char *szToken );
+void Init_NPCs ( char *szInfile, char *szOutfile );
+
+#if defined(__BORLANDC__) && defined(__MSDOS__)
+extern unsigned _stklen = 32000U;
+#endif /* __BORLANDC__ */
+
+int main (int argc, char **argv)
+{
+    if (argc != 3)
+    {
+        printf("\nformat:\n MakeNPC [infile.txt] [outfile.npc]\n");
+        exit(0);
+    }
+
+    printf("NPC is %d bytes\n", sizeof(struct NPCInfo));
+
+    Init_NPCs( argv[1], argv[2] );
+	return(0);
+}
+
+void Init_NPCs ( char *szInfile, char *szOutfile )
+{
+    struct NPCInfo *NPCInfo;
+    FILE *fpNPC, *fpNPCDat;
+	char szLine[255], *pcCurrentPos, szString[255];
+	char szToken[MAX_TOKEN_CHARS + 1]/*, *pcAt*/;
+	unsigned int uCount;
+	int iKeyWord;
+    int CurNPC = -1;
+    int iTemp; /*, OrigNPC*/
+	int TopicsKnown=0;
+
+    fpNPC = fopen(szInfile, "r");
+    if (!fpNPC)
+	{
+        printf("Error reading %s\n", szInfile);
+		exit(0);
+	}
+    fpNPCDat = fopen(szOutfile, "wb");
+    if (!fpNPCDat)
+	{
+        printf("Error writing %s\n", szOutfile);
+		exit(0);
+	}
+
+    NPCInfo = malloc(sizeof(struct NPCInfo));
+
+	for (;;)
+	{
+		/* read in a line */
+        if (fgets(szLine, 255, fpNPC) == NULL) break;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos)
+		{
+            /* skip all comment lines */
+			if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+               || *pcCurrentPos == '#')
+			{
+				*pcCurrentPos='\0';
+				break;
+			}
+			++pcCurrentPos;
+		 }
+
+		/* Search for beginning of first token on line */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+		/* Get first token from line */
+		uCount=0;
+		while(*pcCurrentPos && !isspace(*pcCurrentPos))
+		{
+			if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+			++pcCurrentPos;
+		}
+		if(uCount<=MAX_TOKEN_CHARS)
+			szToken[uCount]='\0';
+		else
+			szToken[MAX_TOKEN_CHARS]='\0';
+
+		/* Find beginning of keyword parameter */
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* Trim trailing spaces from setting string */
+		for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+		{
+			if(isspace(pcCurrentPos[uCount]))
+			{
+				pcCurrentPos[uCount]='\0';
+			}
+		else
+			{
+				break;
+			}
+		}
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+        for(iKeyWord = 0; iKeyWord < MAX_NPC_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+            if(_STRCASECMP(szToken, papszNPCKeyWords[iKeyWord]) == 0)
+			{
+				/* Process token */
+				switch (iKeyWord)
+				{
+                    case 12 :   /* Index of NPC */
+                        // write old NPC, if there was one, to file
+                        if (CurNPC != -1)
+                        {
+                            NPCInfo->KnownTopics =  TopicsKnown;
+                            fwrite(NPCInfo, sizeof(struct NPCInfo), 1, fpNPCDat);
+                        }
+                        ++CurNPC;
+                        printf("%s\n", pcCurrentPos);
+
+                        /* initialize NPC */
+                        memset(NPCInfo, 0, sizeof(struct NPCInfo));
+                        strcpy(NPCInfo->szIndex, pcCurrentPos);
+
+                        // no topics known just yet
+                        NPCInfo->IntroTopic.Active = FALSE;
+                        for (iTemp = 0; iTemp < MAX_TOPICS; iTemp++)
+                            NPCInfo->Topics[iTemp].Active = FALSE;
+
+                        NPCInfo->Loyalty = 5;    // average loyalty
+                        NPCInfo->Roamer = FALSE;
+                        NPCInfo->WhereWander = WN_NONE;
+                        NPCInfo->NPCPCIndex = -1;
+                        NPCInfo->MaxTopics = -1;     // no maximum
+                        NPCInfo->OddsOfSeeing = 0;
+                        NPCInfo->szHereNews[0] = 0;
+                        strcpy(NPCInfo->szQuoteFile, "/q/NpcQuote");
+                        NPCInfo->szMonFile[0] = 0;
+
+                        TopicsKnown = 0;
+						break;
+                    case 1 :    // loyalty
+                        NPCInfo->Loyalty = atoi(pcCurrentPos);
+                        break;
+                    case 2 :    // KnownTopic
+                        NPCInfo->Topics[TopicsKnown].Active = TRUE;
+                        NPCInfo->Topics[TopicsKnown].Known = TRUE;
+                        NPCInfo->Topics[TopicsKnown].ClanInfo = FALSE;
+
+                        GetToken(pcCurrentPos, szString);
+                        printf("KnownTopic = %s\n", pcCurrentPos);
+
+                        // topic as it appears in the quote file
+                        strcpy(NPCInfo->Topics[TopicsKnown].szFileName,
+                            szString);
+
+                        // topic name as it appears to user
+                        strcpy(NPCInfo->Topics[TopicsKnown].szName,
+                            pcCurrentPos);
+
+                        TopicsKnown++;
+                        break;
+                    case 3 :    // Topic
+                        NPCInfo->Topics[TopicsKnown].Active = TRUE;
+                        NPCInfo->Topics[TopicsKnown].Known = FALSE;
+                        NPCInfo->Topics[TopicsKnown].ClanInfo = FALSE;
+
+                        GetToken(pcCurrentPos, szString);
+                        printf("Topic = %s\n", pcCurrentPos);
+
+                        // topic as it appears in the quote file
+                        strcpy(NPCInfo->Topics[TopicsKnown].szFileName,
+                            szString);
+
+                        // topic name as it appears to user
+                        strcpy(NPCInfo->Topics[TopicsKnown].szName,
+                            pcCurrentPos);
+
+                        TopicsKnown++;
+                        break;
+                    case 4 :    // where does he wander.
+                        // leave it for now
+                        if (_STRCASECMP(pcCurrentPos, "Church") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_CHURCH;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Street") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_STREET;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Market") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_MARKET;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Town Hall") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_TOWNHALL;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Training Hall") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_THALL;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Rebel Menu") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_REBEL;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Mine") == 0)
+                        {
+                            NPCInfo->WhereWander = WN_MINE;
+                        }
+                        else
+                            printf("\aIncorrect usage: %s\n", pcCurrentPos);
+                        break;
+                    case 5 :    // which NPC in the NPC.PC is he?
+                        NPCInfo->NPCPCIndex = atoi(pcCurrentPos);
+                        break;
+                    case 6 :
+                        NPCInfo->MaxTopics = atoi(pcCurrentPos);
+                        break;
+                    case 7 :    // odds of seing
+                        NPCInfo->OddsOfSeeing = atoi(pcCurrentPos);
+                        printf("Odds of seeing are %d%%\n", NPCInfo->OddsOfSeeing);
+                        break;
+                    case 8 :    // introtopic
+                        NPCInfo->IntroTopic.Active = TRUE;
+                        NPCInfo->IntroTopic.Known = FALSE;
+                        NPCInfo->IntroTopic.ClanInfo = FALSE;
+
+                        // topic name as it appears to user
+                        strcpy(NPCInfo->IntroTopic.szFileName, pcCurrentPos);
+                        printf("Intro topic = %s\n", pcCurrentPos);
+                        break;
+                    case 9 :    // here news
+                        if (strlen(pcCurrentPos) > 69)
+                            pcCurrentPos[69] = 0;
+                        strcpy(NPCInfo->szHereNews, pcCurrentPos);
+                        break;
+                    case 0 :    // name of NPC
+                        strcpy(NPCInfo->szName, pcCurrentPos);
+                        break;
+                    case 10 :   // quotefile to use
+                        strcpy(NPCInfo->szQuoteFile, pcCurrentPos);
+                        break;
+                    case 11 :   // .mon file to use
+                        strcpy(NPCInfo->szMonFile, pcCurrentPos);
+                        break;
+				}
+				break;
+			}
+		}
+	}
+
+    // write the last NPC to file
+    if (CurNPC != -1)
+    {
+        NPCInfo->KnownTopics =  TopicsKnown;
+        fwrite(NPCInfo, sizeof(struct NPCInfo), 1, fpNPCDat);
+    }
+
+	/* since they started at -1 and not 0 */
+    CurNPC++;
+
+    printf("%d NPCs found.\n%ld bytes used", CurNPC, (long) CurNPC*sizeof(struct NPCInfo));
+
+    fclose(fpNPC);
+    fclose(fpNPCDat);
+    free(NPCInfo);
+}
+
+void GetToken ( char *szString, char *szToken )
+{
+	char *pcCurrentPos;
+	unsigned int uCount;
+
+	/* Ignore all of line after comments or CR/LF char */
+	pcCurrentPos=(char *)szString;
+	while(*pcCurrentPos)
+	{
+		if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r')
+		{
+			*pcCurrentPos='\0';
+			break;
+		}
+		++pcCurrentPos;
+	}
+
+	/* Search for beginning of first token on line */
+	pcCurrentPos = (char *)szString;
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* If no token was found, proceed to process the next line */
+	if(!*pcCurrentPos)
+	{
+		szToken[0] = 0;
+		szString[0] = 0;
+		return;
+	}
+
+	/* Get first token from line */
+	uCount=0;
+	while(*pcCurrentPos && !isspace(*pcCurrentPos))
+	{
+		if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+		++pcCurrentPos;
+	}
+	if(uCount<=MAX_TOKEN_CHARS)
+		szToken[uCount]='\0';
+	else
+		szToken[MAX_TOKEN_CHARS]='\0';
+
+	/* Find beginning of configuration option parameters */
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* Trim trailing spaces from setting string */
+	for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+	{
+		if(isspace(pcCurrentPos[uCount]))
+		{
+			pcCurrentPos[uCount]='\0';
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	strcpy(szString, pcCurrentPos);
+}
diff --git a/src/doors/clans-devkit/makepak.c b/src/doors/clans-devkit/makepak.c
new file mode 100644
index 0000000000000000000000000000000000000000..5a545d6832456e76087d18f17c57781e978e77dd
--- /dev/null
+++ b/src/doors/clans-devkit/makepak.c
@@ -0,0 +1,225 @@
+// MakePak -- creates .PAK file using PAK.LST file
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __MSDOS__
+# include <alloc.h>
+# include <malloc.h>
+#else /* !__MSDOS__ */
+# define farmalloc malloc
+# define farfree free
+#endif /* __MSDOS__ */
+#include <ctype.h>
+#include "defines.h"
+
+#define MAX_TOKEN_CHARS 32
+
+// Structures
+struct __attribute__((packed)) FileHeader {
+    FILE *fp;
+    char szFileName[30];
+    long lStart, lEnd, lFileSize;
+} PACKED;
+
+// Functions
+void GetToken ( char *szString, char *szToken );
+void AddToPak(char *pszFileName, char *pszFileAlias, FILE *fpPakFile);
+
+// Global Data
+long lPakSize;
+
+int main ( int argc, char *argv[])
+{
+    FILE *fpPakFile, *fpList;
+    char szFileName[30], szFileAlias[30];       // filealias = filename in .pak
+    char szLine[255], szPakName[30], szPakList[30];
+
+    printf("MAKEPAK utility by Allen Ussher\n\n");
+
+    if (argc != 3)
+    {
+        printf("Format:  MAKEPAK [.PAK to produce] [PAKfile listing]\n");
+        exit(0);
+    }
+
+
+    if (argc == 3)
+    {
+        strcpy(szPakName, argv[1]);
+        strcpy(szPakList, argv[2]);
+    }
+    else
+    {
+        strcpy(szPakName, "mypak.pak");
+        strcpy(szPakList, "pak.lst");
+    }
+
+    fpPakFile = fopen(szPakName, "wb");
+    if (!fpPakFile)
+    {
+        printf("can't open %s\n", szPakName);
+        exit(0);
+    }
+
+    fpList = fopen(szPakList, "r");
+    if (!fpList)
+    {
+        printf("can't open %s\n", szPakList);
+        fclose(fpPakFile);
+        exit(0);
+    }
+
+    lPakSize = 0;
+
+    for (;;)
+    {
+        if (fgets(szLine, 255, fpList) == NULL)
+            break;
+
+        // skip blank lines
+        if (szLine[0] == '\r' || szLine[0] == '#' || szLine[0] == '\n')
+            continue;
+
+        GetToken(szLine, szFileName);
+        GetToken(szLine, szFileAlias);
+
+        printf("Processing %-20s %-20s\n", szFileName, szFileAlias);
+
+        if (szFileName[0] == 0 || szFileAlias[0] == 0)
+            break;
+
+
+        AddToPak(szFileName, szFileAlias, fpPakFile);
+    }
+
+    fclose(fpPakFile);
+    fclose(fpList);
+	return(0);
+}
+
+void AddToPak(char *pszFileName, char *pszFileAlias, FILE *fpPakFile)
+{
+    struct FileHeader FileHeader;
+    FILE *fpInput;
+    long CurByte, NumBytes;
+    char FAR *Chunk;
+
+    fpInput = fopen(pszFileName, "rb");
+    if (!fpInput)
+    {
+        printf("Couldn't read in %s\n", pszFileName);
+        return;
+    }
+
+    lPakSize += sizeof(struct FileHeader);
+
+    // get size of file
+    fseek(fpInput, 0L, SEEK_END);
+    FileHeader.lFileSize = ftell(fpInput);
+
+    // go back to start of file
+    fseek(fpInput, 0L, SEEK_SET);
+
+    // get header info
+    strcpy (FileHeader.szFileName, pszFileAlias);
+    FileHeader.lStart = lPakSize;
+    FileHeader.lEnd = lPakSize + FileHeader.lFileSize;
+    lPakSize += FileHeader.lFileSize;
+
+    // write header to pakfile
+    fwrite(&FileHeader, sizeof(struct FileHeader), 1, fpPakFile);
+
+    // read in file and transfer to pakfile
+    CurByte = 0;
+    NumBytes = FileHeader.lFileSize;
+
+	Chunk = (char FAR *) farmalloc (64000);
+	if (!Chunk)
+	{
+		fputs ("out of memory!", stderr);
+		fflush (stderr);
+		exit (1);
+	}
+    while (CurByte != FileHeader.lFileSize)
+	{
+		if (NumBytes > 64000L)
+		{
+            fread (Chunk, 64000L, 1, fpInput);
+            fwrite(Chunk, 64000L, 1, fpPakFile);
+
+			NumBytes -= 64000L;
+			CurByte += 64000L;
+		}
+		else
+		{
+            fread (Chunk, NumBytes, 1, fpInput);
+            fwrite(Chunk, NumBytes, 1, fpPakFile);
+
+			CurByte += NumBytes;
+			NumBytes -= NumBytes;
+		}
+	}
+
+    fclose(fpInput);
+
+	farfree (Chunk);
+}
+
+void GetToken ( char *szString, char *szToken )
+{
+	char *pcCurrentPos;
+	unsigned int uCount;
+
+	/* Ignore all of line after comments or CR/LF char */
+	pcCurrentPos=(char *)szString;
+	while(*pcCurrentPos)
+	{
+		if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r')
+		{
+			*pcCurrentPos='\0';
+			break;
+		}
+		++pcCurrentPos;
+	}
+
+	/* Search for beginning of first token on line */
+	pcCurrentPos = (char *)szString;
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* If no token was found, proceed to process the next line */
+	if(!*pcCurrentPos)
+	{
+		szToken[0] = 0;
+		szString[0] = 0;
+		return;
+	}
+
+	/* Get first token from line */
+	uCount=0;
+	while(*pcCurrentPos && !isspace(*pcCurrentPos))
+	{
+        if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+		++pcCurrentPos;
+	}
+	if(uCount<=MAX_TOKEN_CHARS)
+		szToken[uCount]='\0';
+	else
+		szToken[MAX_TOKEN_CHARS]='\0';
+
+	/* Find beginning of configuration option parameters */
+	while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+	/* Trim trailing spaces from setting string */
+	for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+	{
+		if(isspace(pcCurrentPos[uCount]))
+		{
+			pcCurrentPos[uCount]='\0';
+		}
+		else
+		{
+			break;
+		}
+	}
+	strcpy(szString, pcCurrentPos);
+}
diff --git a/src/doors/clans-devkit/makepak.txt b/src/doors/clans-devkit/makepak.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d532d7a091ca8043ce78ed6d1fe562a0ba195aef
--- /dev/null
+++ b/src/doors/clans-devkit/makepak.txt
@@ -0,0 +1,7 @@
+
+Makepak is used to generate an archive file containing all files listed
+in the PAKfile listing.
+
+Format:  MAKEPAK [.PAK to produce] [PAKfile listing]
+
+A sample pakfile list is pak.lst.  It's just a text file.
\ No newline at end of file
diff --git a/src/doors/clans-devkit/mclass.c b/src/doors/clans-devkit/mclass.c
new file mode 100644
index 0000000000000000000000000000000000000000..01973284b05f21ef15852dadc85f940ab990447a
--- /dev/null
+++ b/src/doors/clans-devkit/mclass.c
@@ -0,0 +1,226 @@
+// MClass -- makes classes.dat (and races.dat)
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef __MSDOS__
+#include <malloc.h>
+#endif /* __MSDOS__ */
+
+/*
+typedef char               BOOL;           // Boolean value, at least 1 bit. 
+-- BOOL is defined by defines.h, included in structs.h
+*/
+#include "structs.h"
+#include "keywords.h"
+
+/* defined by 'defines.h' 
+#define TRUE    1
+#define FALSE   0
+*/
+
+struct PClass *PClasses[MAX_PCLASSES], *Races[MAX_PCLASSES];
+
+int TotalItems, TotalRaces = 0, TotalClasses = 0, TotalSpells;
+
+void Deinit_PClasses( struct PClass *PClass[MAX_PCLASSES]);
+int Init_PClasses ( struct PClass *PClass[MAX_PCLASSES], char *szFileName );
+
+int main ( void )
+{
+    FILE *fpData;
+    int iTemp;
+/*    int StringLength;*/
+
+    TotalRaces = Init_PClasses (Races, "races.txt");
+    TotalClasses = Init_PClasses (PClasses, "classes.txt");
+
+    fpData = fopen("races.dat", "wb");
+
+    /* fwrite num of races */
+    printf("Writing %d races.\n", TotalRaces);
+    fwrite(&TotalRaces, sizeof(_INT16), 1, fpData);
+    for (iTemp = 0; iTemp < TotalRaces; iTemp++)
+        fwrite(Races[iTemp], sizeof(struct PClass), 1, fpData);
+
+    fclose(fpData);
+
+    fpData = fopen("classes.dat", "wb");
+    if (!fpData)
+        printf("DOH\n");
+
+    /* fwrite num of classes */
+    printf("Writing %d classes.\n", TotalClasses);
+    fwrite(&TotalClasses, sizeof(_INT16), 1, fpData);
+    for (iTemp = 0; iTemp < TotalClasses; iTemp++)
+        fwrite(PClasses[iTemp], sizeof(struct PClass), 1, fpData);
+
+    fclose(fpData);
+
+	Deinit_PClasses(PClasses);
+	Deinit_PClasses(Races);
+	return(0);
+}
+
+void Deinit_PClasses( struct PClass *PClass[MAX_PCLASSES])
+{
+	int iTemp;
+
+	for (iTemp = 0; iTemp < MAX_PCLASSES; iTemp++)
+	{
+		if (PClass[iTemp])
+			free(PClass[iTemp]);
+	}
+}
+
+int Init_PClasses ( struct PClass *PClass[MAX_PCLASSES], char *szFileName )
+{
+	FILE *fpPClass;
+	char szLine[255], *pcCurrentPos/*, szString[255]*/;
+	char szToken[MAX_TOKEN_CHARS + 1]/*, *pcAt*/;
+	unsigned int uCount;
+	int iKeyWord;
+	int CurPClass = -1;
+	int iTemp, /*OrigPClass,*/ LastSpellSlot=0;
+
+	fpPClass = fopen(szFileName, "r");
+	if (!fpPClass)
+	{
+        printf("Error opening classes file.\n");
+		exit(0);
+	}
+
+	/* make all classes NULL pointers */
+	for (iTemp = 0; iTemp < MAX_PCLASSES; iTemp++)
+		PClass[iTemp] = NULL;
+
+	for (;;)
+	{
+		/* read in a line */
+		if (fgets(szLine, 255, fpPClass) == NULL) break;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos)
+		{
+			/* skip all comment lines */
+			if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+			   || *pcCurrentPos == '%' || *pcCurrentPos == '#')
+			{
+				*pcCurrentPos='\0';
+				break;
+			}
+			++pcCurrentPos;
+		 }
+
+		/* Search for beginning of first token on line */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+		/* Get first token from line */
+		uCount=0;
+		while(*pcCurrentPos && !isspace(*pcCurrentPos))
+		{
+			if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+			++pcCurrentPos;
+		}
+		if(uCount<=MAX_TOKEN_CHARS)
+			szToken[uCount]='\0';
+		else
+			szToken[MAX_TOKEN_CHARS]='\0';
+
+		/* Find beginning of keyword parameter */
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* Trim trailing spaces from setting string */
+		for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+		{
+			if(isspace(pcCurrentPos[uCount]))
+			{
+				pcCurrentPos[uCount]='\0';
+			}
+		else
+			{
+				break;
+			}
+		}
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+		for(iKeyWord = 0; iKeyWord < MAX_PCLASS_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+			if(_STRCASECMP(szToken, papszPClassKeyWords[iKeyWord]) == 0)
+			{
+				/* Process token */
+				switch (iKeyWord)
+				{
+					case 0 :	/* NAME of class */
+						/* see if out of classes memory yet */
+						++CurPClass;
+						if (CurPClass == MAX_PCLASSES)
+						{
+							break;
+						}
+
+						/* allocate mem for this room */
+						PClass[CurPClass] = malloc(sizeof(struct PClass));
+                        memset(PClass[CurPClass], 0, sizeof(struct PClass));
+
+						/* initialize it */
+						for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+							PClass[CurPClass]->Attributes[iTemp] = 0;
+
+						PClass[CurPClass]->MaxHP = 10;
+						PClass[CurPClass]->MaxSP = 10;
+						PClass[CurPClass]->Gold = 0;
+
+						strcpy(PClass[CurPClass]->szName, pcCurrentPos);
+
+						/* set known spells to none */
+						for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+							PClass[CurPClass]->SpellsKnown[iTemp] = 0;
+						LastSpellSlot = 0;
+
+						break;
+					case 1 :	/* Agility */
+					case 2 :	/* Dexterity */
+					case 3 :	/* Strength */
+					case 4 :	/* Wisdom */
+					case 5 :	/* ArmorStr */
+					case 6 :	/* Charisma */
+						PClass[CurPClass]->Attributes[iKeyWord - 1] = atoi(pcCurrentPos);
+						break;
+					case 7 :	/* MaxHP */
+						PClass[CurPClass]->MaxHP = atoi(pcCurrentPos);
+						break;
+					case 8 :	/* Gold */
+						PClass[CurPClass]->Gold = atoi(pcCurrentPos);
+						break;
+					case 9 :	/* MaxSP */
+						PClass[CurPClass]->MaxSP = atoi(pcCurrentPos);
+						break;
+					case 10 :	/* spell */
+						PClass[CurPClass]->SpellsKnown[LastSpellSlot] = atoi(pcCurrentPos);
+						LastSpellSlot++;
+						break;
+				}
+				break;
+			}
+		}
+	}
+
+	/* since they started at -1 and not 0 */
+	CurPClass++;
+
+	fclose(fpPClass);
+
+    return (CurPClass);
+}
diff --git a/src/doors/clans-devkit/mclass.txt b/src/doors/clans-devkit/mclass.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4790ec89c705fd9cfd39438bf733dafeee84bb6c
--- /dev/null
+++ b/src/doors/clans-devkit/mclass.txt
@@ -0,0 +1,8 @@
+
+Use this to generate player classes and races.  Data goes in the following
+two files:
+
+races.txt and classes.txt
+
+These are included.  To compile them, just run mclass directly and
+it'll open the files and write races.dat and classes.dat, respectively.
\ No newline at end of file
diff --git a/src/doors/clans-devkit/mcomp.c b/src/doors/clans-devkit/mcomp.c
new file mode 100644
index 0000000000000000000000000000000000000000..a13eca50ffc99a538f40b9440042f24dc6e9efb6
--- /dev/null
+++ b/src/doors/clans-devkit/mcomp.c
@@ -0,0 +1,282 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/* Monster Compiler */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <string.h>
+//#include "opendoor.h"
+#include "structs.h"
+
+#define TRUE                1
+#define FALSE               0
+#define MAX_SPELLS          40
+#define MAX_MEMBERS         20
+#define MAX_ITEMS_HELD      30
+#define MAX_MONSTERS        255
+#define MAX_MON_WORDS       14
+#define MAX_TOKEN_CHARS     32
+#define NUM_ATTRIBUTES      6
+
+char *papszMonKeyWords[MAX_MON_WORDS] =
+{
+    "Name",
+    "HP",
+    "Agility",
+    "Dexterity",
+    "Strength",
+    "Wisdom",
+    "ArmorStr",
+    "Weapon",
+    "Shield",
+    "Armor",
+    "Difficulty",
+    "SP",
+    "Spell",
+    "Undead"
+	"Charisma"
+};
+
+struct pc TmpMonster;
+
+int main ( int argc, char *argv[] )
+{
+    FILE *fpMonIn, *fpMonOut;
+	char szLine[255], *pcCurrentPos;
+	char szToken[MAX_TOKEN_CHARS + 1];
+	unsigned _INT16 uCount;
+	_INT16 iKeyWord;
+    _INT16 iTemp;
+    _INT16 MonIndex[MAX_MONSTERS];  /* difficulties of all monsters,
+                                    0 means no monster */
+    _INT16 CurMonster = -1, LastSpellSlot=0;
+
+    if (argc != 3)
+    {
+        printf("Format:  mcomp <monster.txt> <output.mon>\n\n");
+        exit(0);
+    }
+
+    fpMonIn = fopen(argv[1], "r");
+    if (!fpMonIn)
+	{
+        printf("Error opening %s.\n", argv[1]);
+        exit(0);
+	}
+
+    fpMonOut = fopen(argv[2], "w+b");
+    if (!fpMonOut)
+	{
+        printf("Error opening %s.\n", argv[2]);
+        exit(0);
+	}
+
+    /* generate index while doing list */
+
+    /* for now, write a blank index */
+    for (iTemp = 0; iTemp < MAX_MONSTERS; iTemp++)
+        MonIndex[iTemp] = 0;
+
+    fwrite(MonIndex, sizeof(MonIndex), 1, fpMonOut);
+
+    for (;;)
+	{
+		/* read in a line */
+        if (fgets(szLine, 255, fpMonIn) == NULL) break;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos)
+		{
+            /* skip all comment lines */
+			if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+			   || *pcCurrentPos == '%' || *pcCurrentPos == '#')
+			{
+				*pcCurrentPos='\0';
+				break;
+			}
+			++pcCurrentPos;
+		 }
+
+		/* Search for beginning of first token on line */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+		/* Get first token from line */
+		uCount=0;
+		while(*pcCurrentPos && !isspace(*pcCurrentPos))
+		{
+			if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+			++pcCurrentPos;
+		}
+		if(uCount<=MAX_TOKEN_CHARS)
+			szToken[uCount]='\0';
+		else
+			szToken[MAX_TOKEN_CHARS]='\0';
+
+		/* Find beginning of keyword parameter */
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* Trim trailing spaces from setting string */
+		for(uCount=strlen(pcCurrentPos);uCount>0;--uCount)
+		{
+			if(isspace(pcCurrentPos[uCount]))
+			{
+				pcCurrentPos[uCount]='\0';
+			}
+		else
+			{
+				break;
+			}
+		}
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+        for(iKeyWord = 0; iKeyWord < MAX_MON_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+            if(_STRCASECMP(szToken, papszMonKeyWords[iKeyWord]) == 0)
+			{
+				/* Process token */
+				switch (iKeyWord)
+				{
+                    case 0 :    /* NAME of monster */
+                        /* write previous monster to file then */
+                        if (CurMonster != -1)
+                        {
+                            fwrite(&TmpMonster, sizeof(struct pc), 1, fpMonOut);
+                        }
+
+                        /* see if out of items memory yet */
+                        ++CurMonster;
+                        if (CurMonster == MAX_MONSTERS)
+						{
+							break;
+						}
+
+                        /* initialize it */
+                        memset(&TmpMonster, 0, sizeof(struct pc));
+                        strcpy(TmpMonster.szName, pcCurrentPos);
+                        TmpMonster.HP = TmpMonster.MaxHP = 30;
+                        TmpMonster.SP = TmpMonster.MaxSP = 0;
+
+                        for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+                            TmpMonster.Attributes[iTemp] = 10;
+
+                        TmpMonster.Status = Here;
+
+                        TmpMonster.Weapon = 0;
+                        TmpMonster.Shield = 0;
+                        TmpMonster.Armor = 0;
+
+                        TmpMonster.WhichRace = -1;
+                        TmpMonster.WhichClass = -1;
+
+                        TmpMonster.Difficulty = 0;
+                        TmpMonster.Level = 0;
+                        TmpMonster.Undead = FALSE;
+
+                        for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+                            TmpMonster.SpellsKnown[iTemp] = 0;
+                        for (iTemp = 0; iTemp < 10; iTemp++)
+                            TmpMonster.SpellsInEffect[iTemp].SpellNum = -1;
+                        LastSpellSlot = 0;
+
+                        printf("Monster : %s\n", TmpMonster.szName);
+						break;
+                    case 1 :    /* HP */
+                        printf("    - hp  : %d\n", atoi(pcCurrentPos));
+                        TmpMonster.HP = TmpMonster.MaxHP = atoi(pcCurrentPos);
+						break;
+                    case 2 :    /* agility */
+                    case 3 :    /* Dexterity */
+                    case 4 :    /* Strength */
+                    case 5 :    /* Wisdom */
+                    case 6 :    /* ArmorStr */
+                        TmpMonster.Attributes[iKeyWord - 2] = atoi(pcCurrentPos);
+						break;
+                    case 7 :    /* Weapon */
+                        TmpMonster.Weapon = atoi(pcCurrentPos);
+
+                        printf("    - wep: %d\n", TmpMonster.Weapon);
+						break;
+                    case 8 :    /* Shield */
+                        TmpMonster.Shield = atoi(pcCurrentPos);
+
+                        printf("    - shi: %d\n", TmpMonster.Shield);
+						break;
+                    case 9 :    /* Armor */
+                        TmpMonster.Armor = atoi(pcCurrentPos);
+
+                        printf("    - amr: %d\n", TmpMonster.Armor);
+						break;
+                    case 10 :    /* difficulty */
+                        TmpMonster.Difficulty =
+                            MonIndex[CurMonster] = atoi(pcCurrentPos);
+
+                        TmpMonster.Level = TmpMonster.Difficulty;
+
+                        printf("    - dif: %d\n", MonIndex[CurMonster]);
+						break;
+                    case 11 :    /* SP */
+                        printf("    - sp  : %d\n", atoi(pcCurrentPos));
+                        TmpMonster.SP = TmpMonster.MaxSP = atoi(pcCurrentPos);
+						break;
+                    case 12 :   /* spell! */
+                        TmpMonster.SpellsKnown[LastSpellSlot] = atoi(pcCurrentPos);
+                        LastSpellSlot++;
+                        break;
+                    case 13 :   // undead
+                        TmpMonster.Undead = TRUE;
+                        break;
+					case 14 : /* charisma */
+						TmpMonster.Attributes[5] = atoi(pcCurrentPos);
+						break;
+				}
+				break;
+			}
+		}
+    }
+
+    /* write last monster */
+    fwrite(&TmpMonster, sizeof(struct pc), 1, fpMonOut);
+
+    /* rewrite index */
+    fseek(fpMonOut, 0L, SEEK_SET);
+    fwrite(MonIndex, sizeof(MonIndex), 1, fpMonOut);
+
+	/* since they started at -1 and not 0 */
+    CurMonster++;
+
+    printf("%d Monster found.\n%ld bytes used", CurMonster, (long) CurMonster*sizeof(struct pc));
+
+    fclose(fpMonIn);
+    fclose(fpMonOut);
+
+	return(0);
+}
diff --git a/src/doors/clans-devkit/mcomp.txt b/src/doors/clans-devkit/mcomp.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9ee2b04f92ae59256f78b6e78fe0bcc53a964ab6
--- /dev/null
+++ b/src/doors/clans-devkit/mcomp.txt
@@ -0,0 +1,2 @@
+This compiles monster data files.  See the sample monsters.txt file.  Just run
+it to see the command-line format.  Pretty simple.
\ No newline at end of file
diff --git a/src/doors/clans-devkit/mitems.c b/src/doors/clans-devkit/mitems.c
new file mode 100644
index 0000000000000000000000000000000000000000..357a9359044d677605e83482d65450eab15de80c
--- /dev/null
+++ b/src/doors/clans-devkit/mitems.c
@@ -0,0 +1,310 @@
+// MItems -- make items
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __MSDOS__
+#include <malloc.h>
+#endif /* __MSDOS__ */
+
+/*
+typedef char               BOOL;           // Boolean value, at least 1 bit. 
+-- BOOL is defined in 'defines.h' included by structs.h
+*/
+// #include "cinclude.h"
+#include "structs.h"
+#include "keywords.h"
+
+/* Defined in 'defines.h'
+#define TRUE    1
+#define FALSE   0
+*/
+
+#define NPCS_NOTHERE    0   // status of NPC, not here -- i.e. not in town
+#define NPCS_HERE       1
+
+struct item_data *Items[MAX_ITEMS];
+
+int TotalItems, TotalRaces, TotalClasses, TotalSpells;
+
+void Init_Items ( char *szFileName );
+void Deinit_Items( void );
+
+
+// 04/03/2002 [au]
+// forgive me, this is a hack.  i don't remember what these were defined as, so i'm gonna make it up here
+#define ITM_STAT 0
+#define ITM_REQ 1
+#define ITM_PEN 2
+
+int main ( int argc, char *argv[] )
+{
+    FILE *fpData;
+    int iTemp;
+
+    if (argc != 3)
+    {
+        printf("usage:\nmitems items.txt items.dat\n");
+        exit(0);
+    }
+
+
+    Init_Items(argv[1]);
+
+    fpData = fopen(argv[2], "wb");
+
+    /* fwrite number of items */
+    printf("Writing %d items.\n", TotalItems);
+    fwrite(&TotalItems, sizeof(_INT16), 1, fpData);
+    for (iTemp = 0; iTemp < TotalItems; iTemp++)
+        fwrite(Items[iTemp], sizeof(struct item_data), 1, fpData);
+
+    fclose(fpData);
+
+    Deinit_Items();
+	return(0);
+}
+
+void Deinit_Items( void )
+{
+	int iTemp;
+
+	for (iTemp = 0; iTemp < MAX_ITEMS; iTemp++)
+	{
+		if (Items[iTemp])
+			free(Items[iTemp]);
+	}
+}
+
+void Init_Items ( char *szFileName )
+{
+	FILE *fpItems;
+	char szLine[255], *pcCurrentPos;
+	char szToken[MAX_TOKEN_CHARS + 1];
+	unsigned int uCount;
+	int iKeyWord;
+	int CurItem = -1;
+	int iTemp;
+	char TypeOfStat=0;
+
+	fpItems = fopen(szFileName, "r");
+	if (!fpItems)
+	{
+		printf("Error opening items file.\n");
+		exit(0);
+	}
+
+	/* make all items NULL pointers */
+	for (iTemp = 0; iTemp < MAX_ITEMS; iTemp++)
+		Items[iTemp] = NULL;
+
+	for (;;)
+	{
+		/* read in a line */
+		if (fgets(szLine, 255, fpItems) == NULL) break;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos)
+		{
+			/* skip all comment lines */
+			if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+			   || *pcCurrentPos == '%' || *pcCurrentPos == '#')
+			{
+				*pcCurrentPos='\0';
+				break;
+			}
+			++pcCurrentPos;
+		 }
+
+		/* Search for beginning of first token on line */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+		/* Get first token from line */
+		uCount=0;
+		while(*pcCurrentPos && !isspace(*pcCurrentPos))
+		{
+			if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+			++pcCurrentPos;
+		}
+		if(uCount<=MAX_TOKEN_CHARS)
+			szToken[uCount]='\0';
+		else
+			szToken[MAX_TOKEN_CHARS]='\0';
+
+		/* Find beginning of keyword parameter */
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* Trim trailing spaces from setting string */
+		for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+		{
+			if(isspace(pcCurrentPos[uCount]))
+			{
+				pcCurrentPos[uCount]='\0';
+			}
+		else
+			{
+				break;
+			}
+		}
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+		for(iKeyWord = 0; iKeyWord < MAX_IM_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+			if(_STRCASECMP(szToken, papszItemKeyWords[iKeyWord]) == 0)
+			{
+				/* Process token */
+				switch (iKeyWord)
+				{
+					case 0 :	/* NAME of item */
+						/* see if out of items memory yet */
+						++CurItem;
+						if (CurItem == MAX_ITEMS)
+						{
+							break;
+						}
+
+						/* allocate mem for this room */
+						Items[CurItem] = malloc(sizeof(struct item_data));
+                        memset(Items[CurItem], 0, sizeof(struct item_data));
+
+						TypeOfStat = ITM_STAT;
+
+						/* initialize it */
+                        Items[CurItem]->Special = FALSE;
+                        Items[CurItem]->cType = I_OTHER;
+
+
+						for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+						{
+							Items[CurItem]->Attributes[iTemp] = 0;
+							Items[CurItem]->ReqAttributes[iTemp] = 0;
+						}
+
+						Items[CurItem]->lCost = 0;
+						Items[CurItem]->DiffMaterials = FALSE;
+                        Items[CurItem]->Energy = 300;
+                        Items[CurItem]->MarketLevel = 0;
+
+                        Items[CurItem]->VillageType = V_ALL;
+                        Items[CurItem]->RandLevel = 0;
+                        Items[CurItem]->HPAdd = 0;
+                        Items[CurItem]->SPAdd = 0;
+                        Items[CurItem]->SpellNum = -1;  // no spell
+
+						strcpy(Items[CurItem]->szName, pcCurrentPos);
+
+                        printf("%2d: %s\n", CurItem, Items[CurItem]->szName);
+
+						break;
+					case 1 :	/* Type */
+						if (_STRCASECMP(pcCurrentPos, "Weapon") == 0)
+						{
+							Items[CurItem]->cType = I_WEAPON;
+						}
+						else if (_STRCASECMP(pcCurrentPos, "Armor") == 0)
+						{
+							Items[CurItem]->cType = I_ARMOR;
+						}
+						else if (_STRCASECMP(pcCurrentPos, "Shield") == 0)
+						{
+							Items[CurItem]->cType = I_SHIELD;
+						}
+                        else if (_STRCASECMP(pcCurrentPos, "Scroll") == 0)
+						{
+                            Items[CurItem]->cType = I_SCROLL;
+						}
+                        else if (_STRCASECMP(pcCurrentPos, "Book") == 0)
+						{
+                            Items[CurItem]->cType = I_BOOK;
+						}
+                        else if (_STRCASECMP(pcCurrentPos, "Other") == 0)
+						{
+                            Items[CurItem]->cType = I_OTHER;
+						}
+						break;
+                    case 2 :    /* Special */
+                        Items[CurItem]->Special = TRUE;
+						break;
+					case 3 :	/* Agility */
+					case 4 :	/* Dexterity */
+					case 5 :	/* Strength */
+					case 6 :	/* Wisdom */
+					case 7 :	/* Armor */
+					case 8 :	/* Charisma */
+						if (TypeOfStat == ITM_STAT)
+						{
+							Items[CurItem]->Attributes[iKeyWord - 3] = atoi(pcCurrentPos);
+						}
+						else if (TypeOfStat == ITM_REQ)
+						{
+							Items[CurItem]->ReqAttributes[iKeyWord - 3] = atoi(pcCurrentPos);
+						}
+						break;
+					case 9 :	/* Cost */
+						Items[CurItem]->lCost = atol(pcCurrentPos);
+						break;
+					case 10 :	 /* DiffMaterials */
+						Items[CurItem]->DiffMaterials = TRUE;
+						break;
+					case 11 :	/* normal stats */
+						TypeOfStat = ITM_STAT;
+						break;
+					case 12 :	/* requirements */
+						TypeOfStat = ITM_REQ;
+						break;
+					case 13 :	/* penalties */
+						TypeOfStat = ITM_PEN;
+						break;
+                    case 14 :    /* Energy */
+                        Items[CurItem]->Energy = atoi(pcCurrentPos);
+						break;
+                    case 15 :    /* Uses */
+                        Items[CurItem]->Energy = atoi(pcCurrentPos);
+						break;
+                    case 16 :    /* Spell # */
+                        Items[CurItem]->SpellNum = atoi(pcCurrentPos) - 1;
+                        printf("spellnum = %d\n", Items[CurItem]->SpellNum);
+						break;
+                    case 17 :    /* Market Level */
+                        Items[CurItem]->MarketLevel = atoi(pcCurrentPos);
+						break;
+                    case 18 :   // villagetypes
+                        if (!_STRCASECMP(pcCurrentPos, "ALL"))
+                            Items[CurItem]->VillageType = V_ALL;
+                        else
+                            Items[CurItem]->VillageType = atoi(pcCurrentPos);
+                        break;
+                    case 19 :   // randlevel
+                        Items[CurItem]->RandLevel = atoi(pcCurrentPos);
+                        break;
+                    case 20 :   // HP
+                        Items[CurItem]->HPAdd = atoi(pcCurrentPos);
+                        break;
+                    case 21 :   // SP
+                        Items[CurItem]->SPAdd = atoi(pcCurrentPos);
+                        break;
+				}
+				break;
+			}
+		}
+	}
+
+	/* since they started at -1 and not 0 */
+	CurItem++;
+
+    TotalItems = CurItem;
+	//pause();
+
+	fclose(fpItems);
+}
diff --git a/src/doors/clans-devkit/mitems.txt b/src/doors/clans-devkit/mitems.txt
new file mode 100644
index 0000000000000000000000000000000000000000..154fb4325aa971440f42485ce512ebef87c56dad
--- /dev/null
+++ b/src/doors/clans-devkit/mitems.txt
@@ -0,0 +1,2 @@
+
+Use this to generate items.
\ No newline at end of file
diff --git a/src/doors/clans-devkit/mspells.c b/src/doors/clans-devkit/mspells.c
new file mode 100644
index 0000000000000000000000000000000000000000..2c01626cd446197050d7061f8987e6f8d418c72f
--- /dev/null
+++ b/src/doors/clans-devkit/mspells.c
@@ -0,0 +1,405 @@
+// MSpells -- make spells
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef __MSDOS__
+#include <malloc.h>
+#endif /* __MSDOS__ */
+
+/* defined by 'defines.h' included by 'structs.h'
+typedef char               BOOL;           // Boolean value, at least 1 bit. */
+// #include "cinclude.h"
+#include "structs.h"
+#include "keywords.h"
+
+/* defined in 'defines.h'
+#define TRUE    1
+#define FALSE   0
+*/
+
+struct Spell *Spells[MAX_SPELLS];
+
+int TotalSpells;
+
+void Deinit_Spells( struct Spell *Spells[MAX_SPELLS]);
+void Init_Spells ( struct Spell *Spells[MAX_SPELLS], char *szFileName );
+
+int main ( int argc, char *argv[] )
+{
+    FILE *fpData;
+    int iTemp;
+    int StringLength;
+
+    printf("MSpells FUW/91b1+\n");
+
+    if (argc != 3)
+    {
+        printf("Format:  mspells <spells.txt> <spells.dat>\n\n");
+        exit(0);
+    }
+
+    Init_Spells ( Spells, argv[1]);
+
+    fpData = fopen(argv[2], "wb");
+    if (!fpData) return(1);
+
+    /* fwrite num of spells */
+    printf("-- Writing %d spells.\n\n", TotalSpells);
+    fwrite(&TotalSpells, sizeof(_INT16), 1, fpData);
+    for (iTemp = 0; iTemp < TotalSpells; iTemp++)
+    {
+        fwrite(Spells[iTemp], sizeof(struct Spell), 1, fpData);
+
+        /* fwrite strings */
+        if (Spells[iTemp]->pszDamageStr)
+            StringLength = strlen(Spells[iTemp]->pszDamageStr) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszDamageStr, StringLength, 1, fpData);
+
+        if (Spells[iTemp]->pszHealStr)
+            StringLength = strlen(Spells[iTemp]->pszHealStr) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszHealStr, StringLength, 1, fpData);
+
+        if (Spells[iTemp]->pszModifyStr)
+            StringLength = strlen(Spells[iTemp]->pszModifyStr) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszModifyStr, StringLength, 1, fpData);
+
+        if (Spells[iTemp]->pszWearoffStr)
+            StringLength = strlen(Spells[iTemp]->pszWearoffStr) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszWearoffStr, StringLength, 1, fpData);
+
+        if (Spells[iTemp]->pszStatusStr)
+            StringLength = strlen(Spells[iTemp]->pszStatusStr) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszStatusStr, StringLength, 1, fpData);
+
+        if (Spells[iTemp]->pszOtherStr)
+            StringLength = strlen(Spells[iTemp]->pszOtherStr) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszOtherStr, StringLength, 1, fpData);
+
+        if (Spells[iTemp]->pszUndeadName)
+            StringLength = strlen(Spells[iTemp]->pszUndeadName) + 1;
+        else
+            StringLength = 0;
+
+        fwrite(&StringLength, sizeof(_INT16), 1, fpData);
+        if (StringLength)
+            fwrite(Spells[iTemp]->pszUndeadName, StringLength, 1, fpData);
+    }
+
+    fclose(fpData);
+
+    Deinit_Spells(Spells);
+	return(0);
+}
+
+void Deinit_Spells( struct Spell *Spells[MAX_SPELLS])
+{
+    int iTemp;
+
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+    {
+        if (Spells[iTemp])
+        {
+            /* free strings first */
+            if (Spells[iTemp]->pszHealStr)
+                free(Spells[iTemp]->pszHealStr);
+            if (Spells[iTemp]->pszUndeadName)
+                free(Spells[iTemp]->pszUndeadName);
+            if (Spells[iTemp]->pszDamageStr)
+                free(Spells[iTemp]->pszDamageStr);
+            if (Spells[iTemp]->pszModifyStr)
+                free(Spells[iTemp]->pszModifyStr);
+            if (Spells[iTemp]->pszWearoffStr)
+                free(Spells[iTemp]->pszWearoffStr);
+            if (Spells[iTemp]->pszStatusStr)
+                free(Spells[iTemp]->pszStatusStr);
+            if (Spells[iTemp]->pszOtherStr)
+                free(Spells[iTemp]->pszOtherStr);
+
+            free(Spells[iTemp]);
+        }
+    }
+}
+
+void Init_Spells ( struct Spell *Spells[MAX_SPELLS], char *szFileName )
+{
+    FILE *fpSpell;
+	char szLine[255], *pcCurrentPos;
+	char szToken[MAX_TOKEN_CHARS + 1];
+	unsigned int uCount;
+	int iKeyWord;
+    int CurSpell = -1;
+    int iTemp;
+
+    fpSpell = fopen(szFileName, "r");
+    if (!fpSpell)
+	{
+        printf("\aError opening spells file %s.\n", szFileName);
+		exit(0);
+	}
+
+    /* make all spells NULL pointers */
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+        Spells[iTemp] = NULL;
+
+	for (;;)
+	{
+		/* read in a line */
+        if (fgets(szLine, 255, fpSpell) == NULL) break;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos)
+		{
+            /* skip all comment lines */
+			if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+               || *pcCurrentPos == '#')
+			{
+				*pcCurrentPos='\0';
+				break;
+			}
+			++pcCurrentPos;
+		 }
+
+		/* Search for beginning of first token on line */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+		/* Get first token from line */
+		uCount=0;
+		while(*pcCurrentPos && !isspace(*pcCurrentPos))
+		{
+			if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+			++pcCurrentPos;
+		}
+		if(uCount<=MAX_TOKEN_CHARS)
+			szToken[uCount]='\0';
+		else
+			szToken[MAX_TOKEN_CHARS]='\0';
+
+		/* Find beginning of keyword parameter */
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* Trim trailing spaces from setting string */
+		for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+		{
+			if(isspace(pcCurrentPos[uCount]))
+			{
+				pcCurrentPos[uCount]='\0';
+			}
+		else
+			{
+				break;
+			}
+		}
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+        for(iKeyWord = 0; iKeyWord < MAX_SPELL_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+            if(_STRCASECMP(szToken, papszSpellKeyWords[iKeyWord]) == 0)
+			{
+				/* Process token */
+				switch (iKeyWord)
+				{
+                    case 0 :    /* NAME of spell */
+                        /* see if out of spells memory yet */
+                        ++CurSpell;
+                        if (CurSpell == MAX_SPELLS)
+						{
+							break;
+						}
+
+                        printf("%s", pcCurrentPos);
+                        if (CurSpell % 10 == 0 && CurSpell)
+                            printf("\n");
+                        else
+                            printf(", ");
+
+						/* allocate mem for this room */
+                        Spells[CurSpell] = malloc(sizeof(struct Spell));
+                        memset(Spells[CurSpell], 0, sizeof(struct Spell));
+
+                        /* initialize it */
+                        for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+                            Spells[CurSpell]->Attributes[iTemp] = 0;
+
+                        Spells[CurSpell]->Level = 0;    /* 0 == doesn't matter */
+                        Spells[CurSpell]->Value = 0;
+                        Spells[CurSpell]->Energy = 40;
+                        Spells[CurSpell]->pszDamageStr = NULL;
+                        Spells[CurSpell]->pszHealStr = NULL;
+                        Spells[CurSpell]->pszModifyStr = NULL;
+                        Spells[CurSpell]->pszWearoffStr = NULL;
+                        Spells[CurSpell]->pszStatusStr = NULL;
+                        Spells[CurSpell]->pszOtherStr = NULL;
+                        Spells[CurSpell]->pszUndeadName = NULL;
+                        Spells[CurSpell]->SP = 1;
+                        Spells[CurSpell]->Friendly = FALSE;
+                        Spells[CurSpell]->Target = TRUE;
+                        Spells[CurSpell]->StrengthCanReduce = FALSE;
+                        Spells[CurSpell]->WisdomCanReduce = FALSE;
+                        Spells[CurSpell]->MultiAffect = FALSE;
+                        Spells[CurSpell]->Garbage = FALSE;
+
+                        strcpy(Spells[CurSpell]->szName, pcCurrentPos);
+                        Spells[CurSpell]->TypeFlag = 0;
+
+                        //od_printf("SPELL: %s\n\r", Spells[CurSpell]->szName);
+						break;
+                    case 1 :    /* Agility */
+                    case 2 :    /* Dexterity */
+                    case 3 :    /* Strength */
+                    case 4 :    /* Wisdom */
+                    case 5 :    /* ArmorStr */
+                    case 6 :    /* Charisma */
+                        Spells[CurSpell]->Attributes[iKeyWord-1] = atoi(pcCurrentPos);
+
+						break;
+                    case 7 :    /* Value */
+                        Spells[CurSpell]->Value = atoi(pcCurrentPos);
+
+                        //printf("    - val: %+d\n", Spells[CurSpell]->Value);
+						break;
+                    case 8 :    /* Flag */
+                        if (_STRCASECMP(pcCurrentPos, "Heal") == 0)
+                        {
+                            //printf("is heal ");
+                            Spells[CurSpell]->TypeFlag |= SF_HEAL;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Damage") == 0)
+                        {
+                            //printf("is damage ");
+                            Spells[CurSpell]->TypeFlag |= SF_DAMAGE;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Modify") == 0)
+                        {
+                            //printf("is modify ");
+                            Spells[CurSpell]->TypeFlag |= SF_MODIFY;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "Incapacitate") == 0)
+                        {
+                            //printf("is incap ");
+                            Spells[CurSpell]->TypeFlag |= SF_INCAPACITATE;
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "RaiseUndead") == 0)
+                        {
+                            //printf("is raiseundead ");
+                            Spells[CurSpell]->TypeFlag |= SF_RAISEUNDEAD;
+                            printf("flag = %d\n", Spells[CurSpell]->TypeFlag);
+                        }
+                        else if (_STRCASECMP(pcCurrentPos, "BanishUndead") == 0)
+                        {
+                            //printf("is banish ");
+                            Spells[CurSpell]->TypeFlag |= SF_BANISHUNDEAD;
+                        }
+                        //printf("flag = %d\n", Spells[CurSpell]->TypeFlag);
+						break;
+                    case 9 :    /* HealStr */
+                        //od_printf("HealStr = %s\n\r", pcCurrentPos);
+                        Spells[CurSpell]->pszHealStr = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszHealStr, pcCurrentPos);
+						break;
+                    case 10 :    /* DamageStr */
+                        Spells[CurSpell]->pszDamageStr = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszDamageStr, pcCurrentPos);
+						break;
+                    case 11 :    /* ModifyStr */
+                        Spells[CurSpell]->pszModifyStr = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszModifyStr, pcCurrentPos);
+						break;
+                    case 12 :    /* SP */
+                        Spells[CurSpell]->SP = atoi(pcCurrentPos);
+						break;
+                    case 13 :   /* friendly */
+                        Spells[CurSpell]->Friendly = TRUE;
+                        break;
+                    case 14 :   /* notarget */
+                        Spells[CurSpell]->Target = FALSE;
+                        break;
+                    case 15 :   /* Level */
+                        Spells[CurSpell]->Level = atoi(pcCurrentPos);
+                        break;
+                    case 16 :    /* WearoffStr */
+                        Spells[CurSpell]->pszWearoffStr = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszWearoffStr, pcCurrentPos);
+						break;
+                    case 17 :    /* energy */
+                        Spells[CurSpell]->Energy = atoi(pcCurrentPos);
+						break;
+                    case 18 :    /* StatusStr */
+                        Spells[CurSpell]->pszStatusStr = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszStatusStr, pcCurrentPos);
+						break;
+                    case 19 :    /* OtherStr */
+                        Spells[CurSpell]->pszOtherStr = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszOtherStr, pcCurrentPos);
+						break;
+                    case 20 :    /* UndeadName */
+                        Spells[CurSpell]->pszUndeadName = malloc( strlen(pcCurrentPos) + 1 );
+                        strcpy(Spells[CurSpell]->pszUndeadName, pcCurrentPos);
+						break;
+                    case 21 :   /* strengthcanreduce */
+                        Spells[CurSpell]->StrengthCanReduce = FALSE;
+                        break;
+                    case 22 :   /* wisdomcanreduce */
+                        Spells[CurSpell]->WisdomCanReduce = FALSE;
+                        break;
+                    case 23 :   /* MultiAffect */
+                        Spells[CurSpell]->MultiAffect = TRUE;
+                        break;
+				}
+				break;
+			}
+		}
+	}
+
+	/* since they started at -1 and not 0 */
+    CurSpell++;
+
+    //printf("%d spells found.\n%ld bytes used", CurSpell, (long) CurSpell*sizeof(struct Spell));
+
+    fclose(fpSpell);
+
+    TotalSpells = CurSpell;
+
+}
+
diff --git a/src/doors/clans-devkit/notes.txt b/src/doors/clans-devkit/notes.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0090e854e15091b56685a055a283bd27e8e16561
--- /dev/null
+++ b/src/doors/clans-devkit/notes.txt
@@ -0,0 +1,26 @@
+Okay, here's the source for the devkit.  A couple of notes:
+
+mcomp.c may or may not work. :-)  i think it should since the structs
+didn't change much.  also, you'll notice that the structs.h and defines.h
+are redefined here. they are EXACTLY the same as the ones in the regular
+source code.  i was too lazy to put them in the proper directories, but
+you can, easily.
+
+See genall.bat for a batch file I used to generate all the data files and
+then compiled them...
+
+For more details on all of this, see clandev.txt.
+
+About the data files:
+
+strings.txt -- standard language file
+eventmon.txt -- monsters for random events
+monsters.txt -- all monsters you fight in the mines (standard fights)
+spells.txt -- all spells available to players
+items.txt -- all items
+npcs.txt -- all non-player characters you meet on the street or in events
+pray.evt -- all prayer events
+eva.txt -- all mine events (note that this ends in .txt, but is just like all the .evt events)
+quests.evt -- all quests
+church.evt -- church events
+secret.evt -- a neat little, secret event :-)
\ No newline at end of file
diff --git a/src/doors/clans-devkit/races.dat b/src/doors/clans-devkit/races.dat
new file mode 100644
index 0000000000000000000000000000000000000000..16b450b3f4211c27994054ef6b78c04b0a94b9f6
Binary files /dev/null and b/src/doors/clans-devkit/races.dat differ
diff --git a/src/doors/clans-devkit/structs.h b/src/doors/clans-devkit/structs.h
new file mode 100644
index 0000000000000000000000000000000000000000..f97923bc34bfea06149077908345812ef196122d
--- /dev/null
+++ b/src/doors/clans-devkit/structs.h
@@ -0,0 +1,671 @@
+#include "defines.h"
+
+struct __attribute__((packed)) IniFile {
+	__BOOL Initialized;
+
+	char *pszLanguage;
+	char *pszNPCFileName[MAX_NPCFILES];
+	char *pszSpells[MAX_SPELLFILES];
+	char *pszItems[MAX_ITEMFILES];
+	char *pszRaces[MAX_RACEFILES];
+	char *pszClasses[MAX_CLASSFILES];
+	char *pszVillages[MAX_VILLFILES];
+} PACKED;
+
+
+struct __attribute__((packed)) config {
+
+  char szSysopName[40];
+  char szBBSName[40];
+
+  char szScoreFile[2][40];        // 0 == ascii, 1 == ansi
+  char szRegcode[25];
+
+  /*
+   * IBBS Specific data
+   */
+  _INT16 BBSID;
+  __BOOL InterBBS;
+  char szNetmailDir[30];
+  char szInboundDir[30];
+  _INT16 MailerType;
+} PACKED;
+
+struct __attribute__((packed)) system {
+  __BOOL Initialized;
+
+  char szTodaysDate[11];
+  char szMainDir[40];
+
+  _INT16 Node;
+  __BOOL InterBBS;
+  __BOOL Local;
+  __BOOL LocalIBBS;
+} PACKED;
+
+struct __attribute__((packed)) PClass {
+	char szName[15];
+	char Attributes[NUM_ATTRIBUTES];
+	_INT16 MaxHP;
+	_INT16 Gold;
+  _INT16 MaxSP;
+  char SpellsKnown[MAX_SPELLS];
+
+	_INT16 VillageType;		// which villages is this allowed in?  0 == ALL
+} PACKED;
+
+struct __attribute__((packed)) Strategy {
+	char AttackLength, AttackIntensity, LootLevel;
+	char DefendLength, DefendIntensity;
+
+	/*
+
+-		*Length = 1..10 <- how long battle is
+
+		ex:
+		if AttackLength = 10 and defender's defendlength = 2,
+
+		NumRounds = (10 + 2) / 2 = 6;
+
+-		*Type	   =	Light		-- small attacks, less vulnerable
+						Moderate	-- moderate attacks on all grounds, medium
+						Heavy		-- heavy attacks, more vulnerable
+
+-		LootLevel = How much you will loot or attempt to loot in percentage
+
+			allowable levels:	10% - low
+								20% - moderate
+								30% - high
+
+	*/
+} PACKED;
+
+
+struct __attribute__((packed)) Army {
+	long Footmen, Axemen, Knights, Followers;
+	char Rating;						// 0-100%, 100% = strongest
+	char Level; 						// useable later?
+
+	struct __attribute__((packed)) Strategy Strategy;
+
+	long CRC;
+} PACKED;
+
+struct __attribute__((packed)) empire {
+	char szName[25];				// who's empire
+	_INT16 OwnerType;					// what type of empire? clan, alliance, vill
+	long VaultGold;
+	_INT16 Land;						// amount of land available for use
+	_INT16 Buildings[MAX_BUILDINGS];	// # of each building type
+	_INT16 AllianceID;
+	char WorkerEnergy;				// energy left for builders in %'age
+	_INT16 LandDevelopedToday; 		// how much development we did
+	_INT16 SpiesToday; 				// how many spying attempts today?
+	_INT16 AttacksToday;
+	long Points;					// used in future?
+	_INT16 Junk[4];
+
+	// other stuff goes here
+	struct __attribute__((packed)) Army Army;
+
+	long CRC;
+} PACKED;
+
+
+
+struct __attribute__((packed)) village {
+  __BOOL Initialized;
+
+  struct __attribute__((packed)) village_data {
+    char ColorScheme[50];
+    char szName[30];
+
+    _INT16 TownType;
+    _INT16 TaxRate, InterestRate, GST;
+    _INT16 ConscriptionRate;
+
+    _INT16 RulingClanId[2];
+    char szRulingClan[25];
+    _INT16 GovtSystem;
+    _INT16 RulingDays;
+
+    unsigned _INT16 PublicMsgIndex;
+
+    _INT16 MarketLevel;
+    _INT16 TrainingHallLevel;  /* how good is the training hall? */
+    _INT16 ChurchLevel;    /* how good is the church */
+    _INT16 PawnLevel;      // level of pawn shop
+    _INT16 WizardLevel;    // wizard's shop level
+
+    unsigned _INT16
+       SetTaxToday     : 1,
+       SetInterestToday: 1,
+       SetGSTToday     : 1,
+       UpMarketToday   : 1,
+       UpTHallToday    : 1,
+       UpChurchToday   : 1,
+       UpPawnToday     : 1,
+       UpWizToday      : 1,
+       SetConToday     : 1,
+       ShowEmpireStats : 1,
+       Junk            : 6;
+
+    char HFlags[8];         /* daily flags -- reset nightly */
+    char GFlags[8];         /* global flags -- reset with reset */
+
+    _INT16 VillageType;    // what type of village do we have here?
+
+    _INT16 CostFluctuation;  // from -10% to +10%
+    _INT16 MarketQuality;
+
+    struct __attribute__((packed)) empire Empire;
+
+    long CRC;                 // used to prevent cheating
+  } *Data;
+} PACKED;
+
+struct __attribute__((packed)) game {
+  __BOOL Initialized;
+
+  struct __attribute__((packed)) game_data {
+    _INT16 GameState;            // 0 == Game is in progress
+                              // 1 == Game is waiting for day to come to play
+                              // 2 == Game is inactive, waiting for reset msg.
+                              //      from LC
+
+    __BOOL InterBBS;            // set to TRUE if IBBS *originally*
+                              // check when entering game against
+                              // Config->InterBBS to see if cheating occurs
+
+    char szTodaysDate[11];    // Set to today's date when maintenance run
+    char szDateGameStart[11]; // First day new game begins
+    char szLastJoinDate[11];  // Last day to join game
+
+    _INT16 NextClanID;           // contains next available clanid[1] value
+    _INT16 NextAllianceID;       // contains next available alliance ID
+
+
+    // ---- league specific data, not used in local games
+    char szWorldName[30];     // league's world name
+    char LeagueID[3];         // 2 char league ID
+    char GameID[16];          // used to differentiate from old league games
+    __BOOL ClanTravel;          // TRUE if clans are allowed to travel
+    _INT16 LostDays;             // # of days before lost packets are returned
+    // ----
+
+    // ---- Individual game settings go here
+    _INT16 MaxPermanentMembers;  // up to 6
+    __BOOL ClanEmpires;         // toggles whether clans can create empires
+    _INT16 MineFights,           // Max # of mine fights per day
+        ClanFights,           // max # of clan fights per day
+        DaysOfProtection;     // # of days of protection for newbies
+
+    long CRC;                 // used to prevent cheating
+
+  } *Data;
+} PACKED;
+
+struct __attribute__((packed)) SpellsInEffect {
+	_INT16 SpellNum;	/* set to -1 so that it's inactive */
+	_INT16 Energy; 	/* how much energy of spell remains, sees if it runs out */
+} PACKED;
+
+struct __attribute__((packed)) item_data {
+	__BOOL Available;
+	_INT16 UsedBy; 	/* 0 means nobody, 1.. etc. gives num of who uses it +1 */
+	char szName[25];
+	char cType;
+	__BOOL Special;	/* if special item, can't be bought or sold */
+	_INT16 SpellNum;	// which spell do you cast when reading this scroll?
+
+	char Attributes[NUM_ATTRIBUTES];
+	char ReqAttributes[NUM_ATTRIBUTES];
+
+	long lCost;
+	__BOOL DiffMaterials; 	/* means it can be made with different matterials */
+	_INT16 Energy; 			/* how long before it "breaks"? */
+	_INT16 MarketLevel;		// what level of market before this is seen?
+
+	_INT16 VillageType;		// which villages is this allowed in?  0 == ALL
+	long ItemDate;			// when was item taken into the pawn shop?
+	char RandLevel; 		// from 0 - 10, level of randomness, 10 is highest
+	char HPAdd, SPAdd;
+} PACKED;
+
+
+struct __attribute__((packed)) pc {
+	char szName[20];
+	_INT16 HP, MaxHP;
+  _INT16 SP, MaxSP;
+
+	char Attributes[NUM_ATTRIBUTES];
+	char Status;
+
+	_INT16 Weapon, Shield, Armor;
+
+	_INT16 WhichRace, WhichClass;
+	long Experience;
+	_INT16 Level;
+	_INT16 TrainingPoints;
+
+  struct __attribute__((packed)) clan *MyClan;  /* pointer to his clan */
+  char SpellsKnown[MAX_SPELLS];
+
+  struct __attribute__((packed)) SpellsInEffect SpellsInEffect[10]; /* 10 spells is sufficient */
+
+
+	_INT16 Difficulty; 		/* used only by monsters */
+  char Undead : 1,
+		 DefaultAction : 7; 	  // default action:
+							//
+							// 0 == attack
+							// 1 == skip it, do nothing
+							// 10 == spell #0
+							// 11 == spell #1
+							// 1x == spell #x
+
+	long CRC;
+} PACKED;
+
+struct __attribute__((packed)) clan {
+  _INT16 ClanID[2];
+  char szUserName[30];
+  char szName[25];
+  char Symbol[21];
+
+  char QuestsDone[8], QuestsKnown[8];
+
+  char PFlags[8], DFlags[8];
+  char ChatsToday, TradesToday;
+
+	_INT16 ClanRulerVote[2];		// who are you voting for as the ruler?
+
+	_INT16 Alliances[MAX_ALLIES];		// alliances change from BBS to BBS, -1
+                                // means no alliance, 0 = first one, ID
+                                // that is...
+
+  long Points;
+  char szDateOfLastGame[11];
+
+  _INT16 FightsLeft, ClanFights,
+      MineLevel;
+
+  _INT16 WorldStatus, DestinationBBS;
+
+	char VaultWithdrawals;
+
+  _INT16 PublicMsgIndex;
+
+	_INT16 ClanCombatToday[MAX_CLANCOMBAT][2];
+  _INT16 ClanWars;
+
+  struct __attribute__((packed)) pc *Member[MAX_MEMBERS];
+  struct __attribute__((packed)) item_data Items[MAX_ITEMS_HELD];
+
+	char ResUncToday, ResDeadToday ;
+
+  struct __attribute__((packed)) empire Empire;
+
+  // Help
+  _INT16 DefActionHelp : 1,
+       CommHelp      : 1,
+       MineHelp      : 1,
+       MineLevelHelp : 1,
+       CombatHelp    : 1,
+       TrainHelp     : 1,
+       MarketHelp    : 1,
+       PawnHelp      : 1,
+       WizardHelp    : 1,
+       EmpireHelp    : 1,
+       DevelopHelp   : 1,
+       TownHallHelp  : 1,
+       DestroyHelp   : 1,
+       ChurchHelp    : 1,
+       THallHelp     : 1,
+       SpyHelp       : 1,
+       AllyHelp      : 1,
+       WarHelp       : 1,
+       VoteHelp      : 1,
+       TravelHelp    : 1,
+
+       WasRulerToday : 1,
+       MadeAlliance  : 1,
+       Protection    : 4,
+       FirstDay      : 1,
+       Eliminated    : 1,
+       QuestToday    : 1,
+       AttendedMass  : 1,
+       GotBlessing   : 1,
+       Prayed        : 1;
+  
+  long CRC;
+} PACKED;
+
+struct __attribute__((packed)) Spell {
+	char szName[20];
+	_INT16 TypeFlag;
+	__BOOL Friendly;
+	__BOOL Target;
+	char Attributes[NUM_ATTRIBUTES];
+	char Value;
+	_INT16 Energy;
+	char Level; 	/* used to see if affects target */
+	char *pszDamageStr;
+	char *pszHealStr;
+	char *pszModifyStr;
+	char *pszWearoffStr;
+	char *pszStatusStr;
+	char *pszOtherStr;
+	char *pszUndeadName;
+  _INT16 SP;
+	__BOOL StrengthCanReduce;
+	__BOOL WisdomCanReduce;
+#if defined(_WIN32) || defined(__unix__)
+	char MultiAffect : 1;
+	char Garbage : 7;
+#else
+	_INT16 MultiAffect : 1;	// set to true if it affects more than one user
+    _INT16  Garbage : 7;
+#endif
+} PACKED;
+
+
+struct __attribute__((packed)) Language {
+	char Signature[30]; 		// "The Clans Language File v1.0"
+
+	unsigned _INT16 StrOffsets[2000];		// offsets for up to 1100 strings
+	unsigned _INT16 NumBytes;				// how big is the bigstring!?
+
+	char *BigString;		// All 500 strings jumbled together into
+								// one
+} PACKED;
+
+struct __attribute__((packed)) BuildingType {
+	char szName[30];
+	char HitZones,			// how vulnerable is it?  Higher = more vulnerable
+		 LandUsed,			// how many units of land used?
+		 EnergyUsed;		// how much energy is used to build it? 100=highest
+	long Cost;				// how much it'll cost ya to build this
+
+	/* in future:
+
+	__BOOL MultipleBuild; 	// FALSE == can only build one at a time
+	__BOOL BuildingPrerequisites[MAX_BUILDINGS];	// ???
+	*/
+
+} PACKED;
+
+
+struct __attribute__((packed)) Alliance {
+	_INT16 ID;
+	char szName[30];
+	_INT16 CreatorID[2];
+	_INT16 OriginalCreatorID[2];
+	_INT16 Member[MAX_ALLIANCEMEMBERS][2];
+
+  struct __attribute__((packed)) empire Empire;
+  struct __attribute__((packed)) item_data Items[MAX_ALLIANCEITEMS];
+} PACKED;
+
+
+
+
+// This struct __attribute__((packed)) should have just about EVERYTHING on the battle
+// who the attacker is, what his name is, what type of attacker, what his ID is
+// who the victim is, what type he is and his ID
+struct __attribute__((packed)) AttackResult {
+	__BOOL Success;					// was the attacker successful?
+	__BOOL NoTarget;					// set this if there was no ruler to oust
+									// or no clan to battle
+	__BOOL InterBBS;					// was this an InterBBS attack?
+
+	// starting info
+	struct __attribute__((packed)) Army OrigAttackArmy; 	// what troops he had originally
+	_INT16 AttackerType;				// what type of attacker he is
+	_INT16 AttackerID[2];				// ID of person doing the attacking
+	_INT16 AllianceID; 				// ID of alliance
+	char szAttackerName[25];		// name of attacker
+
+	// set beforehand
+	_INT16 DefenderType;				// what type of defender
+	_INT16 DefenderID[2];				// who is being attacked?
+
+	// set in InterBBS only
+	char szDefenderName[25];
+
+	_INT16 BBSIDFrom;					// which BBS was the attacker from?
+	_INT16 BBSIDTo;					// which BBS was the attack for?
+
+	// actual result of battle:
+	_INT16 PercentDamage;
+	_INT16 Goal;						// original goal of attack
+	_INT16 ExtentOfAttack;
+	struct __attribute__((packed)) Army AttackCasualties, DefendCasualties;
+	_INT16 BuildingsDestroyed[MAX_BUILDINGS];
+	long GoldStolen;
+	_INT16 LandStolen;
+
+	struct __attribute__((packed)) Army ReturningArmy;		// how many survived and are coming back?
+									// only used for IBBS
+	_INT16 ResultIndex;				// used to prevent cheating
+	_INT16 AttackIndex;				// used to delete attackpacket from backup.dat
+
+	long CRC;						// IBBS only
+} PACKED;
+
+
+struct __attribute__((packed)) Topic {
+	__BOOL Known; 				/* topic known yet? */
+	__BOOL Active;				/* does topic even exist? */
+	__BOOL ClanInfo;				/* if set to TRUE, means gives info on clan
+								   he is in */
+	char szName[70];			/* name of topic as seen by user */
+	char szFileName[25];		/* name of topic in file */
+} PACKED;
+
+
+struct __attribute__((packed)) NPCInfo {
+	char szName[20];
+	struct __attribute__((packed)) Topic Topics[MAX_TOPICS];
+	struct __attribute__((packed)) Topic IntroTopic;
+  __BOOL Garbage;
+  _INT16 Garbage2[2];
+	char Loyalty;		/* how loyal is he? */
+	_INT16 WhereWander;	// where does he wander most often?
+  _INT16 Garbage3;
+	__BOOL Roamer;		// is he a roamer type?
+	_INT16 NPCPCIndex; 	// which NPC is he in the NPC.PC file?
+	_INT16 KnownTopics;	// how many topics does he know?
+	_INT16 MaxTopics;		// how many topics we can discuss in one sitting
+	_INT16 OddsOfSeeing;	// good chance of seeing him or not
+	char szHereNews[70]; // news shown when guy shows up
+	// new additions
+	char szQuoteFile[13];	// what file to use for quotes?
+	char szMonFile[13]; 	// which .MON file is he in?
+	char szIndex[20];		// index of this NPC
+
+	_INT16 VillageType;		// which villages is this allowed in?  0 == ALL
+} PACKED;
+
+
+struct __attribute__((packed)) NPCNdx {
+	char szIndex[20];
+	__BOOL InClan;		/* in a clan yet? */
+	_INT16 ClanID[2];		/* if so, which clan? */
+  _INT16 WhereWander;    // where/what is he now?
+  _INT16 Status;         // where/what is he now?
+} PACKED;
+
+
+struct __attribute__((packed)) TradeList {
+	long Gold;
+	long Followers;
+	long Footmen, Axemen, Knights, Catapults;
+} PACKED;
+
+struct __attribute__((packed)) TradeData {
+	struct __attribute__((packed)) TradeList Giving;
+	struct __attribute__((packed)) TradeList Asking;
+	__BOOL Active;
+
+  _INT16 FromClanID[2], ToClanID[2];
+	char szFromClan[25];
+	long Code;
+} PACKED;
+
+
+struct __attribute__((packed)) Message {
+  _INT16 ToClanID[2], FromClanID[2];
+  char szFromName[25], szDate[11],
+       szAllyName[30], szFromVillageName[40];
+
+  _INT16 MessageType;                  // 0 == Public
+                                    // 1 == Private
+                                    // 2 == Alliance only
+  _INT16 AllianceID;                   // If MessageType == 2, this alliance
+                                    //    receives the message
+  _INT16 Flags;
+  _INT16 BBSIDFrom, BBSIDTo;
+
+  _INT16 PublicMsgIndex;               // Msg# for public posts
+
+  struct __attribute__((packed)) Msg_Txt {
+    _INT16 Offsets[40];
+    _INT16 Length, NumLines;
+    char *MsgTxt;
+  } Data;
+} PACKED;
+
+
+struct __attribute__((packed)) Packet {
+  __BOOL Active;
+
+  char GameID[16];
+  char szDate[11];
+  _INT16 BBSIDFrom, BBSIDTo;
+
+	_INT16 PacketType;
+  long PacketLength;
+} PACKED;
+
+
+struct __attribute__((packed)) AttackPacket {
+	_INT16 BBSFromID;			// from whence it came
+	_INT16 BBSToID;			// where it's going
+  struct __attribute__((packed)) empire AttackingEmpire;
+	struct __attribute__((packed)) Army AttackingArmy;	// army doing the attacking
+	_INT16 Goal;				// what is the goal of this attack?
+	_INT16 ExtentOfAttack; 	// level of attack
+	_INT16 TargetType; 		// needed to find out who he's attacking
+	_INT16 ClanID[2];			// if a clan he's attacking, this is its ID
+	_INT16 AttackOriginatorID[2];	  // clanid of who started the attack
+
+	_INT16 AttackIndex;
+	long CRC;
+} PACKED;
+
+struct __attribute__((packed)) SpyAttemptPacket {
+	char szSpierName[40];
+	_INT16 IntelligenceLevel;
+	_INT16 TargetType; 		// either a village or clan
+	_INT16 ClanID[2];			// who is the target
+	_INT16 MasterID[2];		// who sent it?
+
+	_INT16 BBSFromID;
+	_INT16 BBSToID;
+} PACKED;
+
+struct __attribute__((packed)) SpyResultPacket {
+	_INT16 BBSFromID;			// these are the same as spyattemptpacket
+	_INT16 BBSToID;
+	_INT16 MasterID[2];		// who sent it originally?
+	char szTargetName[35];	// who we're spying on
+
+	__BOOL Success;
+  struct __attribute__((packed)) empire Empire;   // unused if unsuccessful
+	char szTheDate[11];
+} PACKED;
+
+struct __attribute__((packed)) ibbs {
+  __BOOL Initialized;
+
+  struct __attribute__((packed)) ibbs_data {
+    _INT16 BBSID;
+
+    _INT16 NumNodes;
+
+    // Note, use IBBS.Nodes[x] where x corresponds to the BBSID
+    struct __attribute__((packed)) ibbs_node {
+      __BOOL Active;
+
+      struct __attribute__((packed)) ibbs_node_info {
+        char *pszBBSName;
+        char *pszVillageName;
+        char *pszAddress;
+        _INT16 RouteThrough;
+        _INT16 MailType;
+      } Info;
+
+      struct __attribute__((packed)) ibbs_node_reset {
+        _INT16 Received;           /* used only by main BBS */
+        long LastSent;          /* last attempt at sending a reset command */
+      } Reset;
+
+      struct __attribute__((packed)) ibbs_node_recon {
+        long LastReceived;      /* when last recon gotten was */
+        long LastSent;          /* last attempted recon */
+        char PacketIndex;
+      } Recon;
+
+      struct __attribute__((packed)) ibbs_node_attack {
+        _INT16 ReceiveIndex;
+        _INT16 SendIndex;
+      } Attack;
+
+    } Nodes[MAX_IBBSNODES];
+
+  } *Data;
+} PACKED;
+
+struct __attribute__((packed)) ResetData {
+  char GameID[16];
+  char szDateGameStart[11];
+  char szLastJoinDate[11];
+	char szVillageName[40];
+	__BOOL InterBBSGame;
+	__BOOL LeagueWide;
+	__BOOL InProgress;
+	__BOOL EliminationMode;
+
+	__BOOL ClanTravel;
+	_INT16 LostDays;
+	__BOOL ClanEmpires;
+	_INT16 MineFights, ClanFights;
+	_INT16 MaxPermanentMembers;		// up to 6
+	_INT16 DaysOfProtection;
+} PACKED;
+
+struct __attribute__((packed)) UserInfo {
+	_INT16 ClanID[2];
+	__BOOL Deleted;					// set for deletion during maintenance
+	char szMasterName[30];			// name of user who plays
+	char szName[30];				// name of clan itself
+} PACKED;
+
+struct __attribute__((packed)) UserScore {
+	_INT16 ClanID[2];
+	char Symbol[21];
+	char szName[30];
+	long Points;
+	_INT16 BBSID;
+} PACKED;
+
+struct __attribute__((packed)) LeavingData {
+	__BOOL Active;
+  _INT16 DestID;
+	_INT16 ClanID[2];
+
+	// how many troops to bring along with you
+	long Followers, Footmen, Axemen, Knights, Catapults;
+} PACKED;
+
diff --git a/src/doors/clans-devkit/test.txt b/src/doors/clans-devkit/test.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3259faaad7c8ec0ba8c61ffc90c30845d3b86f92
--- /dev/null
+++ b/src/doors/clans-devkit/test.txt
@@ -0,0 +1 @@
+ha 
diff --git a/src/doors/clans-src/WhatsNew.txt b/src/doors/clans-src/WhatsNew.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8b797478999a27f4b9db163b8195b3ecfc2c1826
--- /dev/null
+++ b/src/doors/clans-src/WhatsNew.txt
@@ -0,0 +1,8 @@
+What's new since v0.96b1
+------------------------
+- More Win32/FreeBSD fixes... should now actually work.
+
+What's new since v0.95b7
+-----------------------
+- Many fixes, cleanups too numerous to mention.i
+- Now compiles on Win32 and FreeBSD
diff --git a/src/doors/clans-src/alliance.c b/src/doors/clans-src/alliance.c
new file mode 100644
index 0000000000000000000000000000000000000000..0a07286f00d45a7b6107aac97d06b44e201c1d68
--- /dev/null
+++ b/src/doors/clans-src/alliance.c
@@ -0,0 +1,971 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+
+/*
+ * Alliances
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <dos.h>
+#include <share.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "door.h"
+#include "mstrings.h"
+#include "language.h"
+#include "user.h"
+#include "empire.h"
+#include "menus.h"
+#include "mail.h"
+#include "input.h"
+#include "items.h"
+#include "help.h"
+#include "myopen.h"
+#include "parsing.h"
+#include "fight.h"
+
+extern struct Language *Language;
+extern struct game Game;
+extern struct clan *PClan;
+
+  void RemoveFromAlliance( struct Alliance *Alliance )
+  {
+    _INT16 iTemp;
+    _INT16 WhichMember = 0, ClanID[2];
+    char szName[40], /*cKey,*/ szString[128];
+    struct clan *TmpClan;
+
+    if (GetClanID( ClanID, FALSE, FALSE, Alliance->ID, TRUE ) == FALSE)
+    {
+      return;
+    }
+
+    GetClanNameID(szName, ClanID);
+
+    // if it's the creator, tell him he can't
+    if (ClanID[0] == Alliance->CreatorID[0] &&
+        ClanID[1] == Alliance->CreatorID[1])
+    {
+      rputs("You can't remove the creator\n");
+      return;
+    }
+
+    // ask user if he's sure he wants to remove this guy
+    if (NoYes("Remove from alliance?") == NO)
+      return;
+
+    // list all members of this alliance
+    for (iTemp = 0; iTemp < MAX_ALLIANCEMEMBERS; iTemp++)
+    {
+      if (Alliance->Member[iTemp][0] == ClanID[0] &&
+        Alliance->Member[iTemp][1] == ClanID[1])
+      {
+        WhichMember = iTemp;
+        break;
+      }
+    }
+
+    // remove from alliance[]
+    Alliance->Member[ WhichMember ][0] = -1;
+    Alliance->Member[ WhichMember ][1] = -1;
+
+    // remove from .PC file
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    GetClan(ClanID, TmpClan);
+
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (TmpClan->Alliances[iTemp] == Alliance->ID)
+        break;
+
+    if (iTemp == MAX_ALLIES)
+    {
+      // couldn't find link to alliance
+    }
+    else
+    {
+      // found link!
+      TmpClan->Alliances[ iTemp ] = -1;
+
+      Clan_Update(TmpClan);
+    }
+
+    FreeClan(TmpClan);
+
+    // send message to that player
+    sprintf(szString, "%s ousted you from %s!", PClan->szName,
+      Alliance->szName);
+    GenericMessage(szString, ClanID, PClan->ClanID, PClan->szName, FALSE);
+  }
+
+
+
+
+  void SeeMemberStats ( struct Alliance *Alliance )
+  {
+/*    char szName[30];*/
+    _INT16 ClanID[2], iTemp;
+    struct clan *TmpClan;
+
+    // ask for member name
+    if (GetClanID( ClanID, FALSE, FALSE, Alliance->ID, TRUE ) == FALSE)
+    {
+      return;
+    }
+
+    // get TmpClan
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    GetClan(ClanID, TmpClan);
+
+    // see if in this alliance
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (TmpClan->Alliances[iTemp] == Alliance->ID)
+        break;
+
+    // if so, show stats, else boot him
+    if (iTemp == MAX_ALLIES)
+    {
+      rputs("Clan is not in this alliance!  Can't view stats.\n");
+      FreeClan(TmpClan);
+      return;
+    }
+
+    ClanStats(TmpClan, FALSE);
+
+    FreeClan(TmpClan);
+  }
+
+  void ShowAllianceItems ( struct Alliance *Alliance)
+  {
+    _INT16 iTemp, iTemp2, Length, LastItem = 0, FoundItem = FALSE;
+    _INT16 CurItem;
+    char szString[100];
+
+    rputs("|0B # Name                      ");
+    rputs("|0B # Name                 \n");
+    rputs("|0A屯哪哪哪哪哪哪哪哪哪哪哪耐蛗07  ");
+    rputs("|0A屯哪哪哪哪哪哪哪哪哪哪哪耐蛗07\n");
+
+    /* show all the items here */
+    for (iTemp = 0, CurItem = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+    {
+      if (Alliance->Items[iTemp].Available)
+      {
+        FoundItem = TRUE;
+
+        sprintf(szString, "|0L%2d |0M%-20s", iTemp+1, Alliance->Items[iTemp].szName);
+
+#define LEN (26+9)		// add 9 for the | codes!
+
+        /* add or remove spaces to filler it */
+        if (strlen(szString) > LEN)
+        {
+          szString[LEN] = 0;
+        }
+        else
+        {
+          /* add spaces */
+          szString[LEN] = 0;
+          Length = strlen(szString);
+          for (iTemp2 = LEN-1; iTemp2 >= Length; iTemp2--)
+            szString[iTemp2] = ' ';
+        }
+        rputs(szString);
+        if (CurItem%2 != 0)
+          rputs("\n");
+        CurItem++;
+
+        LastItem = iTemp;
+      }
+    }
+    if (FoundItem == FALSE)
+      rputs(" |04No items.");
+
+    if (LastItem%2 == 0)
+      rputs("\n");
+
+    rputs("\n");
+  }
+
+
+
+  void DonationRoom ( struct Alliance *Alliance )
+  {
+    /* modify item stats, assume it's the player */
+    _INT16 ItemIndex, /*OneItemFound,*/ RoomItemIndex, EmptySlot;
+    _INT16 DefaultItemIndex, iTemp/*, WhoEquip*/;
+    char /*szKeys[10],*/ szString[100]/*, szTemp[60]*/;
+
+    /* options available
+
+    [L]ist items
+    e[X]amine item
+    [D]onate item
+    [T]ake item
+    [Q]uit
+    [V]iew Stats
+
+    */
+
+    for (;;)
+    {
+      rputs(ST_ITEMROOM0);
+
+      switch (od_get_answer("?XDTLQ\r\n I*V"))
+      {
+        case 'V' :  // clan stats
+          rputs("View Stats\n");
+          ClanStats(PClan, TRUE);
+          break;
+        case 'I' :  // show room items
+          rputs("List room items\n\n");
+          ShowAllianceItems(Alliance);
+          break;
+          case '?' :
+          rputs("Help\n\n");
+          Help("Item Help", ST_ITEMHLP);
+          break;
+        case ' ' :
+        case '\r':
+        case '\n':
+        case 'Q' :
+          return;
+        case 'X' :  /* examine item */
+          rputs(ST_ISTATS1);
+
+          /* see if anything to examine */
+          for (iTemp = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+          {
+            if (Alliance->Items[iTemp].Available)
+              break;
+          }
+          if (iTemp == MAX_ALLIANCEITEMS)
+          {
+            rputs(ST_ISTATS2);
+            break;
+          }
+
+          /* find first item in inventory */
+          for (iTemp = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+          {
+            if (Alliance->Items[iTemp].Available)
+              break;
+          }
+          if (iTemp == MAX_ALLIANCEITEMS)
+          {
+            DefaultItemIndex = 1;
+          }
+          else
+            DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS3, DefaultItemIndex, MAX_ALLIANCEITEMS);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (Alliance->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+          ShowItemStats(&Alliance->Items[ItemIndex], NULL);
+          break;
+        case 'L' :
+          rputs(ST_ISTATS5);
+          ListItems(PClan);
+          break;
+        case 'D' :  /* drop item */
+          // see if room in room to drop item
+          for (iTemp = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+          {
+            if (Alliance->Items[iTemp].Available == FALSE)
+              break;
+          }
+          if (iTemp == MAX_ALLIANCEITEMS)
+          {
+            rputs("\n|07The room is currently full.  You cannot drop any more.\n");
+            break;
+          }
+          else RoomItemIndex = iTemp;
+
+          rputs(ST_ISTATS6);
+
+          /* see if anything to drop */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available &&
+              PClan->Items[iTemp].UsedBy == 0)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            rputs("No items to be dropped.\n");
+            break;
+          }
+
+          DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS7, DefaultItemIndex, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+          /* if that item is in use, tell him */
+          if (PClan->Items[ItemIndex].UsedBy != 0)
+          {
+            rputs(ST_ISTATS8);
+            break;
+          }
+
+          /* still wanna drop it? */
+          sprintf(szString, ST_ISTATS9, PClan->Items[ItemIndex].szName);
+
+          if (NoYes(szString) == YES)
+          {
+            /* drop it */
+            sprintf(szString, ST_ISTATS10, PClan->Items[ItemIndex].szName);
+            rputs(szString);
+
+            // add it to room
+            Alliance->Items[RoomItemIndex] = PClan->Items[ItemIndex];
+            Alliance->Items[RoomItemIndex] = PClan->Items[ItemIndex];
+
+            // remove from user's stats
+            PClan->Items[ItemIndex].szName[0] = 0;
+            PClan->Items[ItemIndex].Available = FALSE;
+          }
+          break;
+        case '*' :  /* destroy item */
+          rputs("Destroy Item\n");
+
+          /* see if anything to destroy */
+          for (iTemp = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+          {
+            if (Alliance->Items[iTemp].Available)
+              break;
+          }
+
+          if (iTemp == MAX_ALLIANCEITEMS)
+          {
+            // nothing to destroy
+            rputs("Nothing to destroy!\n");
+            break;
+          }
+          else
+            DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong("Which item to destroy? (0=abort)",
+            DefaultItemIndex, MAX_ALLIANCEITEMS);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (Alliance->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+
+          /* still wanna drop it? */
+          sprintf(szString, "|0SAre you sure you wish to destroy %s?",
+            Alliance->Items[ItemIndex].szName);
+
+          if (NoYes(szString) == YES)
+          {
+            /* destroy it */
+            sprintf(szString, "%s destroyed!\n\n",
+              Alliance->Items[ItemIndex].szName);
+            rputs(szString);
+
+            Alliance->Items[ItemIndex].szName[0] = 0;
+            Alliance->Items[ItemIndex].Available = FALSE;
+
+          }
+          break;
+        case 'T' :  /* take item */
+          rputs("Take item\n");
+
+          // see if inventory full
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available == FALSE)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            /* no more room in inventory */
+            rputs(ST_ITEMNOMOREROOM);
+            break;
+          }
+          else
+            EmptySlot = iTemp;
+
+          /* see if anything to take */
+          for (iTemp = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+          {
+            if (Alliance->Items[iTemp].Available)
+              break;
+          }
+
+          if (iTemp == MAX_ALLIANCEITEMS)
+          {
+            // nothing to destroy
+            rputs("Nothing to take!\n");
+            break;
+          }
+          else
+            DefaultItemIndex = iTemp+1;
+
+            ItemIndex = (_INT16) GetLong("|0STake which item from the room? (0=abort)",
+              DefaultItemIndex, MAX_ALLIANCEITEMS);
+            if (ItemIndex == 0)
+              break;
+            ItemIndex--;
+
+            /* if that item is non-existant, tell him */
+            if (Alliance->Items[ItemIndex].Available == FALSE)
+            {
+              rputs(ST_ISTATS4);
+              break;
+            }
+
+            /* take it */
+            sprintf(szString, "%s taken!\n\n", Alliance->Items[ItemIndex].szName);
+            rputs(szString);
+
+            PClan->Items[EmptySlot] = Alliance->Items[ItemIndex];
+
+            Alliance->Items[ItemIndex].szName[0] = 0;
+            Alliance->Items[ItemIndex].Available = FALSE;
+            break;
+      }
+    }
+  }
+
+
+
+  void GetAlliances( struct Alliance *Alliances[MAX_ALLIANCES])
+  {
+    FILE *fp;
+    _INT16 iTemp;
+
+    // init alliances as NULLs
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      Alliances[iTemp] = NULL;
+
+    fp = fopen("ally.dat", "rb");
+    if (fp)
+    {
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        Alliances[iTemp] = malloc(sizeof(struct Alliance));
+        CheckMem(Alliances[iTemp]);
+
+        if (EncryptRead(Alliances[iTemp], sizeof(struct Alliance), fp, XOR_ALLIES) == 0)
+        {
+          // no more alliances to read in
+          free(Alliances[iTemp]);
+          Alliances[iTemp] = NULL;
+          break;
+        }
+      }
+      fclose(fp);
+    }
+  }
+
+
+  void UpdateAlliances( struct Alliance *Alliances[MAX_ALLIANCES])
+  {
+    FILE *fp;
+    _INT16 iTemp;
+
+    fp = fopen("ally.dat", "wb");
+    if (fp)
+    {
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        if (Alliances[iTemp] == NULL)
+          continue;
+
+        EncryptWrite(Alliances[iTemp], sizeof(struct Alliance), fp, XOR_ALLIES);
+      }
+      fclose(fp);
+    }
+  }
+
+  void CreateAlliance( struct Alliance *Alliance, struct Alliance *Alliances[MAX_ALLIANCES])
+  {
+    _INT16 iTemp;
+    char szName[30], szString[128];
+    BOOL AllianceNameInUse;
+
+    // get NextID
+    Alliance->ID = Game.Data->NextAllianceID++;
+
+    // get name of alliance
+    szName[0] = 0;
+    Alliance->szName[0] = 0;
+    // rputs("Enter a name for this alliance.\n");
+    while (! szName[0])
+    {
+      rputs(ST_AMENU4);
+      GetStr(szName, 29, TRUE);
+      RemovePipes(szName, szString);
+      strcpy(szName, szString);
+
+      if (szName[0] == 0)
+        continue;
+
+      if (szName[0] == '?')
+        szName[0] = '!';
+
+      // see if in use, if so, nullify name
+      AllianceNameInUse = FALSE;
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        if (Alliances[iTemp] == NULL)
+          continue;
+
+        if (stricmp(szName, Alliances[iTemp]->szName) == 0)
+        {
+          AllianceNameInUse = TRUE;
+          break;
+        }
+      }
+
+      if (AllianceNameInUse)
+      {
+        rputs("|07That name is already in use.\n\n");
+        szName[0] = 0;
+      }
+    }
+
+    strcpy(Alliance->szName, szName);
+
+    Alliance->CreatorID[0] = PClan->ClanID[0];
+    Alliance->CreatorID[1] = PClan->ClanID[1];
+    Alliance->OriginalCreatorID[0] = PClan->ClanID[0];
+    Alliance->OriginalCreatorID[1] = PClan->ClanID[1];
+
+    for (iTemp = 0; iTemp < MAX_ALLIANCEMEMBERS; iTemp++)
+    {
+      Alliance->Member[ iTemp ][0] = -1;
+      Alliance->Member[ iTemp ][1] = -1;
+    }
+
+    // set first member to be this creator
+    Alliance->Member[0][0] = PClan->ClanID[0];
+    Alliance->Member[0][1] = PClan->ClanID[1];
+
+    Empire_Create(&Alliance->Empire, FALSE);
+    Alliance->Empire.VaultGold = 0;
+    strcpy(Alliance->Empire.szName, Alliance->szName);
+    Alliance->Empire.OwnerType = EO_ALLIANCE;
+    Alliance->Empire.AllianceID = Alliance->ID;
+
+    // initialize items
+    for (iTemp = 0; iTemp < MAX_ALLIANCEITEMS; iTemp++)
+      Alliance->Items[iTemp].Available = FALSE;
+
+    // make user a part of alliance
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (PClan->Alliances[iTemp] == -1)
+        break;
+
+    PClan->Alliances[ iTemp ] = Alliance->ID;
+  }
+
+
+  void ShowAlliances ( struct clan *Clan )
+  {
+    _INT16 iTemp, NumAlliances = 0, CurAlliance;
+    char /*szName[25],*/ szString[50];
+    struct Alliance *Alliances[MAX_ALLIANCES];
+
+    rputs(ST_ALLIANCES);
+
+    /* go through each of alliance variables */
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (Clan->Alliances[iTemp] != -1)
+        NumAlliances++;
+
+    /* if no alliances, tell user */
+    if (NumAlliances == 0)
+    {
+      rputs(ST_NOALLIANCES);
+      return;
+    }
+
+    GetAlliances(Alliances);
+
+    /* if alliances found, display names */
+
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+    {
+      if (Clan->Alliances[iTemp] != -1)
+      {
+        for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+          if (Alliances[CurAlliance]->ID == Clan->Alliances[iTemp])
+          {
+            sprintf(szString, "|06* |14%s\n", Alliances[ CurAlliance ]->szName);
+            rputs(szString);
+          }
+      }
+    }
+    door_pause();
+
+    // free up mem used by alliances
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      if (Alliances[iTemp])
+        free(Alliances[iTemp]);
+  }
+
+  BOOL EnterAlliance( struct Alliance *Alliance)
+  {
+    char *szTheOptions[13], *szString, szName[25];
+    char szFileName[13];
+    _INT16 iTemp;
+
+    // show stats
+
+    // show help if user needs it
+
+    szString = MakeStr(128);
+
+    LoadStrings(1290, 13, szTheOptions);
+
+    /* get a choice */
+    for (;;)
+    {
+      sprintf(szString, "\n |0BAlliance Menu:  |0C%s\n", Alliance->szName);
+      rputs(szString);
+
+      switch(GetChoice("Alliance", ST_ENTEROPTION, szTheOptions, "LIRSCDP*VQ?W!", 'Q', TRUE))
+      {
+        case 'S' :  // see member's stats
+          SeeMemberStats(Alliance);
+          break;
+        case '!' :  // remove self from alliance
+          // if creator, tell him he can't or destroy alliance
+          if (PClan->ClanID[0] == Alliance->CreatorID[0] &&
+            PClan->ClanID[1] == Alliance->CreatorID[1])
+          {
+            rputs("You are the creator, can't remove self...\n");
+            break;
+          }
+
+          // are you sure?
+          if (NoYes("Remove self?") == NO)
+            break;
+
+          // remove from member[] list
+          for (iTemp = 0; iTemp < MAX_ALLIANCEMEMBERS; iTemp++)
+            if (Alliance->Member[iTemp][0] == PClan->ClanID[0] &&
+              Alliance->Member[iTemp][1] == PClan->ClanID[1])
+            {
+              Alliance->Member[iTemp][0] = -1;
+              Alliance->Member[iTemp][1] = -1;
+              break;
+            }
+
+          // remove from globalplayerclan->alliances[]
+          for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+            if (PClan->Alliances[iTemp] == Alliance->ID)
+            {
+              PClan->Alliances[iTemp] = -1;
+              break;
+            }
+
+          // write message to creator
+          sprintf(szString, "%s left the alliance of %s",
+            PClan->szName, Alliance->szName);
+
+          GenericMessage(szString, Alliance->CreatorID,
+            PClan->ClanID, PClan->szName, FALSE);
+
+          // done
+          free(szString);
+          return FALSE;
+        case 'W' :  // write to all allies
+          Mail_WriteToAllies( Alliance );
+          break;
+        case 'L' :  // list members
+          for (iTemp = 0; iTemp < MAX_ALLIANCEMEMBERS; iTemp++)
+          {
+            if (Alliance->Member[iTemp][0] != -1)
+            {
+              GetClanNameID(szName, Alliance->Member[iTemp]);
+              sprintf(szString, "|0A* |0B%s\n", szName);
+              rputs(szString);
+            }
+          }
+          door_pause();
+          break;
+        case 'I' :  // invite clan
+          Mail_RequestAlliance(Alliance);
+          break;
+        case 'R' :  // remove from alliance
+          RemoveFromAlliance(Alliance);
+          break;
+        case 'V' :  // clan stats
+          ClanStats(PClan, TRUE);
+          break;
+        case 'D' :    /* donation room */
+          DonationRoom(Alliance);
+          break;
+        case 'C' :    /* chat room */
+          sprintf(szFileName, "HALL%02d.TXT", Alliance->ID);
+          Menus_ChatRoom(szFileName);
+          break;
+        case 'P' :    /* manage empire */
+          Empire_Manage(&Alliance->Empire);
+          break;
+        case '*' :  // destroy alliance
+          if (Alliance->CreatorID[0] != PClan->ClanID[0] ||
+            Alliance->CreatorID[1] != PClan->ClanID[1])
+          {
+            rputs("|0SOnly the creator may change destroy this alliance.\n");
+            if (ClanExists(Alliance->CreatorID) == FALSE)
+            {
+              rputs("|0SAlliance creator was not found, however.  You will be the new creator.\n");
+              Alliance->CreatorID[0] = PClan->ClanID[0];
+              Alliance->CreatorID[1] = PClan->ClanID[1];
+            }
+            else
+            {
+              door_pause();
+              break;
+            }
+          }
+          if (NoYes("|0SDestroy this alliance? |08(All will be lost!) |0S:") == YES)
+          {
+            free(szString);
+            return TRUE;
+          }
+          break;
+        case 'Q' :
+          free(szString);
+          return FALSE;
+      }
+    }
+  }
+
+
+  void KillAlliance ( _INT16 AllianceID )
+  {
+    // go through player file
+    // skip user online
+    // if Alliance is same as one given, make it -1
+    // write to file
+
+    struct clan *TmpClan;
+    FILE *fpPlayerFile;
+    _INT16 CurClan, CurAlliance;
+    long Offset;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    fpPlayerFile = _fsopen(ST_CLANSPCFILE, "r+b", SH_DENYRW);
+    if (!fpPlayerFile)
+    {
+      rputs(ST_ERRORPC);
+      free(TmpClan);
+      return;
+    }
+
+    // get list of all clan names from file, write to
+    for (CurClan = 0;; CurClan++)
+    {
+      Offset = (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc));
+      if (fseek(fpPlayerFile, Offset, SEEK_SET))
+      {
+        fclose(fpPlayerFile);
+        break;  /* couldn't fseek, so exit */
+      }
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+      {
+        fclose(fpPlayerFile);
+        break;  /* stop reading if no more players found */
+      }
+
+      // skip if user is online
+      if (TmpClan->ClanID[0] == PClan->ClanID[0] &&
+        TmpClan->ClanID[1] == PClan->ClanID[1])
+        continue;
+
+      // see if in alliance
+      for (CurAlliance = 0; CurAlliance < MAX_ALLIES; CurAlliance++)
+        if (TmpClan->Alliances[CurAlliance] == AllianceID)
+          break;
+
+      // not in alliance, skip
+      if (CurAlliance == MAX_ALLIES)
+        continue;
+
+      // in alliance, update his info and write to file
+      TmpClan->Alliances[CurAlliance] = -1;
+
+      Offset = (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc));
+      fseek(fpPlayerFile, Offset, SEEK_SET);
+      EncryptWrite(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER);
+    }
+
+    fclose(fpPlayerFile);
+    free(TmpClan);
+  }
+
+  void Alliance_Maint( void )
+  {
+    struct Alliance *Alliances[MAX_ALLIANCES];
+    _INT16 iTemp;
+
+    GetAlliances(Alliances);
+
+    // maintain alliances...
+    for (iTemp = 0; iTemp  < MAX_ALLIANCES; iTemp++)
+    {
+      // update empire
+      if (Alliances[iTemp])  {
+        Empire_Maint(&Alliances[iTemp]->Empire);
+        if (Alliances[iTemp]->szName[0] == '?')
+          Alliances[iTemp]->szName[0] = '!';
+	  }
+    }
+
+    // deinit alliances and update to file
+    UpdateAlliances(Alliances);
+
+    // free up mem used by alliances
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      if (Alliances[iTemp])
+        free(Alliances[iTemp]);
+  }
+
+
+  void FormAlliance( _INT16 AllyID )
+  {
+    _INT16 iTemp, UserAllianceSlot, WhichAlliance;
+    struct Alliance *Alliances[MAX_ALLIANCES];
+
+    // see if this guy can ally any more
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+    {
+      // if in this alliance, tell user and exit!
+      if (PClan->Alliances[iTemp] == AllyID)
+      {
+        rputs("Already in this alliance!\n");
+        return;
+      }
+
+      // find open slot
+      if (PClan->Alliances[iTemp] == -1)
+        break;
+    }
+
+    if (iTemp == MAX_ALLIES)
+    {
+      // FIXME: make look better
+      rputs("Too many alliances!\n");
+      return;
+    }
+
+    // else, found spot to place alliance
+    UserAllianceSlot = iTemp;
+
+    // load up alliances
+    GetAlliances(Alliances);
+
+    // find that alliance
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+    {
+      if (Alliances[iTemp]->ID == AllyID)
+        break;
+    }
+
+    if (iTemp == MAX_ALLIANCES)
+    {
+      rputs("Alliance no longer exists!\n");
+
+      // free up mem used by alliances
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+        if (Alliances[iTemp])
+          free(Alliances[iTemp]);
+      return;
+    }
+
+    // else found it
+    WhichAlliance = iTemp;
+
+    // find spot to place in that particular alliance to place clan
+    for (iTemp = 0; iTemp < MAX_ALLIANCEMEMBERS; iTemp++)
+      if (Alliances[WhichAlliance]->Member[ iTemp ][0] == -1)
+        break;
+
+    if (iTemp == MAX_ALLIANCEMEMBERS)
+    {
+      rputs("Too many members in that alliance, you cannot join.\n");
+
+      // free up mem used by alliances
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+        if (Alliances[iTemp])
+          free(Alliances[iTemp]);
+      return;
+    }
+
+    // else, found spot, make him part of it now
+    Alliances[WhichAlliance]->Member[ iTemp ][0] = PClan->ClanID[0];
+    Alliances[WhichAlliance]->Member[ iTemp ][1] = PClan->ClanID[1];
+    PClan->Alliances[ UserAllianceSlot ] = AllyID;
+
+
+    // deinit alliances and update to file
+    UpdateAlliances(Alliances);
+
+    // free up mem used by alliances
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      if (Alliances[iTemp])
+        free(Alliances[iTemp]);
+  }
+
diff --git a/src/doors/clans-src/alliance.h b/src/doors/clans-src/alliance.h
new file mode 100644
index 0000000000000000000000000000000000000000..3ade473e21b037602ee010db181dce5fc1ba8b28
--- /dev/null
+++ b/src/doors/clans-src/alliance.h
@@ -0,0 +1,10 @@
+
+  void GetAlliances( struct Alliance *Alliances[MAX_ALLIANCES]);
+  void UpdateAlliances( struct Alliance *Alliances[MAX_ALLIANCES]);
+  void CreateAlliance( struct Alliance *Alliance, struct Alliance *Alliances[MAX_ALLIANCES]);
+  void ShowAlliances ( struct clan *Clan );
+  BOOL EnterAlliance( struct Alliance *Alliance);
+  void KillAlliance ( _INT16 AllianceID );
+  void Alliance_Maint( void );
+
+  void FormAlliance( _INT16 AllyID );
diff --git a/src/doors/clans-src/backup.lst b/src/doors/clans-src/backup.lst
new file mode 100644
index 0000000000000000000000000000000000000000..43d7d110de0a05a42cc773ae8d5516e4c832a3ac
--- /dev/null
+++ b/src/doors/clans-src/backup.lst
@@ -0,0 +1,63 @@
+*.C
+*.H
+*.HLP
+*.BAT
+COMP.LST
+CLANGET.EXE
+CLANS.ASC
+CLANS.CFG
+CLANS.EXE
+CLANS1L.ASC
+CLANS2.EXE
+CLANTITL.ASC
+CLASSES.ASC
+CLASSES.TXT
+COMBAT.EXE
+COMBAT2.EXE
+COMBAT3.EXE
+DOOR.SYS
+ENEMIES.TXT
+GAME.CFG
+CLANS.CFG
+GETCLASS.EXE
+INSTRUCT.DOC
+ITEMGET.EXE
+ITEMS.TXT
+MAILMENU.ASC
+MAINMENU.ASC
+MARKET.ASC
+MARKMENU.ASC
+MENU.ASC
+MINEMENU.ASC
+NAMES.TXT
+PLAYERS.TXT
+RACES.ASC
+RACES.TXT
+SHELL.EXE
+STATS.ASC
+SUNS.
+SUNS.ASC
+SYNOPSIS.TXT
+TITLE.ASC
+TODAY.ASC
+TOWNSTAT.ASC
+WELCOME.ASC
+strings.txt
+langcomp.c
+langcomp.exe
+NPCS.TXT
+NPC-PC.TXT
+NPCQUOTE.TXT
+EVA.TXT
+QUESTS.TXT
+QUESTS.EVT
+QUESTS.DOC
+eventmon.txt
+monsters.txt
+quests.ini
+clans.ini
+clans.npc
+makenpc.c
+runclans.bat
+*.SMP
+Pro*.log
diff --git a/src/doors/clans-src/clans.c b/src/doors/clans-src/clans.c
new file mode 100644
index 0000000000000000000000000000000000000000..71116082b6008c5240844ba9deb8cd9e4c3e30b2
--- /dev/null
+++ b/src/doors/clans-src/clans.c
@@ -0,0 +1,288 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/* The Clans v0.95 -- recode
+ *
+ *
+ * Main module
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <conio.h>
+#include <dos.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+// #include <alloc.h>
+#include <time.h>
+#include <errno.h>
+
+#include "structs.h"
+#include "tasker.h"
+
+// Modules
+#include "clans.h"                // functions for this module
+#include "door.h"
+#include <OpenDoor.h>            // opendoors functions
+#include "system.h"
+#include "language.h"
+#include "mstrings.h"
+#include "input.h"
+#include "help.h"
+#include "menus.h"
+#include "maint.h"
+#include "user.h"
+#include "game.h"
+#include "misc.h"
+#include "mail.h"
+#include "news.h"
+#include "trades.h"
+#include "scores.h"
+#include "ibbs.h"
+#include "reg.h"
+#ifdef ODPLAT_WIN32
+# include "cmdline.h" /* Win32 only */
+#endif
+
+/*
+ * Global variables
+ */
+
+extern struct Language *Language;
+extern struct game Game;
+extern struct system System;
+extern struct clan *PClan;
+extern struct ibbs IBBS;
+
+
+//extern unsigned _stklen = 8U*(1024U);
+
+/* ----------------------------------------------------------------------- */
+
+  void MainGame ( void )
+  {
+    BOOL Quit = FALSE, EnteredGame = FALSE;
+    char *szTheOptions[12], DefaultAction, szString[128];
+
+    LoadStrings(950, 12, szTheOptions);
+
+    while (!Quit)
+    {
+      // tell user if game in progress, etc.
+      switch (Game.Data->GameState)
+      {
+        case 0 :  // Game in progress
+          // rputs("The game is currently in progress\n");
+          break;
+        case 1 :  // Game is waiting for day to start
+          rputs("\n|0CThe game will begin on ");  rputs(Game.Data->szDateGameStart);
+          rputs("\n");
+          break;
+        case 2 :  // Game is waiting for LC's reset
+          rputs("\n|0CThe game has not yet begun.  (Waiting for LC Reset)\n");
+          break;
+      }
+
+      if (DaysBetween(Game.Data->szLastJoinDate, System.szTodaysDate) > 0)
+        rputs("|12No new players may join at the moment.\n");
+
+
+      if (EnteredGame)
+        DefaultAction = 'Q';
+      else
+        DefaultAction = 'E';
+
+      switch (GetChoice("Clan Title", ST_ENTEROPTION, szTheOptions, "ESTYHIQ?BVGL", DefaultAction, TRUE))
+      {
+        case 'E' :  // Enter game
+          EnteredGame = TRUE;
+
+          if (Disbanded())
+          {
+            Help("Disbanded", ST_MENUSHLP);
+            break;
+          }
+
+          // if user disbanded today, don't let him play
+
+          if (Game.Data->GameState == 1 || Game.Data->GameState == 2)
+          {
+            // Game is waiting for day to start
+            rputs("The game has not yet begun.\n");
+            break;
+          }
+
+          /* see if past end of game, if so, disallow user */
+          if (DaysBetween(Game.Data->szLastJoinDate, System.szTodaysDate) > 0)
+          {
+            // rputs("|07Sorry, this game is currently taking in no new players.\n");
+            rputs(ST_MAIN0);
+            break;
+          }
+
+          // otherwise, let user play
+          if (!User_Init())
+            break;
+
+          /* if not on this BBS, tell him */
+          if (PClan->WorldStatus == WS_GONE)
+          {
+            // tell him
+            // sprintf(szString, "|02Your clan was last seen headed for |14%s |02(%s)!\nPlease call that BBS instead.\n\n",
+            sprintf(szString, ST_MAIN1,
+              IBBS.Data->Nodes[ PClan->DestinationBBS - 1].Info.pszVillageName,
+              IBBS.Data->Nodes[ PClan->DestinationBBS - 1].Info.pszBBSName);
+            rputs(szString);
+
+            rputs("\nIf you had trouble connecting to that BBS, you can call back your clan.\n");
+            if (NoYes("|0SCall back your clan to this BBS?") == YES)
+            {
+              IBBS_SendComeBack(PClan->DestinationBBS, PClan);
+              rputs("\n|0SYour clan will return tomorrow to this village.\n%P");
+            }
+            break;
+          }
+
+          if (stricmp(PClan->szDateOfLastGame, System.szTodaysDate) != 0)
+            User_FirstTimeToday();
+
+          News_ReadNews(TRUE);
+
+          ClanStats(PClan, TRUE);
+
+          Mail_Read();
+          Trades_CheckTrades();
+
+          GameLoop();
+
+          User_Close();
+
+          break;
+
+        case 'B' :  // Bulletin
+          GeneralHelp(ST_BULLHLP);
+          break;
+        case 'V' :  /* village stats */
+          ShowVillageStats();
+          break;
+        case 'I' :  // Instruction
+          Help("Instructions", ST_CLANSHLP);
+          door_pause();
+          break;
+        case 'T' :  /* Today's News */
+          News_ReadNews( TRUE );
+          break;
+        case 'Y' :  /* Yesterday's News */
+          News_ReadNews( FALSE );
+          break;
+        case 'S' :  // See scores
+          DisplayScores(FALSE);
+          break;
+        case 'Q' :  /* Quit */
+          Quit = TRUE;
+          break;
+        case 'H' :  // Help
+          MainHelp();
+          break;
+        case 'G' :  /* game settings */
+          // show game settings
+          Game_Settings();
+
+          if (Game.Data->InterBBS)
+            IBBS_LeagueInfo();
+          break;
+        case 'L' :  // league scores
+          if (Game.Data->InterBBS == FALSE)
+            rputs("|07Not in a league\n%P");
+          else
+            LeagueScores();
+          break;
+      }
+    }
+  }
+
+
+/* ----------------------------------------------------------------------- */
+#ifdef ODPLAT_WIN32
+int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
+#else
+  int main ( int argc, char *argv[] )
+#endif
+  {
+#ifdef ODPLAT_WIN32
+	char **argv;
+	int argc;
+
+	if (!commandline_create (lpCmdLine, &argv, &argc))
+	{
+		MessageBox (NULL, TEXT("failed to parse commandline"), 
+			TEXT("Error"), MB_OK | MB_ICONERROR);
+		return FALSE;
+	}
+#endif
+
+    _argc=argc;
+    _argv=argv;
+
+#ifdef __unix__
+// FIXME this only has to be here for me... it SHOULD use the current umask.
+	umask(0);
+#endif
+
+    System_Init();
+    // run maintenance if need be
+    if (DaysBetween(Game.Data->szTodaysDate, System.szTodaysDate) > 0)
+      Maintenance();
+
+    UnregMessage();
+
+    rputs("\033(U");
+
+    Door_ShowTitle();
+
+    Display("news.txt");
+
+    if (Game.Data->InterBBS)
+      IBBS_ShowLeagueAscii();
+
+    MainGame();
+
+    System_Close();
+
+#ifdef ODPLAT_WIN32
+	commandline_destroy (&argv, argc);
+
+	/* Unused Variables */
+	(void)hInst;
+	(void)hPrevInst;
+	(void)nShowCmd;
+#endif
+
+	return 0;
+  }
diff --git a/src/doors/clans-src/clans.dsp b/src/doors/clans-src/clans.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..531357a42b7b0b188f3f81c7e3bebf8982ae6fe6
--- /dev/null
+++ b/src/doors/clans-src/clans.dsp
@@ -0,0 +1,473 @@
+# Microsoft Developer Studio Project File - Name="clans" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=clans - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "clans.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "clans.mak" CFG="clans - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "clans - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "clans - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "clans - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "clans___Win32_Release"
+# PROP BASE Intermediate_Dir "clans___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Win32_Release"
+# PROP Intermediate_Dir "Win32_Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Zp1 /MD /W3 /Ox /Ot /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_MT" /YX /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ODoorW.lib /nologo /subsystem:windows /machine:I386
+
+!ELSEIF  "$(CFG)" == "clans - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Win32_Debug"
+# PROP Intermediate_Dir "Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Zp1 /MDd /W3 /Gm /GX- /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ODoorW.lib /nologo /subsystem:windows /profile /map /debug /debugtype:both /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "clans - Win32 Release"
+# Name "clans - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\ALLIANCE.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLANS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLANSINI.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLASS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\cmdline.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\CRC.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\DOOR.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\EMPIRE.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\EVENT.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\FIGHT.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\GAME.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\HELP.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\IBBS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\INPUT.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\ITEMS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\LANGUAGE.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MAIL.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MAINT.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MENUS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MENUS2.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MISC.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MYIBBS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MYOPEN.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\NEWS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\NPC.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\PARSING.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\PAWN.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\QUESTS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\REG.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\SCORES.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\SPELLS.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\system.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\TRADES.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\TSLICER.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\USER.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\VIDEO.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\VILLAGE.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\VOTING.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\WB_FAPND.C
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\ALLIANCE.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLANS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLANSF.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLANSINI.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\CLASS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\cmdline.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CRC.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\DEFINES.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\DOOR.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\EMPIRE.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\FIGHT.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\GAME.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\HELP.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\IBBS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\INIT.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\INPUT.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\INTERBBS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\ITEMS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\K_CLANSI.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\K_COMMAN.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\K_CONFIG.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\K_IBBS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\K_QUESTS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\LANGUAGE.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MAIL.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MAINT.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MENUS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MENUS2.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MISC.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MSTRINGS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MYIBBS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MYOPEN.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\NEWS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\NPC.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\OPENDOOR.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\PACKET.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\PARSING.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\PAWN.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\QUESTS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\REG.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\SCORES.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\SNIPFILE.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\SPELLS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\STRUCTS.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\SYSTEM.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\SYSTEMF.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\TASKER.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\TRADES.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\TSLICER.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\USER.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\VIDEO.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\VILLAGE.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\VOTING.H
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/src/doors/clans-src/clans.dsw b/src/doors/clans-src/clans.dsw
new file mode 100644
index 0000000000000000000000000000000000000000..778ab7affd23a6ac564da43938297536ff05e2c5
--- /dev/null
+++ b/src/doors/clans-src/clans.dsw
@@ -0,0 +1,77 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "clans"=.\clans.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "langcomp"=.\langcomp.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "mcomp"=.\mcomp.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "pcedit"=.\pcedit.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "reset"=.\reset.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/src/doors/clans-src/clans.h b/src/doors/clans-src/clans.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/src/doors/clans-src/clans.h
@@ -0,0 +1 @@
+
diff --git a/src/doors/clans-src/clansf.h b/src/doors/clans-src/clansf.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5b7716c216244008e73921994345b55cbdc2cfb
--- /dev/null
+++ b/src/doors/clans-src/clansf.h
@@ -0,0 +1 @@
+void SystemInit ( void );                       // Initializes the system
diff --git a/src/doors/clans-src/clansini.c b/src/doors/clans-src/clansini.c
new file mode 100644
index 0000000000000000000000000000000000000000..6e584bf826a1f2eded54c5800370e28f08caf294
--- /dev/null
+++ b/src/doors/clans-src/clansini.c
@@ -0,0 +1,236 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * CLANS.INI stuff
+ */
+
+#include <stdio.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+#include <string.h>
+
+#include "structs.h"
+#include "language.h"
+#include "system.h"
+#include "parsing.h"
+#include "k_clansi.h"
+
+struct IniFile IniFile = { FALSE };
+extern __BOOL Verbose;
+
+void DisplayStr(char *);
+
+  void ClansIni_Init ( void )
+  {
+    /* read in quests file and allocate memory for quest names */
+    _INT16 iTemp;
+    FILE *fp;
+    char szLine[128], *pcCurrentPos;
+    char szToken[MAX_TOKEN_CHARS + 1];
+    _INT16 iKeyWord;
+    _INT16 CurNPCFile, CurItemFile, CurRaceFile, CurClassFile, CurSpellFile;
+
+    if (Verbose)
+    {
+      DisplayStr("> ClansIni_Init()\n");
+      delay(500);
+    }
+
+
+    IniFile.Initialized = FALSE;
+
+    for (iTemp = 0; iTemp < MAX_NPCFILES; iTemp++)
+      IniFile.pszNPCFileName[iTemp] = NULL;
+    for (iTemp = 0; iTemp < MAX_SPELLFILES; iTemp++)
+      IniFile.pszSpells[iTemp] = NULL;
+    for (iTemp = 0; iTemp < MAX_ITEMFILES; iTemp++)
+      IniFile.pszItems[iTemp] = NULL;
+    for (iTemp = 0; iTemp < MAX_RACEFILES; iTemp++)
+      IniFile.pszRaces[iTemp] = NULL;
+    for (iTemp = 0; iTemp < MAX_CLASSFILES; iTemp++)
+      IniFile.pszClasses[iTemp] = NULL;
+    for (iTemp = 0; iTemp < MAX_VILLFILES; iTemp++)
+      IniFile.pszVillages[iTemp] = NULL;
+
+    IniFile.pszLanguage = NULL;
+
+    fp = _fsopen("clans.ini", "r", SH_DENYWR);
+    if (!fp)
+    {
+      System_Error("No clans.ini\n");
+    }
+
+    /* read in all lines and get event names */
+    CurNPCFile = -1;
+    CurItemFile = -1;
+    CurRaceFile = -1;
+    CurClassFile = -1;
+    CurSpellFile = -1;
+    for (;;)
+    {
+      /* read in a line */
+      if (fgets(szLine, 128, fp) == NULL) break;
+
+      /* Ignore all of line after comments or CR/LF char */
+      pcCurrentPos=(char *)szLine;
+
+      ParseLine(pcCurrentPos);
+
+      /* If no token was found, proceed to process the next line */
+      if(!*pcCurrentPos) continue;
+
+      GetToken(pcCurrentPos, szToken);
+
+      if (szToken[0] == '$')
+        break;
+
+      /* Loop through list of keywords */
+      for(iKeyWord = 0; iKeyWord < MAX_INI_WORDS; ++iKeyWord)
+      {
+        /* If keyword matches */
+        if(stricmp(szToken, papszIniKeyWords[iKeyWord]) == 0)
+        {
+          /* Process config token */
+          switch (iKeyWord)
+          {
+            case 0 :  /* npcfile */
+              if (CurNPCFile == MAX_NPCFILES)
+                break;
+
+              CurNPCFile++;
+
+              IniFile.pszNPCFileName[ CurNPCFile ] =
+                MakeStr( strlen(pcCurrentPos) + 1);
+              strcpy(IniFile.pszNPCFileName[ CurNPCFile ], pcCurrentPos);
+              break;
+            case 1 :  /* Language */
+              if (IniFile.pszLanguage)
+              {
+                free(IniFile.pszLanguage);
+                IniFile.pszLanguage = NULL;
+              }
+              IniFile.pszLanguage =
+                MakeStr( strlen(pcCurrentPos) + 1);
+              strcpy(IniFile.pszLanguage, pcCurrentPos);
+              break;
+            case 2 :  // item files
+              if (CurItemFile == MAX_ITEMFILES)
+                break;
+
+              CurItemFile++;
+
+              IniFile.pszItems[ CurItemFile ] =
+                MakeStr( strlen(pcCurrentPos) + 1);
+              strcpy(IniFile.pszItems[ CurItemFile ], pcCurrentPos);
+
+              // printf("itemfile = %d. %s\n", CurItemFile,
+              //    IniFile.pszItems[ CurItemFile ]);
+              break;
+            case 3 :  // races files
+              if (CurRaceFile == MAX_RACEFILES)
+                break;
+
+              CurRaceFile++;
+
+              IniFile.pszRaces[ CurRaceFile ] =
+                MakeStr( strlen(pcCurrentPos) + 1);
+              strcpy(IniFile.pszRaces[ CurRaceFile ], pcCurrentPos);
+
+              // printf("race = %d. %s\n", CurRaceFile,
+              //     IniFile.pszRaces[ CurRaceFile ]);
+              break;
+            case 4 :  // class files
+              if (CurClassFile == MAX_CLASSFILES)
+                break;
+
+              CurClassFile++;
+
+              IniFile.pszClasses[ CurClassFile ] =
+                MakeStr( strlen(pcCurrentPos) + 1);
+              strcpy(IniFile.pszClasses[ CurClassFile ], pcCurrentPos);
+
+              // printf("class = %d. %s\n", CurClassFile,
+              //     IniFile.pszClasses[ CurClassFile ]);
+              break;
+            case 5 :  // spell files
+              if (CurSpellFile == MAX_SPELLFILES)
+                break;
+
+              CurSpellFile++;
+
+              IniFile.pszSpells[ CurSpellFile ] =
+                MakeStr( strlen(pcCurrentPos) + 1);
+              strcpy(IniFile.pszSpells[ CurSpellFile ], pcCurrentPos);
+
+              // printf("spellfile = %d. %s\n", CurSpellFile,
+              //     IniFile.pszSpells[ CurSpellFile ]);
+              break;
+          }
+        }
+      }
+    }
+
+    fclose(fp);
+  }
+
+  void ClansIni_Close ( void )
+  {
+    _INT16 iTemp;
+
+    if (IniFile.Initialized == FALSE) return;
+
+    if (IniFile.pszLanguage)
+      free(IniFile.pszLanguage);
+
+    // NPC filenames
+    for (iTemp = 0; iTemp < MAX_NPCFILES; iTemp++)
+      if (IniFile.pszNPCFileName[iTemp])
+        free(IniFile.pszNPCFileName[iTemp]);
+
+    // spell filenames
+    for (iTemp = 0; iTemp < MAX_SPELLFILES; iTemp++)
+      if (IniFile.pszSpells[iTemp])
+        free(IniFile.pszSpells[iTemp]);
+
+    for (iTemp = 0; iTemp < MAX_ITEMFILES; iTemp++)
+      if (IniFile.pszItems[iTemp])
+        free(IniFile.pszItems[iTemp]);
+
+    for (iTemp = 0; iTemp < MAX_RACEFILES; iTemp++)
+      if (IniFile.pszRaces[iTemp])
+        free(IniFile.pszRaces[iTemp]);
+
+    for (iTemp = 0; iTemp < MAX_CLASSFILES; iTemp++)
+      if (IniFile.pszClasses[iTemp])
+        free(IniFile.pszClasses[iTemp]);
+
+    for (iTemp = 0; iTemp < MAX_VILLFILES; iTemp++)
+      if (IniFile.pszVillages[iTemp])
+        free(IniFile.pszVillages[iTemp]);
+
+    IniFile.Initialized = FALSE;
+  }
diff --git a/src/doors/clans-src/clansini.h b/src/doors/clans-src/clansini.h
new file mode 100644
index 0000000000000000000000000000000000000000..55298928833d638d3f4f49c09de319bf88c8bc53
--- /dev/null
+++ b/src/doors/clans-src/clansini.h
@@ -0,0 +1,10 @@
+
+  void ClansIni_Init ( void );
+    /*
+     * Reads in CLANS.INI and stores it in memory.
+     */
+
+  void ClansIni_Close ( void );
+    /*
+     * Deinitializes anything initialized by ClansIni_Init
+     */
diff --git a/src/doors/clans-src/clanslogo.gif b/src/doors/clans-src/clanslogo.gif
new file mode 100644
index 0000000000000000000000000000000000000000..5b9ce478d236f7b47100b0293dfda08860c522d6
Binary files /dev/null and b/src/doors/clans-src/clanslogo.gif differ
diff --git a/src/doors/clans-src/clanslogo2.gif b/src/doors/clans-src/clanslogo2.gif
new file mode 100644
index 0000000000000000000000000000000000000000..5a84efee792ed13d48b3a77514498e193f440811
Binary files /dev/null and b/src/doors/clans-src/clanslogo2.gif differ
diff --git a/src/doors/clans-src/class.c b/src/doors/clans-src/class.c
new file mode 100644
index 0000000000000000000000000000000000000000..dcb976afcc3b750223e806827634bf9959852a56
--- /dev/null
+++ b/src/doors/clans-src/class.c
@@ -0,0 +1,155 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Classes/Races ADT
+ */
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include <stdio.h>
+#ifdef __FreeBSD__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
+#include "structs.h"
+#include "myopen.h"
+#include "language.h"
+#include "video.h"
+
+__BOOL ClassesInitialized = FALSE;
+
+extern struct IniFile IniFile;
+struct PClass *PClasses[MAX_PCLASSES], *Races[MAX_PCLASSES];
+extern __BOOL Verbose;
+
+
+// ------------------------------------------------------------------------- //
+
+  void Load_PClasses ( struct PClass *PClass[MAX_PCLASSES], __BOOL GetPClasses )
+    /*
+     * This function will load classes from file into PClass[].
+     *
+     * PRE: GetPClasses = TRUE if we're get classes, FALSE if getting races.
+     */
+  {
+    _INT16 iTemp, NumClasses, CurFile, CurClass = 0, MaxFiles;
+    struct FileHeader ClassFile;
+
+    if (GetPClasses)
+      MaxFiles = MAX_CLASSFILES;
+    else
+      MaxFiles = MAX_RACEFILES;
+
+    // for each file, read in the data
+    for (CurFile = 0; CurFile < MaxFiles; CurFile++)
+    {
+      if (GetPClasses && IniFile.pszClasses[CurFile] == NULL)
+        break;
+      else if (!GetPClasses && IniFile.pszRaces[CurFile] == NULL)
+        break;
+
+      // open file if possible
+      if (GetPClasses)
+        MyOpen(IniFile.pszClasses[CurFile], "rb", &ClassFile);
+      else
+        MyOpen(IniFile.pszRaces[CurFile], "rb", &ClassFile);
+
+      if (ClassFile.fp == NULL) continue;
+
+      // read in data
+
+      /* get num classes */
+      fread(&NumClasses, sizeof(_INT16), 1, ClassFile.fp);
+
+      /* read them in */
+      for (iTemp = 0; iTemp < NumClasses; iTemp++)
+      {
+        PClass[CurClass] = malloc(sizeof(struct PClass));
+        CheckMem(PClass[CurClass]);
+
+        fread(PClass[CurClass], sizeof(struct PClass), 1, ClassFile.fp);
+
+        //printf("%s\n\r", PClass[CurClass]->szName);
+
+        CurClass++;
+        if (CurClass == MAX_PCLASSES) break;
+      }
+      fclose(ClassFile.fp);
+
+      if (CurClass == MAX_PCLASSES) break;
+    }
+  }
+
+  void Free_PClasses( struct PClass *PClass[MAX_PCLASSES])                  
+    /*
+     * This function will free the classes loaded by Load_PClasses
+     */
+  {
+    _INT16 iTemp;
+
+    for (iTemp = 0; iTemp < MAX_PCLASSES; iTemp++)
+    {
+      if (PClass[iTemp])
+      {
+        free(PClass[iTemp]);
+        PClass[iTemp] = NULL;
+      }
+    }
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void PClass_Init ( void )
+    /*
+     * Initialize classes and races.
+     *
+     */
+  {
+    if (Verbose)
+    {
+      DisplayStr("> PClass_Init()\n");
+      delay(500);
+    }
+
+    Load_PClasses(Races, FALSE);
+    Load_PClasses(PClasses, TRUE);
+
+    ClassesInitialized = TRUE;
+  }
+
+  void PClass_Close ( void )
+    /*
+     * DeInitializes classes and races.
+     *
+     */
+  {
+    if (ClassesInitialized == FALSE) return;
+
+    Free_PClasses(PClasses);
+    Free_PClasses(Races);
+
+    ClassesInitialized = FALSE;
+  }
diff --git a/src/doors/clans-src/class.h b/src/doors/clans-src/class.h
new file mode 100644
index 0000000000000000000000000000000000000000..b180b6221e74309bb30a9f0e7f2c6ff1b84e40ff
--- /dev/null
+++ b/src/doors/clans-src/class.h
@@ -0,0 +1,12 @@
+
+  void PClass_Init ( void );
+    /*
+     * DeInitializes classes and races.
+     *
+     */
+
+  void PClass_Close ( void );
+    /*
+     * DeInitializes classes and races.
+     *
+     */
diff --git a/src/doors/clans-src/cmdline.c b/src/doors/clans-src/cmdline.c
new file mode 100644
index 0000000000000000000000000000000000000000..ca97cc8dfcf96332e10effcdc0db325cceee0709
--- /dev/null
+++ b/src/doors/clans-src/cmdline.c
@@ -0,0 +1,155 @@
+/********************************************************************
+  Copyright (c) 2002 Michael Dillon
+
+  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.
+*********************************************************************/
+/* cmdline.c
+
+   The purpose of this file is to provide a few functions to convert
+   Windows single string commandline into the C style commandline
+   arguments.
+*/
+
+#ifdef _WIN32
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <tchar.h>
+#include <ctype.h>
+#include "cmdline.h"
+
+void display_win32_error ()
+{
+  LPVOID message;
+  TCHAR buffer[1000];
+
+  FormatMessage (
+    FORMAT_MESSAGE_IGNORE_INSERTS|
+    FORMAT_MESSAGE_FROM_SYSTEM|
+    FORMAT_MESSAGE_ALLOCATE_BUFFER,
+    NULL,
+    GetLastError(),
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+    (LPTSTR)&message,
+    0,
+    NULL);
+
+  _stprintf (buffer, _T("Win32 System Error:\n%s\n"), message);
+  MessageBox (NULL, buffer, _T("System Error"), MB_OK | MB_ICONERROR);  
+
+  LocalFree (message);
+}
+
+int commandline_create (char *cmd_line, char ***argv, int *argc)
+{
+  char *option;
+  int i = 0, len;
+  TCHAR *program_path;
+  *argv = NULL;
+  *argc = 0;
+
+  option = (char *) calloc (1, strlen (cmd_line) + 5);
+  if (!option)
+  {
+    display_win32_error ();
+    return 0;
+  }
+
+  /* Initialize *argv[] with the program's name as first entry */
+  program_path = (char *) calloc (1, _MAX_PATH);
+  GetModuleFileName (NULL, program_path, _MAX_PATH);
+  program_path = (char *) realloc (program_path, strlen (program_path) + 1);
+  (*argv) = (char **) malloc (strlen (program_path) + 1);
+  (*argv)[(*argc)++] = program_path;
+
+  while (i < (signed)strlen (cmd_line))
+  {
+    /* Skip over excess whitespace */
+    while (isspace(cmd_line[i]))
+      ++i;
+    /* Check for quoted strings */
+    if (cmd_line[i] == '\"')
+    {
+      char *p_cur_quote = &cmd_line[i+1];
+      char *p_next_quote = strchr ((p_cur_quote + 1), '\"');
+      if (p_next_quote)
+      {
+        strncpy (option, p_cur_quote, (p_next_quote - p_cur_quote));
+        ++i;
+      }
+      else
+        strncpy (option, p_cur_quote, strlen (p_cur_quote));
+    }
+    else
+    {
+      /* Get non-quoted value */
+      char *p_cur = &cmd_line[i];
+      char *p_next = strchr (p_cur, ' ');
+      if (p_next)
+        strncpy (option, p_cur, (p_next - p_cur));
+      else
+        strncpy (option, p_cur, strlen (p_cur));
+    }
+    /* Assign new value */
+    len = strlen (option);
+    i += (len + 1);
+    (*argv) = (char **) realloc ((*argv), i + strlen (program_path));
+    (*argv)[(*argc)] = (char *) calloc (1, (len + 1));
+    strncpy ((*argv)[(*argc)++], option, len);
+    /* Memory cleanup */
+    memset ((void *) option, 0, len);
+  }
+
+  free (option);
+  return 1;
+}
+
+int commandline_destroy (char ***argv, int argc)
+{
+  int i;
+
+  for (i = 0; i < argc; i++)
+    free ((*argv)[i]);
+
+  free ((*argv));
+
+  return 1;
+}
+
+#else /* !_WIN32 */
+/* Dummy Functions for non-Win32 platforms */
+void display_win32_error (void)
+{
+}
+
+int commandline_create (char *cmd_line, char ***argv, int *argc)
+{
+	return 0;
+}
+
+int commandline_destroy (char ***argv, int argc)
+{
+	return 0;
+}
+#endif /* _WIN32 */
\ No newline at end of file
diff --git a/src/doors/clans-src/cmdline.h b/src/doors/clans-src/cmdline.h
new file mode 100644
index 0000000000000000000000000000000000000000..d432f507416fb3429cd96dbe1615c21361a9ae37
--- /dev/null
+++ b/src/doors/clans-src/cmdline.h
@@ -0,0 +1,37 @@
+/********************************************************************
+  Copyright (c) 2002 Michael Dillon
+
+  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.
+*********************************************************************/
+/* cmdline.h
+
+   Header file for cmdline.c, provides function prototypes which will
+   only be included once when compiled.
+*/
+#ifndef THE_CLANS__W32_COMMANDLINE_CREATION__H
+#define THE_CLANS__W32_COMMANDLINE_CREATION__H 1
+
+void display_win32_error ();
+int commandline_create (char *, char ***, int *);
+int commandline_destroy (char ***, int);
+
+#endif /* THE_CLANS__W32_COMMANDLINE_CREATION__H */
\ No newline at end of file
diff --git a/src/doors/clans-src/comp.lst b/src/doors/clans-src/comp.lst
new file mode 100644
index 0000000000000000000000000000000000000000..2e87d5e7396f1a44f984022553afc7e9abbcb929
--- /dev/null
+++ b/src/doors/clans-src/comp.lst
@@ -0,0 +1 @@
+clans.obj wb_fapnd.obj extern\odoorl.lib video.obj system.obj parsing.obj ibbs.obj myopen.obj language.obj door.obj village.obj input.obj help.obj game.obj user.obj misc.obj maint.obj spells.obj clansini.obj class.obj menus.obj crc.obj items.obj mail.obj fight.obj scores.obj pawn.obj reg.obj npc.obj quests.obj news.obj empire.obj alliance.obj menus2.obj voting.obj trades.obj myibbs.obj
diff --git a/src/doors/clans-src/crc.c b/src/doors/clans-src/crc.c
new file mode 100644
index 0000000000000000000000000000000000000000..67602b4967ae257e81b4431a94cacdf811fd21e5
--- /dev/null
+++ b/src/doors/clans-src/crc.c
@@ -0,0 +1,26 @@
+/*
+ * CRC code. :)
+ */
+
+#include "defines.h"
+
+  long CRCValue ( void *Data, _INT16 DataSize )
+  {
+    char *p;
+    long CRC = 0;
+
+    p = (char *)Data;
+
+    while (p < ((char *)Data+DataSize))
+    {
+      CRC += (*p);
+      p++;
+    }
+
+    return CRC;
+  }
+
+  _INT16 CheckCRC ( void *Data, _INT16 Size, long CRC )
+  {
+    return (CRCValue(Data, Size) == CRC);
+  }
diff --git a/src/doors/clans-src/crc.h b/src/doors/clans-src/crc.h
new file mode 100644
index 0000000000000000000000000000000000000000..48f0d7b7e8750ee6b8fa34c347aad9c7d1ce2821
--- /dev/null
+++ b/src/doors/clans-src/crc.h
@@ -0,0 +1,4 @@
+
+  long CRCValue ( void *Data, _INT16 DataSize );
+
+  _INT16 CheckCRC ( void *Data, _INT16 Size, long CRC );
diff --git a/src/doors/clans-src/defines.h b/src/doors/clans-src/defines.h
new file mode 100644
index 0000000000000000000000000000000000000000..68b84a149c44c186b65d0bb009254dad78bf9ef2
--- /dev/null
+++ b/src/doors/clans-src/defines.h
@@ -0,0 +1,223 @@
+#ifndef THE_CLANS__DEFINES___H
+#define THE_CLANS__DEFINES___H 1
+
+#define VERSION                 "v0.96b2"
+
+#define NTRUE			581 					// "True" used for reg info
+#define NFALSE			0
+// results of fighting
+#define FT_RAN			0
+#define FT_WON			1
+#define FT_LOST 		2
+
+#define MAX_ITEMSTAKEN	2		// allow this many items to be stolen in combat
+
+
+#define MAX_SPELLS              40
+#define NUM_ATTRIBUTES          6
+
+#define TRUE                    1
+#define FALSE                   0
+
+#define MAIL_OTHER              0           // type of mailers
+#define MAIL_BINKLEY            1
+
+#define MAX_TOKEN_CHARS         32
+#define MAX_MEMBERS             20
+#define MAX_USERS               500
+#define MAX_TOPUSERS            20
+
+#define SPECIAL_CODE    '%'
+
+#define STR_YESNO	" |0A(|0BYes|0C/no|0A) |0F"
+#define STR_NOYES	" |0A(|0Cyes/|0BNo|0A) |0F"
+#define YES 		1
+#define NO			0
+
+#define MAX_PCLASSES	15
+
+// INI Specific data
+#define MAX_NPCFILES	32
+#define MAX_SPELLFILES	8
+#define MAX_RACEFILES	8
+#define MAX_CLASSFILES	8
+#define MAX_VILLFILES	8
+#define MAX_ITEMFILES	8
+#define MAX_CLANCOMBAT	20
+
+#define MAX_LEVELS      100
+#define MAX_ITEMS_HELD	30
+
+#define MAX_BUILDINGS 32
+
+#define MAX_ITEMS		60
+#define I_ITEM			0
+#define I_WEAPON		1
+#define I_ARMOR 		2
+#define I_SHIELD		3
+#define I_SCROLL		4
+#define I_BOOK			5
+#define I_OTHER 		6
+
+// display types for GetStringChoice
+#define DT_WIDE     0
+#define DT_LONG 		1
+
+// XOR Values
+#define XOR_VILLAGE   (char)9
+#define XOR_GAME      (char)9
+#define XOR_USER      (char)9
+#define XOR_PC        (char)9
+#define XOR_MSG       (char)69
+#define XOR_ITEMS     (char)23
+#define XOR_ALLIES    (char)0xA3
+#define XOR_TRADE     (char)0x2B
+#define XOR_IBBS      (char)0x8A
+#define XOR_PACKET    (char)0x47
+#define XOR_IPS       (char)0x94
+#define XOR_TRAVEL    (char)0x3B
+#define XOR_ULIST     (char)0xCE
+#define XOR_DISBAND   (char)0x79
+
+#define ATTR_AGILITY      0
+#define ATTR_DEXTERITY    1
+#define ATTR_STRENGTH     2
+#define ATTR_WISDOM       3
+#define ATTR_ARMORSTR     4
+#define ATTR_CHARISMA     5
+
+#define SF_HEAL                 1
+#define SF_DAMAGE               2
+#define SF_MODIFY               4
+#define SF_INCAPACITATE         8
+#define SF_RAISEUNDEAD          16
+#define SF_BANISHUNDEAD         32
+
+#define MAX_ALLIES		5						// player may be in 5 alliances
+#define MAX_ALLIANCES 16
+#define MAX_ALLIANCEMEMBERS 20
+#define MAX_ALLIANCEITEMS	30
+
+/* interBBS stuff */
+#define WS_STAYING              0           /* they're staying */
+#define WS_LEAVING              1           /* they're leaving */
+#define WS_GONE                 2           /* they're leaving */
+
+// Village types
+#define V_ALL         0
+#define V_WOODLAND		1
+#define V_COASTAL     2
+#define V_WASTELAND 	3
+
+// gov't system
+#define GS_DEMOCRACY	0
+#define GS_DICTATOR 	1
+
+#define NUM_BUILDINGTYPES	10
+
+#define B_BARRACKS		0
+#define B_WALL			1
+#define B_TOWER 		2
+#define B_STEELMILL 	3
+#define B_STABLES		4
+#define B_AGENCY		5
+#define B_SECURITY		6
+#define B_GYM			7
+#define B_DEVELOPERS	8
+#define B_BUSINESS		9
+
+
+#define MAX_QUESTS		64
+#define MAX_OPTIONS 	16
+#define MAX_QUOTES		64
+#define MAX_TOPICS		10
+
+
+#define NPCS_NOTHERE	0	// status of NPC, not here -- i.e. not in town
+#define NPCS_HERE		1
+
+#define MAX_CHATSPERDAY 4
+#define MAX_MONSTERS	255 					// Number of monsters in .MON file
+
+
+/* IBBS Stuff */
+#define MAX_IBBSNODES   50
+
+
+#define WN_NONE 		0						// not a wanderer
+#define WN_CHURCH		1
+#define WN_STREET		2
+#define WN_MARKET		3
+#define WN_TOWNHALL 5
+#define WN_THALL		6
+#define WN_MINE 		8
+
+#define MAX_NPCS		16
+
+// empire owner types
+#define EO_VILLAGE		0
+#define EO_ALLIANCE 	1
+#define EO_CLAN 		2
+
+
+#define MAX_PAWNLEVEL	5
+#define MAX_WIZARDLEVEL 5
+#define MAX_MARKETLEVEL 5
+#define MAX_CHURCHLEVEL 5
+#define MAX_THALLLEVEL	4
+
+#define MAX_PACKETAGE   2       // number of days before a packet is old
+#define MAX_BACKUPAGE   4       // number of days before a backup packet is old
+
+#define MQ_AVERAGE      0
+#define MQ_GOOD         1
+#define MQ_VERYGOOD     2
+#define MQ_EXCELLENT    3
+
+// uncomment for Turbo C++
+// typedef char BOOL;
+#ifdef __unix__
+# define BOOL char			// Stops OpenDoor.h from re-defining it.
+# define FAR
+# define _INT16	short
+#elif defined(_MSC_VER)
+# define _INT16 short int
+# ifndef FAR
+#  define FAR
+# endif
+#else
+# define FAR far
+# define _INT16 int
+#endif
+
+typedef char __BOOL;
+
+#ifdef __GNUC__
+# define PACKED __attribute__ ((packed))
+#elif defined(_MSC_VER)
+# define PACKED
+// # pragma warning(disable:4103)  // Not sure what this does...
 
+# pragma pack(1)
+#endif
+
+#ifndef PACKED
+# define PACKED
+#endif
+
+#ifdef _MSC_VER
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# define delay(x) Sleep(x)
+# define sleep(x) Sleep((x * 1000))
+# define RANDOM(x) ((x) == 0 ? 0 : (rand() % (x)))
+#endif
+
+enum Status { Dead, Unconscious, RanAway, Here };
+enum PlayerStats { stAgility, stDexterity, stStrength, stWisdom, stArmorStr };
+enum action { acAttack, acRun, acCast, acRead, acSkip, acNone };
+typedef _INT16 action;
+
+_INT16	_argc;
+char	**_argv;
+
+#endif /* THE_CLANS__DEFINES___H */
diff --git a/src/doors/clans-src/doc b/src/doors/clans-src/doc
new file mode 100644
index 0000000000000000000000000000000000000000..65ebb0c734b12ccfee6079c66bc237a836fad193
--- /dev/null
+++ b/src/doors/clans-src/doc
@@ -0,0 +1,820 @@
+
+
+
+The Clans (InterBBS) v0.95
+-------------------------------------------------------------------------------
+Copyright (C) 1997-2002 Allen Ussher
+
+http://theclans.sourceforge.net
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[0.0]  Table of Contents
+-------------------------------------------------------------------------------
+
+Introduction to The Clans
+=========================
+Description ...........................................................   0.1
+Disclaimer ............................................................   0.2
+Registration ..........................................................   0.3
+No Multinode ..........................................................   0.4
+*** Lazy Sysop's Guide *** ............................................   0.9
+
+Setting up The Clans
+====================
+Setting Up The Clans ..................................................   1.1
+Resetting The Clans ...................................................   1.2
+Daily Maintenance .....................................................   1.3
+Starting an InterBBS Game .............................................   1.4
+Joining an InterBBS Game ..............................................   1.5
+Local InterBBS Games ..................................................   1.6
+Troubleshooting .......................................................   1.7
+
+
+Introduction to The Clans
+===============================================================================
+
+[0.1]  Description
+-------------------------------------------------------------------------------
+The Clans is a mix of role playing game and strategy war game for your BBS.
+The greatest feature of The Clans is its InterBBS support.  The InterBBS
+feature should help increase the number of calls to your BBS from users who
+don't normally call.  They may originally call to play the game but given
+time, they may choose to write messages and do other things as well.
+
+The InterBBS gaming can be summed up like this:
+
+    1. Each BBS acts as a "Village" in the league.
+    2. A player logging into Village A can choose the "travel to another
+       village" option in the game.  If he chooses to travel to Village B,
+       his user data will be sent over to Village B (the BBS running the
+       Clans as Village B, of course).
+    3. During maintenance, the data from BBS A is sent to BBS B and the
+       player will be able to log into BBS B the next day to play The Clans
+       there with his clan.
+    4. On top of that, each Village will have its own power struggles between
+       clans and the ruler (which will change often).  The ruler sets such
+       things as tax rates so it is in the player's interest to visit each
+       Village in the league to find the best one for him.
+    5. Each village will be able to attack other villages in the
+       league and steal supplies.  Clans in that village will be able to
+       help supply the village's army with troops and other things.
+
+Here is a run down of some of The Clan's features:
+- Addictive gameplay.  Trust me.  Watch your users play this game
+  religiously each day. :)
+- Unique InterBBS gaming!
+
+
+
+
+[0.2]  Disclaimer
+-------------------------------------------------------------------------------
+*No warranty* is provided for this product.  Allen Ussher, the author, is
+not liable for any damages incurred by use of The Clans.  The Clans is
+provided "as is" and a warranty of any kind is neither expressed nor
+implied, all of are hereby explicitly disclaimed.  Any damage caused by The
+Clans directly or indirectly is not the responsibility of Allen Ussher.
+There is also no guarantee that this software will continue to be updated
+or that support will be offered.
+
+
+[0.3]  Registration
+-------------------------------------------------------------------------------
+Registration is no longer required for The Clans.  If you wish to donate any
+amount, contact me through email first at tigertigr@yahoo.ca.
+Thanks.
+
+
+[0.4]  No Multinode
+-------------------------------------------------------------------------------
+Because of the complexity of the game and its strategic, somewhat turn-based
+nature, multinode play is not featured in this game.  However, The Clans will
+ensure no two users enter the game at the same time.  It will alert a user
+trying to enter while someone is on that the game is currently in use.  To
+do this, an ONLINE.FLG semaphore file is created in the Clans directory.  If
+something occurs which causes the file to still exist even after a user has
+exited the door, you may simply delete the file (otherwise, users entering the
+game will be told someone is online even though they are not).  This file is
+also deleted during maintenance.
+
+
+[0.9]  Lazy Sysop's Guide
+-------------------------------------------------------------------------------
+Ok, you're lazy (as are most of us) and don't want to waste time reading this
+file (although I highly recommend you do anyway).  To set up the game
+(locally only -- you MUST read the docs to set up InterBBS) follow these
+simple steps:
+
+       1.  Run CONFIG.EXE.  Configure your node data here.
+       2.  Modify RUNCLANS.BAT to suit your BBS.  Call RUNCLANS.BAT from your
+           BBS as a door.*
+       3.  Run RESET.EXE from DOS.
+       4.  Add "Clans /M" to your nightly maintenance.
+
+That's it.  If you were lost anywhere above, you better read the regular
+setup guide below. ;)
+
+*NOTE: If you are planning on joining an InterBBS league, YOU MUST set up
+       your BBS software to call the door with REAL NAMES ONLY.  This
+       will "standardize" the league and make it easier for players to travel
+       from BBS A to BBS B.  Handles can change from board to board but
+       real names can't (or shouldn't).
+
+
+Setting up and running The Clans
+===============================================================================
+Please refer to section 1.7 Troubleshooting if a problem occurs.
+
+
+[1.1]  Setting Up The Clans
+-------------------------------------------------------------------------------
+First, you must run the setup program, CONFIG.EXE.  This program allows you
+to specify which nodes you have on your BBS and their dropfile directories.
+The Clans doesn't need to know what type of dropfile it should look for.  It
+will do this automatically.
+
+To run the clans, you must create a batch file which runs the game.  How to
+set up a door on your BBS is not covered here as there are several types of
+BBS software, each of which has a different setup.  Please refer to your BBS
+documentation for information on how to set up a door.  You must set up the
+BBS so that it calls a batch file like the following (RUNCLANS.BAT):
+
+--[beginning of file]--                 [notes]
+
+cd \TheClans                            Change this to your Clans directory.
+Clans /N%1                              %1 is the node you wish to run.
+cd \bbsdirectory                        Change this to your BBS directory.
+
+--[end of file]--------
+
+To run this batchfile, simply use "RUNCLANS.BAT [node]" where [node] is the
+node on the BBS from which you are calling from.  To run from Node 1, use
+"RUNCLANS.BAT 1".  If you wish, you may create your own batch file, but
+remember *YOU MUST CHANGE TO THE CLANS DIRECTORY* and *you must specify the
+node using "CLANS /Nx" where 'x' is the node*.
+
+Now that the game is setup for local play, you must reset it.  Please see
+the next section for information on resetting the game.
+
+*NOTE: If you are planning on joining an InterBBS league, YOU MUST set up
+       your BBS software to call the door with REAL NAMES ONLY.  This
+       will "standardize" the league and make it easier for players to travel
+       from BBS A to BBS B.  Handles can change from board to board but
+       real names can't (or shouldn't).
+
+
+
+[1.2]  Resetting The Clans
+-------------------------------------------------------------------------------
+To reset the game*, all you must do is run the reset program RESET.EXE
+within the Clans directory.
+
+You will be given several options for the reset of the game.  After you are
+done entering the information, the game will be reset (all data files from
+the previous game will be removed automatically).
+
+If you are in a league, you must also run CLANS /I after you run RESET.EXE.
+But be sure that all your configurations have been set up already before
+doing this!  Have your WORLD.NDX file and ROUTE.CFG files created before
+running CLANS /I.  If you have set up a local IBBS league (i.e. on one BBS
+only), you must run CLANS /LIBBS /I (note the /LIBBS option added).
+
+* You MUST reset the game the first time it is installed.
+
+
+
+[1.3]  Daily Maintenance
+-------------------------------------------------------------------------------
+It is recommended that you run The Clans maintenace each day by adding this
+command line to your nightly BBS maintenance:
+
+        cd \TheClans
+        CLANS /M
+        cd \bbsdirectory
+
+As with the previous batch file example, please modify it to suit your BBS.
+
+If you do not include this in your nightly maintenance or, for some reason,
+the maintenance is not run, The Clans will automatically run maintenance the
+next time someone enters the game.  However, it is highly recommended that
+you run the maintenance daily to ensure that stats are calculated properly
+(this is especially true for InterBBS games).
+
+
+[1.4]  Starting an InterBBS Game
+-------------------------------------------------------------------------------
+* Clans uses an InterBBS setup similar to other games so if you are already
+  familiar with InterBBS game setups, you should find setting up The Clans
+  easy.  If you are new to InterBBS gaming, you will also find it easy as
+  each step in the setup is outlined for you.
+
+If you are new to InterBBSing, you may wish to choose to join an existing
+InterBBS game of The Clans (see section 1.5).  However, if you wish to start
+an InterBBS game, you shouldn't find it too difficult.  You should have at
+least a minimal understanding of fido-style networks (but it's really not
+necessary).
+
+First of all, let me go over some terms:
+
+      League                 The system of BBSes which are linked together
+                             to play The Clans.  The league can also be
+                             thought of as the "world" which the game takes
+                             place in as each BBS is considered a "Village."
+      LeagueID               This is a two-character identification code which
+                             differentiates one league from another.
+      League Coordinator     This is the sysop of the main BBS which is
+      (LC)                   coordinating the game (YOU, if you are starting
+                             a new InterBBS league).
+      BBSID                  This is a numerical ID which each BBS in the
+                             league uses.  Each BBS has a unique BBS ID.
+                             The main BBS (the LC's BBSID should be 1).
+
+To set up an InterBBS game, follow these steps thoroughly:
+
+   1. (Obviously, you must find out which boards are going to be in your
+      league.  It is assumed that you have taken care of this trivial
+      step by now.)  First, you must set up the WORLD.NDX file.  The
+      WORLD.NDX file is a file containing the information on your league
+      setup.  See WORLDNDX.SMP for a sample WORLD.NDX file.  While
+      modifying the WORLD.NDX file, you may wish to go through the
+      following steps:
+
+       A.  Choose a LeagueID.  This is a two-character alphanumeric
+           identification code.  Basically, you can use any characters which
+           you can use to name files in DOS.  i.e: none of the following:
+
+           . ? * % / \ etc.
+
+           When choosing an ID, ensure that no other league in your area is
+           using the ID.  This way, a BBS can play in two leagues.
+
+       B.  Choose a World Name.  This is not too important but adds to the
+           fun of the game.  This is the name of the "world" which
+           encompasses all the villages (i.e. BBSes) in the game.  Be
+           creative.  You can use whatever name you want here (it doesn't
+           matter if another league is using the name).
+
+       C.  Now you are ready to create the entries needed for each BBS in the
+           league.  Set up each BBS in the league using these keywords:
+
+           BBSId        - The BBSId of the BBS in the league you are adding.
+                          This is unique.  The first BBS has BBS ID of 1.
+                          The 2nd board in the list would use BBS ID 2 etc.
+           BBSName      - The name of the BBS.
+           VillageName  - The name of the Village for that BBS.  You should
+                          find out what each Sysop wants for his Village
+                          name before adding this option.  If VillageName
+                          is left out, the BBSName is used.
+           Address      - This is the network address of the BBS.  The BBSes
+                          in the league do NOT need to all belong in the
+                          same network, as long as they are all connected
+                          somehow.
+
+
+           Here is an example of the BBS entries in a WORLD.NDX file for a
+           league of 3 BBSes:
+
+
+           BBSId           1
+           BBSName         Revolution Nine
+           VillageName     The Village
+           Address         1:1/1
+
+           BBSId           2
+           BBSName         Joe's BBS
+           VillageName     Joe's City
+           Address         1:1/2
+
+           BBSId           3
+           BBSName         Frank's BBS
+           VillageName     Franktown
+           Address         1:1/3
+
+       D.  Optional, but pretty darn cool.  You can create an ASCII text file
+           using pipe codes for colours which is displayed whenever a user
+           plays on a board in the league.  See WORLDNDX.SMP for an example.
+           Basically, start all lines with an Ascii keyword and place
+           whatever you want after it:
+
+                Ascii  [ put stuff here ]
+                Ascii  [ and here ]
+                Ascii  [ and optionally here ]
+
+   2. Now that your WORLD.NDX file has been created, you are ready to send it
+      out to each BBS in the league.  Tell the BBSes in your league to copy
+      this file to their Clans directory.  Next tell them to set the game
+      up for InterBBS by enabling the InterBBS option in the CONFIG.EXE
+      program.  They should follow the Joining an InterBBS League steps
+      outlined in the following section.  Be sure you give them the BBS Id
+      for their BBS.  YOU must also choose the InterBBS option in the
+      CONFIG.EXE program (enter the BBS ID as 1 since you are the head
+      BBS in the league).
+
+   3. The game is almost ready to play.  Now run the reset program
+      from DOS:
+
+      RESET
+
+      Enter all the important information as you would a normal reset and
+      choose "Leaguewide reset ..."  After doing this, you must run
+      CLANS /I from DOS so that Clans will create outbound packets telling
+      each BBS in the league to get ready to begin the game.  You should
+      have set the game start date to perhaps a week ahead of the day you
+      set up the league so that everyone can get ready.
+
+   4. If everything is set up properly, the other BBSes should get a packet
+      telling their game to reset for InterBBS.  Then Clans on their BBS
+      should send a reply to your BBS saying they received the packet.  You
+      may check the league coordinator's log LC.LOG to ensure each BBS
+      received the Reset packet and sent a receipt packet.
+
+   5. It is also a good idea to create a VillInfo section in your WORLD.NDX
+      file.  See the WORLDNDX.SMP for an example.  Basically, this section
+      acts as a way of advertising the BBSes who are running The Clans in your
+      league.  Whenever a user chooses to travel to another BBS and chooses a
+      BBS, a small advertisment (from this file) will appear.  This is
+      extremely useful for attracting people to call your board and very
+      helpful in keeping a link to other boards (for people who don't do
+      messages).
+
+   6. You may also wish to choose a routing method (this may not be needed for
+      small leagues).  See the section below for information.
+
+You're done.
+
+** IMPORTANT: **
+* As a league coordinator, you MUST remind your fellow sysops to use real
+  names only when running the game.  This ensures no duplicate players are
+  formed and also ensures that players may jump from board to board easily.
+
+****** Be sure you toss your netmail right after packets by The Clans are
+       created.
+** IMPORTANT: **
+
+Adding a new node while a game is in progress
+---------------------------------------------
+It is easy to add a new node to your existing game.
+
+   1. Simply modify the WORLD.NDX to accomodate the new BBS.  Do this by
+      creating a new entry for the BBS in the file.  If you use the HOST
+      routing method (see below) you may also need to add the new node
+      to one of the host BBSes.
+
+      After creating the new entry for the joining BBS, tell the sysop of
+      the joining BBS what his BBS Id is.  He will need this information!
+
+   2. Now, you must distribute the updated WORLD.NDX file.  To do this is
+      easy.  Run CLANS with the /NewNDX parameter and it'll send out the
+      NDX file to all boards in the league:
+
+                CLANS /NewNDX
+
+
+That is all!
+
+
+Routing methods
+---------------
+The Clans uses two methods for routing packets and you may use either one or
+both.  The Clans will route data internally so you need not modify your
+existing mail system if one is already in place.
+
+Similar to other InterBBS games, Clans can use the HOST routing method.  This
+method allows you to set up BBSes which act as hosts for other BBSes.  For
+instance, this is a possible BBS setup in a league (each number represents
+a BBS):
+
+                 1
+                / \
+               2   3 - 8
+             / |   | \
+           4   5   6  7
+          /
+        9
+
+* BBS 1 hosts BBSes 2 and 3.
+* 2 hosts 4 and 5.
+* 3 hosts 6, 7, and 8.
+* 4 hosts 9.
+* 5, 6, 7, 8, and 9 are not hosts.
+
+In the WORLD.NDX file, you would represent this system by using the Host
+keyword.  Normally, a node would be represented in the WORLD.NDX file this
+way:
+
+BBSId           1
+BBSName         Revolution Nine
+VillageName     The Village
+Address         3:2/1
+
+To use the host method, use the Host keyword anywhere after the BBSId in
+the block of data:
+
+BBSId           1
+Host            2 3
+BBSName         Revolution Nine
+VillageName     The Village
+Address         3:2/1
+
+The format, as you can see, is "Host a b c d ..." where a, b, c, and d are
+the BBSIds of the BBSes which are nodes of that host.  Following this pattern,
+the above hosting method can be specified this way (only BBSIds are used here
+for clarity.  In the file, you'd use all the data as in the previous example):
+
+BBSId           1
+Host            2 3
+
+BBSId           2
+Host            4 5
+
+BBSId           3
+Host            6 7 8
+
+BBSId           4
+Host            9
+
+BBSId           5
+
+BBSId           6
+
+BBSId           7
+
+BBSId           8
+
+BBSId           9
+
+Since BBSes 5, 6, 7, 8, and 9 are not hosts, they do not use the Host keyword.
+
+The other method for routing is the ROUTE.CFG file.  This file allows you to
+individually set which BBSes you want to route your data through and whether
+or not you wish to CRASH or HOLD packets.  However, ROUTE.CFG will likely
+differ for each system as each one may have different BBSes which they wish
+to route through.  See ROUTE.CFG for more information on how to use the file.
+
+The ROUTE.CFG file (if used) may NOT be the same for each BBS in the league.
+Be sure to tell your nodes if you will use the ROUTE.CFG file or not.
+
+Both the above methods can be used in conjunction with one another.  If the
+Host method is found in the WORLD.NDX file, it will be used.  Anything that
+appears in the ROUTE.CFG will supersede whatever was used in the WORLD.NDX
+file.  In other words, if the Host method is used and it specifies that
+packets being sent to BBS #3 are to be routed through BBS #1 BUT the ROUTE.CFG
+file says to route the packets through BBS #5 instead, BBS #5 will be used
+and not BBS #1.
+
+By using both methods, you can set up more specific methods by using the CRASH
+and HOLD keywords (see ROUTE.CFG for information).
+
+
+Note For Beginners
+------------------
+If you are unsure about routing and the BBSes in the league you are creating
+are all local (i.e. no long distance), all are open 24 hours a day (or a
+close to it), and the league is a small one, you don't need any routing.
+
+However, the simplest method of routing (if you desire one) is to send all data
+through the league coordinator's BBS (BBS #1) by using this keyword in the
+ROUTE.CFG file:
+
+        ROUTE ALL 1
+
+NOTE:  THE LEAGUE COORDINATOR'S ROUTE.CFG SHOULD NOT USE ANY ROUTING IF THIS IS
+       USED.  If the coordinator used ROUTE ALL 1, all his packets would be
+       sent to himself and would NOT be sent out to the other BBSes!  For the
+       league coordinator (if using this simplistic routing), all packets
+       would be sent directly to their respective BBSes (i.e. NO routing).
+
+       To repeat, if using the "ROUTE ALL 1" for your league, everyone in the
+       league EXCEPT the league coordinator should use that setup.  The
+       league coordinator would not use the "ROUTE ALL 1" line in his
+       ROUTE.CFG!
+
+
+[1.5]  Joining an Existing InterBBS League
+-------------------------------------------------------------------------------
+   1. First, you must find an existing Clans league to join.  If you find none,
+      you may wish to start your own league (see the previous section).
+
+   2. Once you find a league to join, tell the league coordinator you would
+      like to join and tell him what you would like to use as your Village
+      name.  The LC will then supply you with a WORLD.NDX file and
+      instructions on the ROUTE.CFG file.  Copy the WORLD.NDX file to your
+      Clans directory.  The coordinator will tell you what your BBS Id is.
+      Remember this number!  Run CONFIG.EXE in your Clans directory and choose
+      the Setup InterBBS option.  Next choose the BBS Id option.  Enter the
+      BBS Id given to you by your league coordinator.
+
+      You should also enter your netmail directory, inbound directory, and
+      choose your mailer type while in the CONFIG.EXE program.
+
+   3. Now you must set up your mailer to process packets for The Clans.
+      Add the following lines to the batch file or run a batch file after
+      getting any packets with your mailer:
+
+        cd \clans               (change this to your clans directory)
+        clans /I                (this processes packets coming in)
+
+   4. Once everything is in place, run the reset program:
+
+        RESET
+
+      Choose the "Join a league" option and you're done.
+      This will reset the game and have it "wait" for a message from the
+      main BBS telling it to start its game (i.e. let local users on).
+      Finally, run CLANS /I to complete the reset process.
+
+   Your game is now ready for InterBBS warfare!  You don't need to add anything
+   to your BBS's nightly maintenance.  (You SHOULD already have "CLANS /M" in
+   the nightly maintenance, if it's not there, however, the game will
+   automatically run the maintenance the first chance it gets each day.)
+
+****** Be sure you toss your netmail right after packets by The Clans are
+       created.
+
+
+[1.5b]  How InterBBS Packets Are Handled
+-------------------------------------------------------------------------------
+The following information is provided so that users who wish to set up an
+IBBS game without a mailer or mail network can do so.
+
+Packets
+-------
+Information between nodes is sent through files called packets.  These packets
+are named in the following manner:
+
+        CLxxxyyy.ida
+
+xxx = BBS ID the packet is from
+yyy = BBS ID the packet is destined for
+id  = league ID
+a   = arbitrary character used by the game to name packets (from 'A' to 'Z')
+
+For instance, a packet from BBS #1 in the league to BBS #9 in league 22 might
+look like this:
+
+        CL001009.22F
+
+The packets leaving BBS #1 appear in the OUTBOUND directory of the clans
+directory.
+
+The inbound directory is where the inbound packets go.  For BBS #3, the
+inbound packets would be named CL???003.ida.
+
+Send Packets
+------------
+The main reason a mailer is used for InterBBS is because it will automatically
+send these packets to their respective BBSes.  If you do not or cannot use
+a mailer, you will need to be able to send these packets back and forth
+between the BBSes.  There are many ways you could do this, via a terminal and
+script or manually.  However, you will still need to set up the WORLD.NDX
+files and ROUTE.CFG files the same way.  For the addresses, you can put in any
+arbitrary addresses.
+
+When you receive a packet from another BBS, put it in a directory you chose
+for the inbound directory in the Clans configuration.  Then run CLANS /I
+to process it.  That's pretty much all you need to do.  Just get those packets
+sent back and forth properly somehow. :)
+
+
+[1.6]  Local InterBBS
+-------------------------------------------------------------------------------
+It is possible for you to set up several copies of the Clans and have each
+one act as a village right on your own computer.  In fact, this was how The
+Clans' InterBBS features were tested.  You do not require a mailer or anything,
+but you will have to set up a mail/outbound directory.  To set up a local
+InterBBS game, follow these instructions:
+
+   1.  Install The Clans in a directory corresponding to each Village.  For
+       instance, if you want 3 villages, you might set it up like this:
+
+                C:\VILLAGE1             -- first Clans game goes here
+                C:\VILLAGE2             -- second game
+                C:\VILLAGE3             -- third game
+
+   2.  Next, set up the batch files to run each game as you would normally for
+       a local game but add on these parameters:
+
+                /LIBBS
+
+       So you might have for node 1:
+
+                CLANS /LIBBS /N1
+
+   3.  Have a daily maintenance run for each copy like so:
+
+                CLANS /LIBBS /M
+
+   4.  Set up the ROUTE.CFG for each like this:
+
+                -- start of file --
+                NORMAL ALL
+                -- end of file --
+
+   5.  Set up the WORLD.NDX file so each BBS is listed (as you normally
+       would).  For the addresses, you can use whatever numbers you want
+       since this is just a local game.  Here's an example set of addresses:
+
+                village1        -- 99:1/1
+                village2        -- 99:1/2
+                village3        -- 99:1/3
+
+   6.  Copy WORLD.NDX to each village directory.
+
+   7.  Modify each clans.cfg file for each board so that each has its own
+       unique BBS Id.  You should make one of them the "Main BBS" by setting
+       its BBS Id to 1.  Make sure each also has its InterBBS flag enabled
+       (use CONFIG.EXE).
+
+   8.  Finally, make an outbound directory called CLANOUT and place it
+       anywhere you want.  You could have C:\CLANOUT for instance.  Then,
+       modify each game's config so that EACH ONE'S outbound directory is
+       CLANOUT and each one's mail directory CLANOUT as well.  This is where
+       the data is exchanged between the different games that you are
+       running.
+
+   9.  Finally, run RESET on all games.  For the main village (BBSId=1)
+       choose Leaguewide reset.  For the other games, choose Join a league.
+
+  10.  To process the packets created by the main Clans game (BBS Id=1) you
+       can optionally run each copy of The Clans in each directory with
+       the /I parameter:
+
+                CLANS /LIBBS /I
+
+       That should be it.  You're done.
+
+
+
+[1.7]  Troubleshooting (+ Q&A)
+-------------------------------------------------------------------------------
+
+[Problem]  The game is rewriting my DOOR.SYS file and setting the username ot
+           all caps and is changing the user time as well.
+[Solution] Use another dropfile type such as DORINFO1.DEF.  OpenDoors screws
+           up with DOOR.SYS for seem reason and chooses to write it again...
+
+[Problem]  Why is your IBBS so crappy?  Let's see some clan attacking and
+           better support for international leagues!  What the hell is this
+           crap?  Clan travelling?  What are you on?!
+[Solution] Play another game if you want those aspects.  Clans was meant to
+           be this way and whining and complaining will get you nowhere.  I
+           wanted something different and put that in, I didn't want the same
+           thing as other games.  Some other ideas people suggested (or
+           maybe I think they suggested) but I don't think fit the game:
+
+                - a tavern
+                - somebody to flirt with (yeah, right)
+                - healing (I think maybe somebody suggested this)
+                - put back the bank (I think it is pretty pointless)
+
+[Problem]  Why's it taking so long for the next version to come out?
+[Solution] I'm university dammit, I've got lots of assignments and studying to
+           do, get off my back.
+
+[Problem]  It tells me it can't find the WORLD.NDX file.
+[Solution] You only need this file if you are in an InterBBS game.  If you
+           aren't in an InterBBS league, make sure you turn OFF the InterBBS
+           option in the CONFIG.EXE program.  If you ARE in a league, be
+           sure to get the WORLD.NDX file from the league coordinator before
+           continuing.  If you ARE the LC, read the documentation on how to
+           create a WORLD.NDX file.
+
+[Problem]  It tells me it can't find the WORLD.DAT file.
+[Solution] You'll need to reset to create this file.  Run RESET.
+
+[Problem]  Users on other boards and in the league come to my board to play
+           but they always have to make new players.  Their data isn't
+           transfered or what?!
+[Solution] Make sure you have set REAL NAMES ONLY for running your door and
+           that all other sysops have done the same.  If this isn't the
+           problem, be sure your routing is working properly and is set
+           right.
+
+[Problem]  You're game is awesome.  I have ideas that you can use, where
+           do I go!?
+[Solution] Hey, that's not a problem.  But email me your ideas anyway:
+
+                tigertigr@yahoo.ca
+
+           If it fits with the context of the game and is a good idea
+           which can be implemented fairly easily, I'll probably put it in!
+
+[Problem]  I added a new node to my Clans league but it hasn't received a reset
+           packet from me.  What's the problem!?
+[Solution] It's likely you set up the WORLD.NDX incorrectly.  If you were
+           using the host routing method, stick with it!  That is, whenever
+           a new node is added, stick him into the hosting hierarchy somehow
+           or else the reset packet (directed to the new node) will be sent
+           to the wrong guy (it shouldn't cause him to reset though since
+           it's not FOR him).  To fix the problem, edit out the new node
+           from your WORLD.NDX file (put # chars in front of that node's
+           entry) and run The Clans with the /I parameter from DOS.  Then
+           fix up your hosting method and uncomment the new node (remove
+           the # chars).  The Clans should now send a reset packet once
+           more to the new node but this time do it correctly.
+
+[Problem]  I've reset and everything and it's been a couple days now and
+           nothing is being received by the other nodes.  It says that they
+           are still awaiting the ok by the league coordinator.
+[Solution] Be sure that the ROUTE.CFG file (if used) is correct.  If you are
+           using a "ROUTE ALL 1" type config where everything is routed through
+           the LC's BBS, then be sure the LC's ROUTE.CFG DOES NOT have
+           "ROUTE ALL 1".  If it does, it'll create an infinite feedback loop
+           where LC's packets will go to itself and screw up everything.
+
+           Another you must be sure of is that your netmail is being tossed.
+           Whenever The Clans creates a null-message (in netmail) the message
+           must be tossed by your mail tosser.
+
+[Problem]  I don't seem to be getting any packets and the game doesn't seem to
+           be making any.  How can I check my setup to see if it is correct?
+[Solution] Use the /Recon parameter when running CLANS to see if a packet is
+           created properly.  The game will create a recon packet (won't
+           affect the game) directed towards the BBS you specify.  For
+           instance, to create a recon packet for BBS #9, use
+
+                CLANS /Recon 9
+
+Some common errors with configs (see if you did this if you have problems):
+
+        WORLD.NDX --
+
+              * Host method is used but some BBSes are left out.
+                Ex (only two lines are shown for clarity):
+
+                BBSID   1
+                Host 2
+
+                BBSID   2
+
+                BBSID   3
+
+                Here BBS #3 is not linked up to anyone, all BBSes must
+                be linked up in the host hierarchy.
+
+        CLANS.CFG --
+
+                BBS ID is incorrect.  Make sure your BBS Id is the as the
+                one listed in the WORLD.NDX file.  If it isn't, change it!
+
+
+
+[1.8]  Miscellany
+-------------------------------------------------------------------------------
+The Clans was first developed around the fall of 1996.  Coding began, around
+December of that year.  First beta appeared on the webpage on March 25, 1997.
+
+Special thanks to:
+
+Rev.Nine users  -- thanks for playing the game so rigorously and loving it!
+Title Page Man  -- thanks for helping me test out the InterBBS features!
+All beta testers who emailed me with bugs -- thanks. :)
+Phil205 Prof    -- thanks for an incredibly dull class which forced me to
+                   think up ideas for this game.
+The following bands for providing me with music in my CD player while I
+programmed in the wee ours of the night:  My Bloody Valentine, Lush, Sloan,
+Blur, Teenage Fanclub, Stereolab and The Beatles. :-)
+The Clans v0.95b7:  Upgrading
+-----------------------------
+
+All this fixes is the clans.pak file (i.e. NPC not found error message is
+no longer encountered in mines)
+
+IMPORTANT:
+
+
+If you are using a version BELOW v0.95b4:
+
+* You must reset after upgrading.
+
+* If you are in a league, get everybody to upgrade then have everybody reset
+  and choose the Join a league option while you (the LC) reset the whole
+  league.
+
+* If you have any packets lying around from previous league games, delete them
+  all before upgrading!  They're easy to spot, just look for files of the
+  form CLxxxyyy.* in your inbound directory
+
+If you are using v0.95b4 or higher and upgrading, no reset is required.
+
+------------------------------------------------------------------------------
+Email me with bug reports please:  tigertigr@yahoo.ca
diff --git a/src/doors/clans-src/door.c b/src/doors/clans-src/door.c
new file mode 100644
index 0000000000000000000000000000000000000000..320268c216bd56f2805098592fceae9c7b7a505f
--- /dev/null
+++ b/src/doors/clans-src/door.c
@@ -0,0 +1,953 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Door-specific ADT
+ *
+ * -- All other functions which deal with door specific stuff, should use this
+ *    ADT and NOT OpenDoors...
+ *
+ *
+ * DoorInit MUST be called before all other functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <dos.h>
+#include <share.h>
+#include <conio.h>
+#endif
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "ibbs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "system.h"
+// #include "tslicer.h"
+#include "video.h"
+#include "door.h"
+#include "village.h"
+#include "myopen.h"
+#include "parsing.h"
+#include "help.h"
+
+#define ASCIIFILE	0
+#define ANSIFILE  1
+
+#define COLOR	0xB800
+#define MONO	0xB000
+
+extern struct system System;
+extern struct config *Config;
+extern struct Language *Language;
+extern struct clan *PClan;
+extern char Spells_szCastDestination[25];
+extern char Spells_szCastSource[25];
+extern _INT16 Spells_CastValue;
+extern struct village Village;
+extern struct game Game;
+extern BOOL Verbose;
+
+struct {
+  BOOL Initialized;
+  BOOL AllowScreenPause;
+
+  char ColorScheme[50];
+
+  BOOL UserBooted;            // True if a user was online already
+} Door = { FALSE, TRUE,
+  { 1, 9, 3, 1, 11, 7, 3, 2, 10, 2, 5, 3, 9, 5, 13, 1, 9, 15, 7, 0, 0, 8, 4,
+    1, 1, 1 },
+  FALSE
+     };
+
+// ------------------------------------------------------------------------- //
+
+  __BOOL Door_Initialized ( void )
+    /*
+     * Returns TRUE if od_init was already called.
+     */
+  {
+    return Door.Initialized;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void CreateSemaphor( void )
+  {
+    FILE *fp;
+
+    fp = _fsopen("online.flg", "wb", SH_DENYRW);
+    fwrite(&System.Node, sizeof(_INT16), 1, fp);
+    fclose(fp);
+  }
+
+  void RemoveSemaphor( void )
+  {
+    unlink("online.flg");
+  }
+
+  BOOL SomeoneOnline ( void )
+    /*
+     * Function will check if a user is online by seeing if a semaphor file
+     * exists.
+     */
+  {
+    FILE *fp;
+    _INT16 WhichNode;
+
+    fp = _fsopen("online.flg", "rb", SH_DENYWR);
+    if (fp)
+    {
+      fread(&WhichNode, sizeof(_INT16), 1, fp);
+      fclose(fp);
+
+      // if node is same as current node, disregard this file
+      if (WhichNode == System.Node)
+        return FALSE;
+      else
+        return TRUE;
+    }
+    else
+      return FALSE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Door_SetColorScheme ( char *ColorScheme )
+    /*
+     * This function will set the color scheme.
+     */
+  {
+    _INT16 iTemp;
+
+    for (iTemp = 0; iTemp < 50; iTemp++)
+      Door.ColorScheme[iTemp] = ColorScheme[iTemp];
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void LocalLoad(void)
+    /*
+     * This function will read in the local user's login name.
+     *
+     */
+  {
+#ifdef __unix__
+
+//#elif defined(ODPLAT_WIN32)
+	  // Todo create local login screen
+#else
+    char name[80], szString[128];
+    _INT16 i;
+
+    /* display box */
+    clrscr();
+
+    zputs(ST_LOCAL1);
+    zputs(ST_LOCAL2);
+    zputs(ST_LOCAL3);
+    zputs(ST_LOCAL4);
+    zputs(ST_LOCAL5);
+    zputs(ST_LOCAL6);
+    zputs(ST_LOCAL7);
+    zputs(ST_LOCAL8);
+    zputs(ST_LOCAL9);
+    zputs(ST_LOCAL10);
+    zputs(ST_LOCAL11);
+
+    // if in a league, tell the guy
+    if (Game.Data->InterBBS)
+    {
+      IBBS_LoginStats();
+    }
+
+    qputs(" |09The Clans |07" VERSION, 0, 16);
+
+    sprintf(szString, " |07Enter login name.  Press [|09Enter|07] for |14%s", Config->szSysopName);
+    qputs(szString, 0, 18);
+    sprintf(szString, " |07Node |09%03d  |15> ", System.Node);
+    qputs(szString, 0, 19);
+
+    name[0] = 0;
+    szString[0] = 0;
+    gotoxy(14,20);
+    Input(szString, 27);
+
+    if (strlen(szString))
+      strcpy (name, szString);
+    else
+    {
+      if (strlen(Config->szSysopName))
+        strcpy (name, Config->szSysopName);
+      else
+        strcpy (name, "Sysop");
+    }
+
+    zputs("|16");
+
+    strcpy(od_control.user_name, name);
+/*    for (i = 0; i < (signed)strlen(name); i++)
+      name[i] = toupper(name[i]); */
+    strcpy(od_control.user_location, Config->szBBSName);
+    od_control.user_timelimit = 30;
+    od_control.od_info_type = CUSTOM;
+    od_control.user_ansi = TRUE;
+    od_control.user_screen_length = 25;
+
+    System.Local = TRUE;
+#endif
+  }
+
+// ------------------------------------------------------------------------- //
+
+    /*
+     * Functions run before and after chat respectively.
+     *
+     */
+
+  void BeforeChat ( void )
+  {
+    rputs(ST_BEFORECHAT);
+  }
+
+  void AfterChat ( void )
+  {
+    rputs(ST_AFTERCHAT);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void NoDoorFileHandler(void)
+    /*
+     * If no dropfile was found, this function is run.
+     */
+  {
+    if (!System.Local)
+    {
+      /* show title ascii */
+
+      zputs(ST_NODOORFILE);
+      delay(2500);
+      System_Close();
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+  BOOL StatusOn = TRUE;
+
+  void NoStatus ( void )
+    /*
+     * If no status line is chosen, this is run?
+     */
+  {
+#ifndef __unix__
+    if (StatusOn)
+    {
+      od_set_statusline(STATUS_NONE);
+      StatusOn = FALSE;
+    }
+    else
+    {
+      StatusOn = TRUE;
+      od_set_statusline(STATUS_NORMAL);
+
+      if (Video_VideoType() == MONO)
+      {
+        ClearArea(0,23,  79,24,  (7<<4) );
+        qputs("|23|00The C l a n s   " VERSION " copyright 1998 Allen Ussher    F1-F3 toggles status bar  ", 0, 24);
+      }
+      else
+      {
+        ClearArea(0,23,  79,24,  7|(1<<4));
+        qputs("|15|17The C l a n s   |00" VERSION " |03copyright 1998 Allen Ussher    |00F1-F3 toggles status bar  |16", 0, 24);
+      }
+    }
+#endif
+  }
+
+  void TwoLiner ( unsigned char which )
+    /*
+     * Two line status line function.
+     */
+  {
+#ifndef __unix__
+    char szString[128];
+    static char Status[2][155];
+
+    switch(which)
+    {
+      case PEROP_INITIALIZE :
+        od_control.key_status[0] = 0x3B00;    // F1
+        od_control.key_status[1] = 0x3C00;    // F2
+        od_control.key_status[2] = 0x3D00;    // F3
+        od_control.key_status[3] = 0;    // F4
+        od_control.key_status[4] = 0;    // F5
+        od_control.key_status[5] = 0;    // F6
+        od_control.key_status[6] = 0;    // F7
+        od_control.key_status[7] = 0;    // F8
+
+        od_control.od_hot_key[od_control.od_num_keys] = 0x4300;    // F9
+        od_control.od_hot_function[od_control.od_num_keys] = NoStatus;
+        od_control.od_num_keys++;
+
+        od_control.key_chat = 0x2E00;     // Alt-C
+        od_control.key_drop2bbs = 0x2000;   // Alt-D
+        od_control.key_dosshell = 0x2400;   // Alt-J
+        od_control.key_hangup = 0x2300;     // Alt-H
+        od_control.key_keyboardoff = 0x2500;  // Alt-K
+        od_control.key_lesstime = 0x5000;   // dn key
+        od_control.key_moretime = 0x4800;   // up key
+
+        if (Video_VideoType() == MONO)
+        {
+          ClearArea(0,23,  79,24,  (7<<4) );
+          qputs("|23|00The C l a n s   " VERSION " copyright 1998 Allen Ussher    F1-F3 toggles status bar  ", 0, 24);
+        }
+        else
+        {
+          ClearArea(0,23,  79,24,  7|(1<<4));
+
+          qputs("|15|17The C l a n s   |00" VERSION " |03copyright 1998 Allen Ussher    |00F1-F3 toggles status bar  |16", 0, 24);
+        }
+        break;
+      case PEROP_DEINITIALIZE :
+        break;
+      case PEROP_DISPLAY1 :
+        if (!StatusOn)  NoStatus();
+
+        sprintf(Status[0], "%s of %-010s                     ", od_control.user_name, od_control.user_location);
+        xputs(Status[0], 0, 23);
+        sprintf(Status[1], " Baud: %5ld Time: %2d      %s    Node: %3d ", od_control.baud, od_control.user_timelimit - od_control.user_time_used, (od_control.user_ansi) ? "[ANSI] " : "[ASCII]", System.Node);
+        xputs(Status[1], 31, 23);
+        break;
+      case PEROP_UPDATE1 :
+        if (!StatusOn)  NoStatus();
+
+        xputs(Status[0], 0, 23);
+
+        sprintf(szString, "%-3d", od_control.user_timelimit - od_control.user_time_used);
+
+        Status[1][19] = szString[0];
+        Status[1][20] = szString[1];
+        Status[1][21] = szString[2];
+        Status[1][22] = szString[3];
+        xputs(Status[1], 31, 23);
+        break;
+      case PEROP_DISPLAY2 :
+      case PEROP_UPDATE2 :
+        if (!StatusOn)  NoStatus();
+        xputs("Alt+ [H]angup  [J]ump to DOS  [C]hat w/User  [D]rop to BBS                      ", 0, 23);
+        break;
+      case PEROP_DISPLAY3 :
+      case PEROP_UPDATE3 :
+        if (!StatusOn)  NoStatus();
+        xputs("[F9] Toggle Status Line ON/OFF  [Up] Give Time to user  [Down] Take Time        ", 0, 23);
+        break;
+    }
+#endif
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Door_ToggleScreenPause ( void )
+  {
+    Door.AllowScreenPause = !Door.AllowScreenPause;
+  }
+
+  void Door_SetScreenPause ( __BOOL State )
+  {
+    Door.AllowScreenPause = State;
+  }
+
+  __BOOL Door_AllowScreenPause ( void )
+  {
+    return Door.AllowScreenPause;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void door_pause( void )
+    /*
+     * Displays <pause> prompt.
+     */
+  {
+    char *pc;
+
+    rputs(ST_PAUSE);
+
+    /* wait for user to hit key */
+    while (od_get_key(TRUE) == FALSE)
+      od_sleep(0);
+
+    od_putch('\r');
+    pc = ST_PAUSE;
+    while (*pc)
+    {
+      od_putch(' ');
+      pc++;
+    }
+    od_putch('\r');
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void rputs( char *string )
+    /*
+     * Outputs the pipe or ` encoded string.
+     */
+  {
+    _INT16 i;
+    char number[3]; // two digit number!
+    char *pCurChar,*pStrChar;
+    _INT16 attr;  // color
+    static _INT16 o_fg = 7, o_bg = 0;
+    static _INT16 old_fg = 7, old_bg = 0;
+    char szString[128],
+         *szQuality[4] = { "Average", "Good", "Very Good", "Excellent" };
+
+    if (!(*string))
+      return;
+
+    pCurChar = string;
+
+    while (*pCurChar)
+    {
+      for(pStrChar=pCurChar;*pStrChar!='|'&&*pStrChar!=0&&*pStrChar!=SPECIAL_CODE&&*pStrChar!='\n'&&*pStrChar!='`'&&*pStrChar!=SPECIAL_CODE;pStrChar++);
+      od_disp( pCurChar, pStrChar-pCurChar, FALSE );
+      pCurChar=pStrChar;
+      if(!(*pCurChar))break;
+
+      if ( (*pCurChar) == '|')
+      {
+        if ( isdigit( *(pCurChar + 1) ) && isdigit( *(pCurChar +2)) )
+        {
+          number[0] = *(pCurChar+1);
+          number[1] = *(pCurChar+2);
+          number[2] = 0;
+
+          attr = atoi(number);
+          if (attr > 15)
+          {
+            if (o_bg != (attr-16))
+            {
+              o_bg = attr - 16;
+              od_set_colour(o_fg, o_bg);
+            }
+          }
+          else
+          {
+            if (o_fg != attr)
+            {
+              o_fg = attr;
+              od_set_colour(o_fg, o_bg);
+            }
+          }
+          pCurChar += 3;
+        }
+        else if ( *(pCurChar+1) == '0' && isalpha(*(pCurChar+2)) )
+        {
+          if (!(o_fg == Door.ColorScheme[ *(pCurChar+2) - 'A'] &&
+            o_bg == 0))
+          {
+            o_fg = Door.ColorScheme[ *(pCurChar+2) - 'A'];
+            o_bg = 0;
+
+            od_set_colour(o_fg, o_bg);
+          }
+          pCurChar += 3;
+        }
+        else if ( *(pCurChar+1) == 'S')
+        {
+          old_fg = o_fg;
+          old_bg = o_bg;
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'R')
+        {
+          o_fg = old_fg;
+          o_bg = old_bg;
+
+          od_set_colour(o_fg, o_bg);
+          pCurChar += 2;
+        }
+        else
+        {
+          od_emulate( *pCurChar );
+          pCurChar++;
+        }
+
+      }
+      else if ( (*pCurChar) == SPECIAL_CODE)
+      {
+        if ( *(pCurChar+1) == 'P')
+        {
+          /* pause */
+          pCurChar += 2;
+          door_pause();
+        }
+        else if ( *(pCurChar+1) == 'C')
+        {
+          /* cls */
+          od_clr_scr();
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'B')
+        {
+          /* backspace */
+          od_putch('\b');
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'V')
+        {
+          /* version */
+          rputs(VERSION);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'N')
+        {
+          Door_ToggleScreenPause();
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'T')
+        {
+          /* send 24 CR/LF to "clear" line*/
+          for (i = 0; i < od_control.user_screen_length; i++)
+          {
+            od_disp_str("\n\r");
+            delay(10);
+          }
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'Y')
+        {
+          /* send 24 CR/LF to "clear" line*/
+          for (i = 0; i < od_control.user_screen_length; i++)
+            od_disp_str("\n\r");
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'Z')
+        {
+          /* end line */
+          return;
+        }
+        else if ( *(pCurChar+1) == 'D')
+        {
+          /* delay 100 */
+          delay(100);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'R')
+        {
+          /* \r */
+          od_disp_str("\r");
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'L')
+        {
+          /* \r */
+          od_disp_str("\n\r");
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'F')
+        {
+          /* fights remaining */
+          sprintf(szString, "%d", PClan->FightsLeft);
+          rputs(szString);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'M')
+        {
+          /* mine level */
+          sprintf(szString, "%d", PClan->MineLevel);
+          rputs(szString);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'S')
+        {
+          /* spellcasting options */
+          switch(*(pCurChar+2))
+          {
+            case 'S' : /* source of cast */
+              rputs(Spells_szCastSource);
+              pCurChar += 3;
+              break;
+            case 'D' : /* destination/target of cast */
+              rputs(Spells_szCastDestination);
+              pCurChar += 3;
+              break;
+            case 'V' : /* value of cast */
+              sprintf(szString, "%d", Spells_CastValue);
+              rputs(szString);
+              pCurChar += 3;
+              break;
+            default :
+              pCurChar++;
+              break;
+          }
+        }
+        else if ( *(pCurChar+1) == '1')
+        {
+          /* pawn level */
+          sprintf(szString, "%d", Village.Data->PawnLevel);
+          rputs(szString);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == '2')
+        {
+          /* wiz shop level */
+          sprintf(szString, "%d", Village.Data->WizardLevel);
+          rputs(szString);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'X')
+        {
+          /* mine level */
+          sprintf(szString, "%d", Village.Data->MarketLevel);
+          rputs(szString);
+          pCurChar += 2;
+        }
+        else if ( *(pCurChar+1) == 'Q')
+        {
+          /* market quality level */
+
+          sprintf(szString, "%s", szQuality[Village.Data->MarketQuality]);
+          rputs(szString);
+          pCurChar += 2;
+        }
+        else
+        {
+          // od_emulate( *pCurChar );
+          od_putch( *pCurChar );
+          pCurChar++;
+        }
+      }
+      else if ( (*pCurChar) == '\n')
+      {
+        od_putch('\n');
+        od_putch('\r');
+        pCurChar++;
+      }
+      else if ( (*pCurChar) == '`' && iscodechar( *(pCurChar + 1) )
+        && iscodechar( *(pCurChar +2)) )
+      {
+        pCurChar++;
+
+        // get background
+        if (isdigit(*pCurChar))
+          o_bg = *pCurChar - '0';
+        else
+          o_bg = *pCurChar - 'A' + 10;
+
+        pCurChar++;
+
+        // get foreground
+        if (isdigit(*pCurChar))
+          o_fg = *pCurChar - '0';
+        else
+          o_fg = *pCurChar - 'A' + 10;
+
+        od_set_colour(o_fg, o_bg);
+
+        pCurChar++;
+      }
+      else
+      {
+        //od_emulate( *pCurChar );
+        od_putch( *pCurChar );
+        pCurChar++;
+      }
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Display( char *FileName )
+    /*
+     * Displays the file given.
+     */
+  {
+    /* if file ends in .ASC, assume that it is pipe codes */
+    /* if file ends in .ANS, assume it is ANSI */
+    /* if ends in something else, assume pipe codes */
+
+    _INT16 FileType; /* 0 == ASCII, 1 == ANSI */
+    _INT16 CurLine = 0, NumLines, cTemp;
+    long MaxBytes;
+    char *Lines[30];
+    struct FileHeader FileHeader;
+
+    if ( (toupper(FileName[ strlen(FileName) - 3 ]) == 'A' ) &&
+       (toupper(FileName[ strlen(FileName) - 2 ]) == 'N' ) &&
+       (toupper(FileName[ strlen(FileName) - 1 ]) == 'S' ) )
+      FileType = ANSIFILE;
+    else
+      FileType = ASCIIFILE;
+
+    /* now display it according to the type of file it is */
+    // open the file
+    MyOpen(FileName, "r", &FileHeader);
+
+    if (!FileHeader.fp)
+    {
+      /* rputs("Display: File not found!\n"); */
+      return;
+    }
+
+    /* init mem */
+    for (cTemp = 0; cTemp < 30; cTemp++)
+    {
+      Lines[cTemp] = malloc(255);
+      CheckMem(Lines[cTemp]);
+    }
+
+    for (;;)
+    {
+      // if at end of file, stop
+      /* get od_control.user_screen_length-3 lines if possible */
+      for (cTemp = 0; cTemp < (od_control.user_screen_length-3) && cTemp < 30; cTemp++)
+      {
+        MaxBytes = FileHeader.lEnd - ftell(FileHeader.fp) + EXTRABYTES;
+        if (MaxBytes > 254)
+          MaxBytes = 254;
+
+        if (ftell(FileHeader.fp) >= FileHeader.lEnd || feof(FileHeader.fp))
+        {
+          break;
+        }
+
+        if (!fgets(Lines[cTemp], (_INT16) MaxBytes, FileHeader.fp))
+          break;
+
+        Lines[cTemp][(_INT16)(MaxBytes - EXTRABYTES + 1)] = 0;
+      }
+      NumLines = cTemp;
+
+      /* display them all */
+      for (CurLine = 0; CurLine < NumLines; CurLine++)
+      {
+        if (FileType == ANSIFILE)
+          od_disp_emu(Lines[CurLine], TRUE);
+        else  /* assume ASCII pipe codes */
+          rputs(Lines[CurLine]);
+      }
+
+      /* pause if od_control.user_screen_length-3 lines */
+      if (CurLine == (od_control.user_screen_length-3) && Door.AllowScreenPause)
+      {
+        rputs(ST_MORE);
+        od_sleep(0);
+        if (toupper(od_get_key(TRUE)) == 'N')
+        {
+          rputs("\r                       \r");
+          break;
+        }
+        rputs("\r                       \r");
+
+        CurLine = 0;
+      }
+      else if (Door.AllowScreenPause == FALSE)
+        CurLine = 0;
+
+      /* see if end of file, if so, exit */
+      if (ftell(FileHeader.fp) >= FileHeader.lEnd || feof(FileHeader.fp))
+        break;
+
+      /* see if key hit */
+      if (od_get_key(FALSE)) break;
+    }
+
+    fclose(FileHeader.fp);
+
+    /* de-init mem */
+    for (cTemp = 0; cTemp < 30; cTemp++)
+      free(Lines[cTemp]);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 YesNo( char *Query )
+  {
+    /* show query */
+    DisplayStr(Query);
+
+    /* show Yes/no */
+    // rputs(" |01[|09Yes|01/no]: ");
+    DisplayStr(STR_YESNO);
+
+    /* get user input */
+    if (od_get_answer("YN\r\n") == 'N')
+    {
+      /* user says NO */
+      DisplayStr("No\n");
+      return NO;
+    }
+    else  /* user says YES */
+    {
+      DisplayStr("Yes\n");
+      return YES;
+    }
+  }
+
+  _INT16 NoYes( char *Query )
+  {
+    /* show query */
+    DisplayStr(Query);
+
+    /* show Yes/no */
+    // rputs(" |01[yes/|09No|01]: ");
+    DisplayStr(STR_NOYES);
+
+    /* get user input */
+    if (od_get_answer("YN\r\n") == 'Y')
+    {
+      /* user says YES */
+      DisplayStr("Yes\n");
+      return (YES);
+    }
+    else  /* user says NO */
+    {
+      DisplayStr("No\n");
+      return (NO);
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+  void Door_ShowTitle ( void )
+  {
+    char szFileName[20];
+
+    sprintf(szFileName, "Title %d", (_INT16) RANDOM(3));
+
+    Door_SetScreenPause(FALSE);
+    Help(szFileName, ST_MENUSHLP);
+    Door_SetScreenPause(TRUE);
+    rputs("|16|07");
+    od_get_key(TRUE);
+    od_clr_scr();
+  }
+// ------------------------------------------------------------------------- //
+
+  void Door_Init ( __BOOL Local )
+    /*
+     * Called to initialize OpenDoors specific info (od_init namely) and
+     * load the dropfile or prompt the user for local login.
+     */
+  {
+    if (Verbose)
+    {
+      DisplayStr("> Door_Init()\n");
+      delay(500);
+    }
+
+    /* force opendoors to NOT show copyright message */
+    od_control.od_nocopyright = TRUE;
+    od_control.od_node = System.Node;
+    od_control.od_before_exit = System_Close;
+    //    od_registration_key = YOUR_KEY;
+
+    /* If local, intialize user data before od_init is run */
+    if (Local)
+    {
+      od_control.od_info_type = NO_DOOR_FILE;
+      od_control.od_force_local = TRUE;
+      od_control.user_ansi = TRUE;
+      od_control.od_always_clear = TRUE;
+	  od_control.od_disable |= DIS_NAME_PROMPT;
+	  od_control.baud = 0;
+
+      LocalLoad();
+    }
+
+    /* initialize opendoors ------------------------------------------------*/
+    od_control.od_mps = INCLUDE_MPS;
+
+    strcpy(od_registered_to, "Your Name");
+
+    od_add_personality("TWOLINER", 1, 23, TwoLiner);
+    od_control.od_default_personality = TwoLiner;
+      
+    // 12/23/2001 [au] no longer use time-slicer
+    //    od_control.od_ker_exec = TSlicer_Update;
+
+    od_control.od_cbefore_chat = BeforeChat;
+    od_control.od_cafter_chat = AfterChat;
+
+    od_control.od_chat_colour1 = 14;
+    od_control.od_chat_colour2 = 7;
+
+    od_control.od_no_file_func = NoDoorFileHandler;
+
+    od_init();
+
+#ifdef _WIN32
+	/* All need for the console has passed */
+	FreeConsole();
+#endif
+
+
+    Door.Initialized = TRUE;
+
+    od_control.od_before_chat = "";
+    od_control.od_after_chat = "";
+
+    /* see if local using dropfile */
+    if (System.Local == FALSE)
+    {
+      if (od_carrier() == FALSE)
+      {
+        System.Local = TRUE;
+      }
+    }
+
+    if (SomeoneOnline())
+    {
+      //  rputs("\nSomeone is currently playing the game on another node.\nPlease return in a few minutes.\n%P");
+      Door.UserBooted = TRUE;
+      rputs(ST_MAIN4);
+      System_Close();
+    }
+
+    // otherwise, create semaphor
+    CreateSemaphor();
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Door_Close ( void )
+    /*
+     * Called to destroy anything created by Door_Init.
+     */
+  {
+    if (Door.UserBooted == FALSE)
+      RemoveSemaphor();
+  }
diff --git a/src/doors/clans-src/door.h b/src/doors/clans-src/door.h
new file mode 100644
index 0000000000000000000000000000000000000000..eb1c852ca65ab48f43168237f6a8bdfa52e75b52
--- /dev/null
+++ b/src/doors/clans-src/door.h
@@ -0,0 +1,49 @@
+/*
+ * Door-specific ADT
+ */
+
+  void Door_Init ( __BOOL Local );
+    /*
+     * Called to initialize OpenDoors specific info (od_init namely) and
+     * load the dropfile or prompt the user for local login.
+     */
+
+  void Door_Close ( void );
+    /*
+     * Called to destroy anything created by Door_Init.
+     */
+
+  __BOOL Door_Initialized ( void );
+    /*
+     * Returns TRUE if od_init was already called.
+     */
+
+
+  void Door_SetColorScheme ( char *ColorScheme );
+    /*
+     * This function will set the color scheme.
+     */
+
+  void rputs(char *string);
+    /*
+     * Outputs the pipe or ` encoded string.
+     */
+
+  void door_pause( void );
+    /*
+     * Displays <pause> prompt.
+     */
+
+  void Display( char *FileName );
+    /*
+     * Displays the file given.
+     */
+
+  _INT16 YesNo( char *Query );
+  _INT16 NoYes( char *Query );
+
+  void Door_ToggleScreenPause ( void );
+  void Door_SetScreenPause ( __BOOL State );
+  __BOOL Door_AllowScreenPause ( void );
+
+  void Door_ShowTitle ( void );
diff --git a/src/doors/clans-src/empire.c b/src/doors/clans-src/empire.c
new file mode 100644
index 0000000000000000000000000000000000000000..b6683509198073c3ee181357125de9531949386f
--- /dev/null
+++ b/src/doors/clans-src/empire.c
@@ -0,0 +1,3542 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Empire ADT
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#include <string.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "help.h"
+#include "input.h"
+#include "door.h"
+#include "news.h"
+#include <OpenDoor.h>
+#include "user.h"
+#include "fight.h"
+#include "alliance.h"
+#include "mail.h"
+#include "packet.h"
+#include "ibbs.h"
+#include "myopen.h"
+
+// empire owner types
+#define EO_VILLAGE    0
+#define EO_ALLIANCE 	1
+#define EO_CLAN       2
+
+#define MAX_VILLAGEEMPIREATTACKS    2
+#define MAX_EMPIREATTACKS           5
+
+#define MAX_SPIES		10
+#define SPY_COST		1000L
+
+// our goals
+#define G_OUSTRULER     0
+#define G_STEALLAND     1
+#define G_STEALGOLD     2
+#define G_DESTROY       3
+
+#define SCOST_FOOTMAN   15
+#define SCOST_AXEMEN    30
+#define SCOST_KNIGHT    60
+#define SCOST_CATAPULT	120
+
+// stats for army
+#define DAMAGE_FACTOR	60
+#define SPD_FOOTMEN 	5
+#define SPD_AXEMEN		3
+#define SPD_KNIGHTS 	7
+#define OFF_FOOTMEN 	6
+#define OFF_AXEMEN		8
+#define OFF_KNIGHTS 	9
+#define DEF_FOOTMEN 	2
+#define DEF_AXEMEN		4
+#define DEF_KNIGHTS 	1
+#define VIT_FOOTMEN 	8
+#define VIT_AXEMEN      7
+#define VIT_KNIGHTS 	6
+
+
+extern struct config *Config;
+extern struct game Game;
+extern struct Language *Language;
+extern struct clan *PClan;
+extern struct village Village;
+
+
+struct BuildingType BuildingType[NUM_BUILDINGTYPES] =
+		{
+    {"Barracks",            5, 15,  30,  2500 },
+    {"Walls",              15, 5,    7,  1000 },
+    {"Towers",             10, 8,   12,  1500 },
+    {"Steel Mill",          8, 20,  28,  3000 },
+    {"Stables",            10, 20,  40,  5000 },
+    {"Intell. Agencies",    9, 10,  25,  1000 },
+    {"Security Centers",    9, 10,  25,  1000 },
+    {"Gymnasiums",         10, 5,   20,  4500 },
+    {"Developer's Halls",   7, 10,  15,  3000 },
+    {"Shops",               8, 20,  30,  5000 }
+		};
+
+extern struct ibbs IBBS;
+
+  void DestroyBuildings ( _INT16 NumBuildings[MAX_BUILDINGS],
+    _INT16 NumDestroyed[MAX_BUILDINGS], _INT16 Percent, _INT16 *LandGained );
+
+  void EmpireAttack ( struct empire *AttackingEmpire, struct Army *AttackingArmy,
+    struct empire *DefendingEmpire, struct AttackResult *Result,
+    _INT16 Goal, _INT16 ExtentOfAttack);
+
+  void ProcessAttackResult ( struct AttackResult *AttackResult );
+
+// ------------------------------------------------------------------------- //
+  void SendResultPacket(struct AttackResult *Result, _INT16 DestID)
+  {
+    Result->ResultIndex = IBBS.Data->Nodes[DestID-1].Attack.SendIndex+1;
+    IBBS.Data->Nodes[DestID-1].Attack.SendIndex++;
+
+    IBBS_SendPacket ( PT_ATTACKRESULT, sizeof(struct AttackResult), Result,
+                          DestID );
+  }
+
+
+  void ProcessAttackPacket ( struct AttackPacket *AttackPacket )
+  {
+    struct AttackResult *Result;
+    _INT16 LandGained, iTemp;
+
+    // initialize result beforehand
+    Result = malloc(sizeof(struct AttackResult));
+    CheckMem(Result);
+    Result->Success = FALSE;
+    Result->NoTarget= FALSE;
+    Result->InterBBS = TRUE;
+    Result->AttackerType = AttackPacket->AttackingEmpire.OwnerType;
+    Result->AttackerID[0] = AttackPacket->AttackOriginatorID[0];
+    Result->AttackerID[1] = AttackPacket->AttackOriginatorID[1];
+    Result->AllianceID = -1;
+    strcpy(Result->szAttackerName, AttackPacket->AttackingEmpire.szName);
+    Result->DefenderType = AttackPacket->TargetType;
+    Result->AttackIndex = AttackPacket->AttackIndex;
+
+    if (Result->DefenderType == EO_VILLAGE)
+    {
+      Result->DefenderID[0] = Village.Data->RulingClanId[0];
+      Result->DefenderID[1] = Village.Data->RulingClanId[1];
+      strcpy(Result->szDefenderName, Village.Data->szName);
+    }
+    else if (Result->DefenderType == EO_CLAN)
+    {
+      Result->DefenderID[0] = AttackPacket->ClanID[0];
+      Result->DefenderID[1] = AttackPacket->ClanID[1];
+      GetClanNameID(Result->szDefenderName, Result->DefenderID);
+    }
+
+    Result->BBSIDFrom = AttackPacket->BBSFromID;
+    Result->BBSIDTo   = IBBS.Data->BBSID;
+
+    Result->PercentDamage = 0;
+    Result->Goal = AttackPacket->Goal;
+    Result->ExtentOfAttack = AttackPacket->ExtentOfAttack;
+
+    Result->AttackCasualties.Footmen = 0;
+    Result->AttackCasualties.Axemen  = 0;
+    Result->AttackCasualties.Knights = 0;
+    Result->DefendCasualties.Footmen = 0;
+    Result->DefendCasualties.Axemen  = 0;
+    Result->DefendCasualties.Knights = 0;
+
+    for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+      Result->BuildingsDestroyed[iTemp] = 0;
+
+    Result->GoldStolen = 0;
+    Result->LandStolen = 0;
+
+    Result->ReturningArmy.Footmen = AttackPacket->AttackingArmy.Footmen;
+    Result->ReturningArmy.Axemen  = AttackPacket->AttackingArmy.Axemen;
+    Result->ReturningArmy.Knights = AttackPacket->AttackingArmy.Knights;
+
+    // if no ruler, skip this
+    if ((Village.Data->RulingClanId[0] == -1 && AttackPacket->TargetType == EO_VILLAGE
+      && AttackPacket->Goal == G_OUSTRULER)
+       || (ClanExists(Result->DefenderID) == FALSE && AttackPacket->TargetType == EO_CLAN))
+    {
+      Result->NoTarget = TRUE;
+
+      // set everything to 0
+      Result->Success = FALSE;
+      Result->OrigAttackArmy = AttackPacket->AttackingArmy;
+    }
+    else
+    {
+      EmpireAttack (&AttackPacket->AttackingEmpire, &AttackPacket->AttackingArmy,
+        &Village.Data->Empire, Result,
+        AttackPacket->Goal, AttackPacket->ExtentOfAttack);
+
+      // process result -- this writes messages, updates news
+      ProcessAttackResult(Result);
+    }
+
+    // send back result to other BBS
+    SendResultPacket(Result, Result->BBSIDFrom);
+
+    // update defender's army
+    Village.Data->Empire.Army.Footmen -= Result->DefendCasualties.Footmen;
+    Village.Data->Empire.Army.Axemen  -= Result->DefendCasualties.Axemen;
+    Village.Data->Empire.Army.Knights -= Result->DefendCasualties.Knights;
+
+    // "give" the defender land from which his buildings came from
+    //   this land is "gained" because of buildings destroyed
+    LandGained = 0;
+    for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+    {
+      LandGained += (Result->BuildingsDestroyed[iTemp]*BuildingType[iTemp].LandUsed);
+    }
+    Village.Data->Empire.Land += LandGained;
+
+    // update his losses
+    Village.Data->Empire.VaultGold -= Result->GoldStolen;
+    Village.Data->Empire.Land -= Result->LandStolen;
+
+    for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+    {
+      Village.Data->Empire.Buildings[iTemp] -= Result->BuildingsDestroyed[iTemp];
+    }
+
+    free(Result);
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  void ProcessResultPacket ( struct AttackResult *Result )
+  {
+    // if village, update village's stats
+
+    // if clan, update his stats
+
+    struct Packet Packet;
+    struct AttackPacket *AttackPacket;
+    struct clan *TmpClan;
+    char szNews[255], szAttackerName[35], szDefenderName[40], *szMessage,
+      szGoal[40], szOutcome[30], *szString, *cpBuffer;
+    _INT16 WhichBBS, iTemp, Junk[2];
+    BOOL ShowedOne;
+    long AfterOffset, BeforeOffset;
+    FILE *fpBackup;
+
+
+    WhichBBS = Result->BBSIDTo-1;
+
+    switch (Result->AttackerType)
+    {
+      case EO_VILLAGE :
+        // update attack's army
+        Village.Data->Empire.Army.Footmen += Result->ReturningArmy.Footmen;
+        Village.Data->Empire.Army.Axemen  += Result->ReturningArmy.Axemen;
+        Village.Data->Empire.Army.Knights += Result->ReturningArmy.Knights;
+
+        // give attacker his land
+        Village.Data->Empire.Land         += Result->LandStolen;
+        Village.Data->Empire.VaultGold    += Result->GoldStolen;
+        strcpy(szAttackerName, Village.Data->szName);
+        break;
+      case EO_CLAN :
+        TmpClan = malloc(sizeof(struct clan));
+        CheckMem(TmpClan);
+        if (GetClan(Result->AttackerID, TmpClan))
+        {
+          TmpClan->Empire.Army.Footmen += Result->ReturningArmy.Footmen;
+          TmpClan->Empire.Army.Axemen  += Result->ReturningArmy.Axemen;
+          TmpClan->Empire.Army.Knights += Result->ReturningArmy.Knights;
+
+          // give attacker his land
+          TmpClan->Empire.Land     += Result->LandStolen;
+          TmpClan->Empire.VaultGold  += Result->GoldStolen;
+
+          // give points for win, take away some for loss
+          if (Result->Success)
+            PClan->Points += 50;
+          else
+            PClan->Points -= 25;
+
+          strcpy(szAttackerName, TmpClan->szName);
+
+          Clan_Update(TmpClan);
+        }
+        FreeClan(TmpClan);
+        break;
+    }
+
+    if (Result->DefenderType == EO_VILLAGE)
+      sprintf(szDefenderName, "the village of %s", Result->szDefenderName);
+    else
+      sprintf(szDefenderName, "the clan of %s", Result->szDefenderName);
+
+    // write to news
+    if (Result->NoTarget && Result->Goal == G_OUSTRULER)
+    {
+      // sprintf(szNews, ">> %s's army returns after finding no ruler to oust in %s\n",
+      sprintf(szNews, ST_WNEWS5,
+        szAttackerName, IBBS.Data->Nodes[WhichBBS].Info.pszVillageName);
+      News_AddNews(szNews);
+
+      // strcpy(szOutcome, "but found no ruler to oust!\n");
+      strcpy(szOutcome, ST_WNEWS6);
+    }
+    else if (Result->NoTarget)
+    {
+      // sprintf(szNews, ">> %s's army returns after being unable to find the clan empire.\n",
+      sprintf(szNews, ST_WNEWS7, szAttackerName);
+      News_AddNews(szNews);
+
+      // strcpy(szOutcome, "but found no empire!\n");
+      strcpy(szOutcome, ST_WNEWS8);
+    }
+    else if (Result->Success)
+    {
+      // strcpy(szOutcome, "and came out victorious!\n");
+      strcpy(szOutcome, ST_WNEWS9);
+
+      switch(Result->Goal)
+      {
+        case G_OUSTRULER :
+          // sprintf(szNews, ">> %s's army returns after successfully ousting the ruler of %s\n\n",
+          sprintf(szNews, ST_WNEWS10,
+            szAttackerName, IBBS.Data->Nodes[WhichBBS].Info.pszVillageName);
+          News_AddNews(szNews);
+          break;
+        case G_STEALLAND :
+          // sprintf(szNews, ">> %s's army returns successfully from %s looting %d land from %s.\n\n",
+          sprintf(szNews, ST_WNEWS11,
+            szAttackerName,
+                      IBBS.Data->Nodes[WhichBBS].Info.pszVillageName,
+                      Result->LandStolen, szDefenderName);
+          News_AddNews(szNews);
+          break;
+        case G_STEALGOLD :
+          // sprintf(szNews, ">> %s's army returns successfully from %s looting %d gold from %s.\n\n",
+          sprintf(szNews, ST_WNEWS12,
+                      szAttackerName,
+                      IBBS.Data->Nodes[WhichBBS].Info.pszVillageName,
+                      Result->GoldStolen, szDefenderName);
+          News_AddNews(szNews);
+          break;
+        case G_DESTROY :
+          // sprintf(szNews, ">> %s's army returns successfully from %s destroying %s's buildings.\n\n",
+          sprintf(szNews, ST_WNEWS13,
+            szAttackerName,
+            IBBS.Data->Nodes[WhichBBS].Info.pszVillageName, szDefenderName);
+          News_AddNews(szNews);
+          break;
+      }
+    }
+    else
+    {
+      // strcpy(szOutcome, "and came out defeated.\n");
+      strcpy(szOutcome, ST_WNEWS14);
+      // sprintf(szNews, ">> %s's army returns unsuccessfully from %s after attacking %s.\n\n",
+      sprintf(szNews, ST_WNEWS15,
+        szAttackerName,
+        IBBS.Data->Nodes[WhichBBS].Info.pszVillageName, szDefenderName);
+      News_AddNews(szNews);
+    }
+
+    szMessage = MakeStr(600);
+    szString  = MakeStr(255);
+
+    switch(Result->Goal)
+    {
+      case G_OUSTRULER :
+        strcpy(szGoal, "to oust the ruler");
+        break;
+      case G_STEALLAND :
+        strcpy(szGoal, "to steal land");
+        break;
+      case G_STEALGOLD :
+        strcpy(szGoal, "to steal gold");
+        break;
+      case G_DESTROY :
+        strcpy(szGoal, "to destroy");
+        break;
+    }
+
+    // sprintf(szMessage, "Results of %s's attack on %s have returned.\n Your troops attempted %s %s.\n\nYou killed the following",
+    sprintf(szMessage, ST_WNEWS16,
+      Result->AttackerType == EO_VILLAGE ? "the town" : "your clan",
+      szDefenderName, szGoal, szOutcome);
+
+    // append what was lost and who you killed
+  //    sprintf(szString, " %ld Footmen\n %ld Axemen\n %ld Knights \n",
+    sprintf(szString, ST_WAR0,
+      Result->DefendCasualties.Footmen,
+      Result->DefendCasualties.Axemen,
+      Result->DefendCasualties.Knights);
+    strcat(szMessage, szString);
+  //    sprintf(szString, "You lost the following:\n %ld Footmen\n %ld Axemen\n %ld Knights \n",
+    sprintf(szString, ST_WAR1,
+      Result->AttackCasualties.Footmen,
+      Result->AttackCasualties.Axemen,
+      Result->AttackCasualties.Knights);
+    strcat(szMessage, szString);
+
+    // sprintf(szString, "The following have returned:\n %ld Footmen\n %ld Axemen\n %ld Knights \n",
+    sprintf(szString, ST_WNEWS17,
+      Result->ReturningArmy.Footmen,
+      Result->ReturningArmy.Axemen,
+      Result->ReturningArmy.Knights);
+    strcat(szMessage, szString);
+
+    switch(Result->Goal)
+    {
+      case G_STEALLAND :
+        if (Result->LandStolen)
+        {
+          // sprintf(szString, "You stole %ld land.\n", Result->LandStolen);
+          sprintf(szString, ST_WNEWS18, Result->LandStolen);
+          strcat(szMessage, szString);
+        }
+        else if (Result->Success)
+          // strcat(szMessage, "You found no land to steal!\n");
+          strcat(szMessage, ST_WNEWS19);
+        break;
+      case G_STEALGOLD :
+        if (Result->GoldStolen)
+        {
+          // sprintf(szString, "You stole %ld gold.\n", Result->GoldStolen);
+          sprintf(szString, ST_WNEWS20, Result->GoldStolen);
+          strcat(szMessage, szString);
+        }
+        else if (Result->Success)
+          // strcat(szMessage, "You found no gold to steal!\n");
+          strcat(szMessage, ST_WNEWS21);
+        break;
+    }
+
+    ShowedOne = FALSE;
+    for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+    {
+      if (Result->BuildingsDestroyed[iTemp] == 0)
+        continue;
+
+      if (!ShowedOne)
+      {
+        // strcat(szMessage, "The following buildings were destroyed:\n");
+        strcat(szMessage, ST_PAR2);
+        ShowedOne = TRUE;
+      }
+      sprintf(szString, ST_WRESULTS10, Result->BuildingsDestroyed[iTemp],
+        BuildingType[iTemp].szName);
+      strcat(szMessage, szString);
+    }
+
+    GenericMessage(szMessage, Result->AttackerID, Junk, "", FALSE);
+
+    free(szMessage);
+    free(szString);
+
+
+    // now, wipe out that packet from backup.dat
+    fpBackup = fopen("backup.dat", "r+b");
+    if (!fpBackup)
+    {
+      return;
+    }
+
+    for (;;)
+    {
+      BeforeOffset = ftell(fpBackup);
+
+      if (EncryptRead(&Packet, sizeof(struct Packet), fpBackup, XOR_PACKET) == 0)
+        break;
+
+      AfterOffset = ftell(fpBackup);
+
+      if (Packet.Active)
+      {
+        if (Packet.PacketType == PT_ATTACK)
+        {
+          // get attackpacket
+          AttackPacket = malloc(sizeof(struct AttackPacket));
+          CheckMem(AttackPacket);
+          EncryptRead(AttackPacket, sizeof(struct AttackPacket), fpBackup, XOR_PACKET);
+
+          // if same AttackIndex, mark it off
+          if (AttackPacket->AttackIndex == Result->AttackIndex)
+          {
+            Packet.Active = FALSE;
+
+            fseek(fpBackup, BeforeOffset, SEEK_SET);
+
+            /* write it to file */
+            EncryptWrite(&Packet, sizeof(struct Packet), fpBackup, XOR_PACKET);
+          }
+          free(AttackPacket);
+        }
+
+        fseek(fpBackup, AfterOffset, SEEK_SET);
+      }
+
+      // move on
+      if (Packet.PacketLength)
+        fseek(fpBackup, Packet.PacketLength, SEEK_CUR);
+    }
+
+    fclose(fpBackup);
+
+	(void)cpBuffer;
+
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void Empire_Create ( struct empire *Empire, BOOL UserEmpire )
+  {
+    _INT16 iTemp;
+
+    if (UserEmpire && Game.Data->ClanEmpires)
+    {
+      Empire->Land = 100;
+    }
+    else
+      Empire->Land = 0;
+
+    Empire->Points = 0;
+
+    for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+      Empire->Buildings[iTemp] = 0;
+
+    Empire->WorkerEnergy = 100;
+
+    // deal with army
+    Empire->Army.Followers = 0;
+    Empire->Army.Footmen = 0;
+    Empire->Army.Axemen = 0;
+    Empire->Army.Knights = 0;
+    Empire->Army.Rating = 100;
+    Empire->Army.Level = 0;
+    Empire->SpiesToday = 0;
+    Empire->AttacksToday = 0;
+    Empire->LandDevelopedToday = 0;
+    Empire->Army.Strategy.AttackLength = 10;
+    Empire->Army.Strategy.DefendLength = 10;
+    Empire->Army.Strategy.LootLevel    = 0;
+    Empire->Army.Strategy.AttackIntensity = 50;
+    Empire->Army.Strategy.DefendIntensity = 50;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Empire_Maint ( struct empire *Empire )
+  {
+    // run "maintenance" on empire
+    char szNews[128];
+    long GoldMade;
+    _INT16 iTemp, Rating;
+
+    Empire->WorkerEnergy = 100;
+    Empire->LandDevelopedToday = 0;
+    Empire->SpiesToday = 0;
+    Empire->AttacksToday = 0;
+
+    Rating = Empire->Army.Rating;
+    Rating += (RANDOM(10) + 2*Empire->Buildings[B_GYM]);
+    if (Rating > 100)
+      Rating = 100;
+    if (Rating < 0)
+      Rating = 0;
+    Empire->Army.Rating = Rating;
+
+    // make money for empire here
+    if (Empire->OwnerType == EO_VILLAGE)
+    {
+      GoldMade = 0;
+
+      // each business makes about 1000 gold
+      for (iTemp = 0; iTemp < Empire->Buildings[B_BUSINESS]; iTemp++)
+      {
+        GoldMade += (1000 + RANDOM(500) + RANDOM(500));
+      }
+
+      // sprintf(szNews, ">> Businesses brought in %ld gold today!\n\n",
+      sprintf(szNews, ST_NEWS3, GoldMade);
+      News_AddNews(szNews);
+      Empire->VaultGold += GoldMade;
+    }
+
+  }
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 ArmySpeed( struct Army *Army )
+  {
+    _INT16 Speed, NumTroops;
+
+    NumTroops = Army->Footmen + Army->Axemen + Army->Knights;
+
+    if (NumTroops)
+      Speed = (Army->Footmen*SPD_FOOTMEN + Army->Axemen*SPD_AXEMEN
+            + Army->Knights*SPD_KNIGHTS) / NumTroops;
+    else
+      Speed = 0;
+
+    return Speed;
+  }
+
+
+  long ArmyOffense( struct Army *Army )
+  {
+    long Offense, NumTroops;
+
+    Offense = Army->Footmen*OFF_FOOTMEN + Army->Axemen*OFF_AXEMEN
+        + Army->Knights*OFF_KNIGHTS;
+
+	(void)NumTroops;
+    return Offense;
+  }
+
+
+  long ArmyDefense( struct Army *Army )
+  {
+    long Defense, NumTroops;
+
+    Defense = Army->Footmen*DEF_FOOTMEN + Army->Axemen*DEF_AXEMEN
+        + Army->Knights*DEF_KNIGHTS;
+
+	(void)NumTroops;
+    return Defense;
+  }
+
+  long ArmyVitality( struct Army *Army )
+  {
+    long Vitality, NumTroops;
+
+    Vitality = (Army->Footmen*VIT_FOOTMEN + Army->Axemen*VIT_AXEMEN
+        + Army->Knights*VIT_KNIGHTS) * 2;
+
+	(void)NumTroops;
+    return Vitality;
+  }
+
+
+  void Empire_Stats ( struct empire *Empire )
+  {
+    char szString[128];
+    _INT16 iTemp;
+    BOOL ShowedOne;
+
+    od_clr_scr();
+
+    sprintf(szString, ST_ESTATS0, Empire->szName);
+    rputs(szString);
+
+    rputs(ST_LONGDIVIDER);
+
+    sprintf(szString, ST_ESTATS1, Empire->VaultGold);
+    rputs(szString);
+    sprintf(szString, ST_ESTATS2, Empire->Land);
+    rputs(szString);
+
+    sprintf(szString, ST_ESTATS3, Empire->WorkerEnergy);
+    rputs(szString);
+
+    rputs(ST_ESTATS4);
+    sprintf(szString, ST_ESTATS5, Empire->Army.Footmen);
+    rputs(szString);
+    sprintf(szString, ST_ESTATS6, Empire->Army.Axemen);
+    rputs(szString);
+    sprintf(szString, ST_ESTATS7, Empire->Army.Knights);
+    rputs(szString);
+    sprintf(szString, ST_ESTATS8, Empire->Army.Rating);
+    rputs(szString);
+
+    // show stats
+    sprintf(szString, ST_ESTATS9, ArmySpeed(&Empire->Army));
+    rputs(szString);
+    sprintf(szString, ST_ESTATS10, ArmyVitality(&Empire->Army));
+    rputs(szString);
+    sprintf(szString, ST_ESTATS11, ArmyOffense(&Empire->Army));
+    rputs(szString);
+    sprintf(szString, ST_ESTATS12, ArmyDefense(&Empire->Army));
+    rputs(szString);
+
+    rputs(ST_ESTATS13);
+    ShowedOne = FALSE;
+    for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+    {
+      if (Empire->Buildings[iTemp])
+      {
+        ShowedOne = TRUE;
+        sprintf(szString, "  %d %s\n", Empire->Buildings[iTemp],
+          BuildingType[iTemp].szName);
+        rputs(szString);
+      }
+    }
+    if (!ShowedOne)
+      rputs(ST_ESTATS14);
+
+    rputs(ST_LONGDIVIDER);
+    door_pause();
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void DevelopLand( struct empire *Empire )
+  {
+    long LimitingVariable, CostToDevelop;
+    _INT16 LandToDevelop;
+    char szString[128];
+
+    // show help for developing land
+    if (!PClan->DevelopHelp)
+    {
+      PClan->DevelopHelp = TRUE;
+      Help("Development Help", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    // each unit of land costs this much to develop
+    CostToDevelop = (long)(100L - Empire->Buildings[B_DEVELOPERS]*5L);
+    if (CostToDevelop < 20)
+      CostToDevelop = 20;
+    // FIXME: in future have X developments as max per day?!
+
+    LimitingVariable = Empire->VaultGold/CostToDevelop;
+
+    if (LimitingVariable + Empire->Land >= 3000)
+      LimitingVariable = 3000 - Empire->Land;
+
+    if (LimitingVariable < 0)
+      LimitingVariable = 0;
+
+
+    sprintf(szString, ST_DEVLAND0, CostToDevelop);
+    rputs(szString);
+
+    LandToDevelop = GetLong(ST_DEVLAND1, 0, LimitingVariable);
+
+    if (LandToDevelop)
+    {
+      Empire->Land += LandToDevelop;
+      Empire->VaultGold -= (CostToDevelop*LandToDevelop);
+
+      sprintf(szString, ST_DEVLAND2, LandToDevelop, (CostToDevelop*LandToDevelop));
+      rputs(szString);
+
+      Empire->LandDevelopedToday += LandToDevelop;
+    }
+  }
+
+  void DonateToEmpire( struct empire *Empire )
+  {
+    char *szTheOptions[15];
+    char szString[128], szFileName[30];
+    long LimitingVariable, NumToDonate;
+    BOOL IsRuler;
+
+    LoadStrings(1450, 15, szTheOptions);
+
+    if (Empire->OwnerType == EO_VILLAGE)
+      strcpy(szFileName, "Donate To Empire1");
+    else
+      strcpy(szFileName, "Donate To Empire2");
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n");
+      rputs(" |0BDonation\n");
+      rputs(ST_LONGLINE);
+
+      IsRuler = PClan->ClanID[0] == Village.Data->RulingClanId[0] &&
+        PClan->ClanID[1] == Village.Data->RulingClanId[1];
+
+      // show empire stats
+  /*
+      if (Empire->OwnerType != EO_VILLAGE || (!IsRuler &&
+        Village.Data->ShowEmpireStats && Empire->OwnerType == EO_VILLAGE) ||
+        (Empire->OwnerType == EO_VILLAGE && IsRuler) )
+  */
+      {
+        sprintf(szString, ST_DEMPIRE0, Empire->Army.Followers);
+        rputs(szString);
+        sprintf(szString, ST_DEMPIRE1, Empire->Army.Footmen);
+        rputs(szString);
+        sprintf(szString, ST_DEMPIRE2, Empire->Army.Axemen);
+        rputs(szString);
+        sprintf(szString, ST_DEMPIRE3, Empire->Army.Knights);
+        rputs(szString);
+        sprintf(szString, ST_DEMPIRE4, Empire->VaultGold);
+        rputs(szString);
+        sprintf(szString, ST_DEMPIRE5, Empire->Land);
+        rputs(szString);
+      }
+  /*
+      else if (Empire->OwnerType == EO_VILLAGE && IsRuler == FALSE &&
+        Village.Data->ShowEmpireStats == FALSE)
+      {
+        rputs(" |0CEmpire stats made unavailable by ruler.\n");
+      }
+  */
+
+      switch(GetChoice(szFileName, ST_ENTEROPTION, szTheOptions, "12346789Q?V50AB", 'Q', TRUE))
+      {
+        case '1' :      /* followers */
+          LimitingVariable = PClan->Empire.Army.Followers;
+
+          NumToDonate = GetLong(ST_DEMPIRE6, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            Empire->Army.Followers += NumToDonate;
+            PClan->Empire.Army.Followers -= NumToDonate;
+          }
+          break;
+        case '2' :      /* footmen */
+          // first limit is number of barracks they can own
+          LimitingVariable = Empire->Buildings[B_BARRACKS]*20;
+
+          // next, subtract from this the number of troops they already own
+          LimitingVariable -= Empire->Army.Footmen;
+
+          // this leaves how many they can take in
+
+          // if you have less troops to donate than this,
+          // you can only train that many
+          if (PClan->Empire.Army.Footmen < LimitingVariable)
+            LimitingVariable = PClan->Empire.Army.Footmen;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToDonate = GetLong(ST_DEMPIRE7, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            Empire->Army.Footmen   += NumToDonate;
+            PClan->Empire.Army.Footmen -= NumToDonate;
+          }
+          break;
+        case '3' :      /* axemen */
+          if (Empire->Buildings[B_STEELMILL] == 0)
+          {
+            rputs(ST_DEMPIRE18);
+            break;
+          }
+          // first limit is number of barracks they can own
+          LimitingVariable = Empire->Buildings[B_BARRACKS]*10;
+
+          // next, subtract from this the number of troops they already own
+          LimitingVariable -= Empire->Army.Axemen;
+
+          // this leaves how many they can take in
+
+          // if you have less troops to donate than this,
+          // you can only train that many
+          if (PClan->Empire.Army.Axemen < LimitingVariable)
+            LimitingVariable = PClan->Empire.Army.Axemen;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToDonate = GetLong(ST_DEMPIRE8, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            Empire->Army.Axemen   += NumToDonate;
+            PClan->Empire.Army.Axemen -= NumToDonate;
+          }
+          break;
+        case '4' :      /* Knights */
+          if (Empire->Buildings[B_STEELMILL] == 0 ||
+            Empire->Buildings[B_STABLES] == 0)
+          {
+            rputs(ST_DEMPIRE19);
+            break;
+          }
+          // first limit is number of barracks they can own
+          LimitingVariable = Empire->Buildings[B_BARRACKS]*5;
+
+          // next, subtract from this the number of troops they already own
+          LimitingVariable -= Empire->Army.Knights;
+
+          // this leaves how many they can take in
+
+          // if you have less troops to donate than this,
+          // you can only train that many
+          if (PClan->Empire.Army.Knights < LimitingVariable)
+            LimitingVariable = PClan->Empire.Army.Knights;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToDonate = GetLong(ST_DEMPIRE9, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            Empire->Army.Knights   += NumToDonate;
+            PClan->Empire.Army.Knights -= NumToDonate;
+          }
+          break;
+        case '7' :      /* withdraw footmen */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE20);
+            break;
+          }
+
+          // first limit is number of barracks you can own
+          LimitingVariable = PClan->Empire.Buildings[B_BARRACKS]*20;
+
+          // next, subtract from this the number of troops you already own
+          LimitingVariable -= PClan->Empire.Army.Footmen;
+
+          // this leaves how many you can take in
+
+          // if they have less troops to give than this,
+          // you can only take that many
+          if (Empire->Army.Footmen < LimitingVariable)
+            LimitingVariable = Empire->Army.Footmen;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToDonate = GetLong(ST_DEMPIRE11, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.Army.Footmen += NumToDonate;
+            Empire->Army.Footmen -= NumToDonate;
+          }
+          break;
+        case '8' :      /* withdraw axemen */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE20);
+            break;
+          }
+          if (PClan->Empire.Buildings[B_STEELMILL] == 0)
+          {
+            rputs(ST_DEMPIRE21);
+            break;
+          }
+          // first limit is number of barracks you can own
+          LimitingVariable = PClan->Empire.Buildings[B_BARRACKS]*10;
+
+          // next, subtract from this the number of troops you already own
+          LimitingVariable -= PClan->Empire.Army.Axemen;
+
+          // this leaves how many you can take in
+
+          // if you have less troops to donate than this,
+          // you can only train that many
+          if (Empire->Army.Axemen < LimitingVariable)
+            LimitingVariable = Empire->Army.Axemen;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToDonate = GetLong(ST_DEMPIRE12, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.Army.Axemen   += NumToDonate;
+            Empire->Army.Axemen -= NumToDonate;
+          }
+          break;
+        case '9' :      /* withdraw Knights */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE20);
+            break;
+          }
+          if (PClan->Empire.Buildings[B_STEELMILL] == 0 ||
+            PClan->Empire.Buildings[B_STABLES] == 0)
+          {
+            rputs(ST_DEMPIRE22);
+            break;
+          }
+          // first limit is number of barracks you can own
+          LimitingVariable = PClan->Empire.Buildings[B_BARRACKS]*5;
+
+          // next, subtract from this the number of troops you already own
+          LimitingVariable -= PClan->Empire.Army.Knights;
+
+          // this leaves how many you can take in
+
+          // if you have less troops to donate than this,
+          // you can only train that many
+          if (Empire->Army.Knights < LimitingVariable)
+            LimitingVariable = Empire->Army.Knights;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToDonate = GetLong(ST_DEMPIRE13, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.Army.Knights += NumToDonate;
+            Empire->Army.Knights -= NumToDonate;
+          }
+          break;
+        case '6' :      /* followers */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE20);
+            break;
+          }
+          LimitingVariable = Empire->Army.Followers;
+
+          NumToDonate = GetLong(ST_DEMPIRE10, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.Army.Followers += NumToDonate;
+            Empire->Army.Followers -= NumToDonate;
+          }
+          break;
+        case '5' :      /* land */
+          LimitingVariable = PClan->Empire.Land;
+
+          NumToDonate = GetLong(ST_DEMPIRE14, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.Land -= NumToDonate;
+            Empire->Land += NumToDonate;
+          }
+          break;
+        case '0' :      /* take land */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE20);
+            break;
+          }
+
+          LimitingVariable = Empire->Land;
+
+          NumToDonate = GetLong(ST_DEMPIRE15, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.Land += NumToDonate;
+            Empire->Land -= NumToDonate;
+          }
+          break;
+        case 'A' :      /* give gold */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE23);
+            break;
+          }
+          LimitingVariable = PClan->Empire.VaultGold;
+
+          NumToDonate = GetLong(ST_DEMPIRE16, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.VaultGold -= NumToDonate;
+            Empire->VaultGold += NumToDonate;
+          }
+          break;
+        case 'B' :      /* take gold */
+          if (Empire->OwnerType == EO_VILLAGE)
+          {
+            rputs(ST_DEMPIRE23);
+            break;
+          }
+
+          LimitingVariable = Empire->VaultGold;
+
+          NumToDonate = GetLong(ST_DEMPIRE17, 0, LimitingVariable);
+
+          if (NumToDonate)
+          {
+            PClan->Empire.VaultGold += NumToDonate;
+            Empire->VaultGold -= NumToDonate;
+          }
+          break;
+        case 'Q' :      /* return to previous menu */
+          return;
+        case '?' :      /* redisplay options */
+          break;
+        case 'V' :      /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+      }
+    }
+  }
+
+  void Destroy_Menu ( struct empire *Empire )
+  {
+    // allow user to build new structures
+
+    _INT16 iTemp, WhichBuilding;
+    char *szTheOptions[13], cKey, szString[128];
+
+    LoadStrings(1270, 12, szTheOptions);
+    szTheOptions[11] = "Buildings";
+    szTheOptions[12] = "View Stats";
+
+    for (;;)
+    {
+      rputs("\n\n");
+      rputs(" |0BDestroy Menu\n");
+      rputs(ST_LONGLINE);
+
+      /* show stats */
+      sprintf(szString, ST_MEMPIRE11, Empire->Land);
+      rputs(szString);
+
+      // show all buildings erected
+      for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+      {
+        // sprintf(szString, " |0A(|0B%c|0A) |0C%-20s    |0F%d\n\r", iTemp + '0', BuildingType[iTemp].szName,
+        sprintf(szString, ST_MEMPIRE13, iTemp + '0', BuildingType[iTemp].szName,
+          Empire->Buildings[iTemp]);
+        rputs(szString);
+      }
+      // rputs(" |0A(|0BQ|0A) |0CQuit\n |0A(|0BV|0A) |0CView Stats\n");
+      rputs(ST_MEMPIRE27);
+      rputs(ST_LONGLINE);
+
+      switch(cKey = GetChoice("", ST_ENTEROPTION, szTheOptions, "Q?0123456789V", 'Q', TRUE))
+      {
+        // user chooses type to build here using 123456789
+        case '0' :
+        case '1' :
+        case '2' :
+        case '3' :
+        case '4' :
+        case '5' :
+        case '6' :
+        case '7' :
+        case '8' :
+        case '9' :
+          WhichBuilding = cKey - '0';
+
+          // show building stats
+          sprintf(szString, ST_MEMPIRE15, BuildingType[ WhichBuilding ].szName);
+          rputs(szString);
+          sprintf(szString, ST_MEMPIRE17, BuildingType[ WhichBuilding ].LandUsed);
+          rputs(szString);
+          sprintf(szString, ST_MEMPIRE18, BuildingType[ WhichBuilding ].Cost);
+          rputs(szString);
+
+          Help(BuildingType[ WhichBuilding ].szName, ST_WARHLP);
+
+          if (Empire->Buildings[WhichBuilding] <= 0)
+          {
+            Empire->Buildings[WhichBuilding] = 0;
+            // rputs("|07You don't have any of that building to destroy.\n%P");
+            rputs(ST_MEMPIRE29);
+            break;
+          }
+
+          // if (NoYes("Destroy this?") == NO) break;
+          if (NoYes(ST_MEMPIRE30) == NO) break;
+
+          // "destroy" it now
+          Empire->Land += BuildingType[ WhichBuilding ].LandUsed;
+          Empire->VaultGold += ((BuildingType[ WhichBuilding ].Cost*1)/2);
+          Empire->Buildings[WhichBuilding]--;
+
+          // sprintf(szString, "%s destroyed.  %d land and %d gold gained.\n",
+          sprintf(szString, ST_MEMPIRE31,
+            BuildingType[ WhichBuilding ].szName,
+            BuildingType[ WhichBuilding ].LandUsed,
+            ((BuildingType[ WhichBuilding ].Cost*1)/2));
+          rputs(szString);
+          break;
+        case 'V' :      // clan stats
+          ClanStats(PClan, TRUE);
+          break;
+        case 'Q' :      /* return to previous menu */
+          return;
+        case '?' :      /* redisplay options */
+          break;
+      }
+    }
+  }
+
+  void StructureMenu ( struct empire *Empire )
+  {
+    // allow user to build new structures
+
+    _INT16 iTemp, WhichBuilding;
+    char *szTheOptions[14], cKey, szString[128];
+
+    LoadStrings(1270, 14, szTheOptions);
+
+    for (;;)
+    {
+      rputs("\n\n");
+      rputs(" |0BBuild Menu\n");
+      rputs(ST_LONGLINE);
+
+      /* show stats */
+      sprintf(szString, ST_MEMPIRE11, Empire->Land);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE12, Empire->WorkerEnergy);
+      rputs(szString);
+
+      // show all buildings erected
+      for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+      {
+        if (iTemp == B_BUSINESS && Empire->OwnerType != EO_VILLAGE)
+          continue;
+
+        // sprintf(szString, " |0A(|0B%c|0A) |0C%-20s    |0F%d\n\r", iTemp + '0', BuildingType[iTemp].szName,
+        sprintf(szString, ST_MEMPIRE13, iTemp + '0', BuildingType[iTemp].szName,
+          Empire->Buildings[iTemp]);
+        rputs(szString);
+      }
+      // rputs(" |0A(|0BQ|0A) |0CQuit\n |0A(|0BV|0A) |0CView Stats\n");
+      rputs(ST_MEMPIRE14);
+      rputs(ST_LONGLINE);
+
+      switch(cKey = GetChoice("", ST_ENTEROPTION, szTheOptions, "Q?012345678*9V", 'Q', TRUE))
+      {
+        // user chooses type to build here using 123456789
+        case '0' :
+        case '1' :
+        case '2' :
+        case '3' :
+        case '4' :
+        case '5' :
+        case '6' :
+        case '7' :
+        case '8' :
+        case '9' :
+          WhichBuilding = cKey - '0';
+
+          if (WhichBuilding == B_BUSINESS && Empire->OwnerType != EO_VILLAGE)
+          {
+            // rputs("|07Businesses can only be built by the village.\n");
+            rputs(ST_MEMPIRE28);
+            break;
+          }
+
+          // show building stats
+          sprintf(szString, ST_MEMPIRE15, BuildingType[ WhichBuilding ].szName);
+          rputs(szString);
+          sprintf(szString, ST_MEMPIRE16, BuildingType[ WhichBuilding ].EnergyUsed);
+          rputs(szString);
+          sprintf(szString, ST_MEMPIRE17, BuildingType[ WhichBuilding ].LandUsed);
+          rputs(szString);
+          sprintf(szString, ST_MEMPIRE18, BuildingType[ WhichBuilding ].Cost);
+          rputs(szString);
+
+          Help(BuildingType[ WhichBuilding ].szName, ST_WARHLP);
+
+          // see if can't build this
+          if (BuildingType[ WhichBuilding ].LandUsed > Empire->Land)
+          {
+            // od_printf("You need more worker land.\n\r");
+            rputs(ST_MEMPIRE19);
+            break;
+          }
+          // see if can't build this
+          else if (BuildingType[ WhichBuilding ].Cost > Empire->VaultGold)
+          {
+            // od_printf("You need more gold.\n\r");
+            rputs(ST_MEMPIRE34);
+            break;
+          }
+          else if (BuildingType[ WhichBuilding ].EnergyUsed > Empire->WorkerEnergy)
+          {
+            // od_printf("You need more worker energy.\n\r");
+            rputs(ST_MEMPIRE20);
+            break;
+          }
+
+          // show stats
+          sprintf(szString, "|0CYou have |0B%ld |0Cgold, |0B%d |0Cland, |0B%d%% |0Cworker Energy\n",
+            Empire->VaultGold, Empire->Land, Empire->WorkerEnergy);
+          rputs(szString);
+
+          // if (YesNo("Build this?") == NO) break;
+          if (YesNo(ST_MEMPIRE21) == NO) break;
+
+          // "build" it now
+          Empire->Land -= BuildingType[ WhichBuilding ].LandUsed;
+          Empire->VaultGold -= BuildingType[ WhichBuilding ].Cost;
+          Empire->WorkerEnergy -= BuildingType[ WhichBuilding ].EnergyUsed;
+          Empire->Buildings[WhichBuilding]++;
+
+          // sprintf(szString, "%s built!\n\r", BuildingType[ WhichBuilding ].szName);
+          sprintf(szString, ST_MEMPIRE22, BuildingType[ WhichBuilding ].szName);
+          rputs(szString);
+          break;
+        case '*' :  // destroy buildings
+          Destroy_Menu(Empire);
+          break;
+        case 'Q' :      /* return to previous menu */
+          return;
+        case 'V' :      // clan stats
+          ClanStats(PClan, TRUE);
+          break;
+        case '?' :      /* redisplay options */
+          break;
+      }
+    }
+  }
+
+
+  void ManageArmy ( struct empire *Empire )
+  {
+    char *szTheOptions[6];
+    char szString[128];
+    long LimitingVariable, NumToTrain;
+
+    LoadStrings(360, 6, szTheOptions);
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n");
+      rputs(ST_MEMPIRE23);
+      rputs(ST_LONGLINE);
+
+      // show army stats
+      sprintf(szString, ST_ESTATS15, ArmySpeed(&Empire->Army));
+      rputs(szString);
+      sprintf(szString, ST_ESTATS16, ArmyOffense(&Empire->Army));
+      rputs(szString);
+      sprintf(szString, ST_ESTATS17, ArmyDefense(&Empire->Army));
+      rputs(szString);
+      sprintf(szString, ST_ESTATS18, ArmyVitality(&Empire->Army));
+      rputs(szString);
+
+      rputs(ST_MTROOPHEADER);
+
+      sprintf(szString, ST_MTROOPCOST1, Empire->Army.Footmen);
+      rputs(szString);
+
+      if (Empire->Buildings[B_STEELMILL])
+      {
+        sprintf(szString, ST_MTROOPCOST2, Empire->Army.Axemen);
+        rputs(szString);
+      }
+
+      if (Empire->Buildings[B_STABLES] && Empire->Buildings[B_STEELMILL])
+      {
+        sprintf(szString, ST_MTROOPCOST3, Empire->Army.Knights);
+        rputs(szString);
+      }
+
+      rputs(ST_MMENURETURN);
+
+      /* give status of troops in one line */
+      sprintf(szString, ST_MMENUTROOPSTATUS,
+        Empire->Army.Followers, Empire->VaultGold);
+      rputs(szString);
+
+      rputs(ST_LONGLINE);
+
+      switch(GetChoice("", ST_ENTEROPTION, szTheOptions, "123?QH", 'Q', TRUE))
+      {
+        case 'H' :  // general help
+          GeneralHelp(ST_ARMYHLP);
+          break;
+        case '1' :      /* footmen */
+          Help("Footmen", ST_ARMYHLP);
+
+          // first limit is number of barracks you own
+          LimitingVariable = Empire->Buildings[B_BARRACKS]*20;
+
+          // next, subtract from this the number of troops you own
+          LimitingVariable -= Empire->Army.Footmen;
+
+          // this leaves how many you can train
+
+          // if you have less gold than this, you can only train that
+          // many
+          if (Empire->VaultGold / SCOST_FOOTMAN < LimitingVariable)
+            LimitingVariable = Empire->VaultGold / SCOST_FOOTMAN;
+
+          if (Empire->Army.Followers < LimitingVariable)
+            LimitingVariable = Empire->Army.Followers;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToTrain = GetLong(ST_MMENUTRAIN1, 0, LimitingVariable);
+
+          if (NumToTrain)
+          {
+            /* tell him he trained em */
+            sprintf(szString, ST_MMENUTRAIN2, NumToTrain, NumToTrain*SCOST_FOOTMAN);
+            rputs(szString);
+
+            Empire->VaultGold -= (NumToTrain*SCOST_FOOTMAN);
+
+            Empire->Army.Footmen += NumToTrain;
+            Empire->Army.Followers -= NumToTrain;
+          }
+          break;
+        case '2' :      /* axemen */
+          if (Empire->Buildings[B_STEELMILL] == 0)
+          {
+            rputs(ST_MEMPIRE25);
+            break;
+          }
+          Help("Axemen", ST_ARMYHLP);
+
+          // first limit is number of barracks you own
+          LimitingVariable = Empire->Buildings[B_BARRACKS]*10;
+
+          // next, subtract from this the number of troops you own
+          LimitingVariable -= Empire->Army.Axemen;
+
+          // this leaves how many you can train
+
+          // if you have less gold than this, you can only train that
+          // many
+          if (Empire->VaultGold / SCOST_AXEMEN < LimitingVariable)
+            LimitingVariable = Empire->VaultGold / SCOST_AXEMEN;
+
+          if (Empire->Army.Followers < LimitingVariable)
+            LimitingVariable = Empire->Army.Followers;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToTrain = GetLong(ST_MMENUTRAIN3, 0, LimitingVariable);
+
+          if (NumToTrain)
+          {
+            sprintf(szString, ST_MMENUTRAIN4, NumToTrain, NumToTrain*SCOST_AXEMEN);
+            rputs(szString);
+
+            Empire->VaultGold -= (NumToTrain*SCOST_AXEMEN);
+
+            Empire->Army.Axemen += NumToTrain;
+            Empire->Army.Followers -= NumToTrain;
+          }
+          break;
+        case '3' :      /* Knights */
+          if (Empire->Buildings[B_STEELMILL] == 0 ||
+            Empire->Buildings[B_STABLES] == 0)
+          {
+            rputs(ST_MEMPIRE26);
+            break;
+          }
+          Help("Knights", ST_ARMYHLP);
+
+          // first limit is number of barracks you own
+          LimitingVariable = Empire->Buildings[B_BARRACKS]*5;
+
+          // next, subtract from this the number of troops you own
+          LimitingVariable -= Empire->Army.Knights;
+
+          // this leaves how many you can train
+
+          // if you have less gold than this, you can only train that
+          // many
+          if (Empire->VaultGold / SCOST_KNIGHT < LimitingVariable)
+            LimitingVariable = Empire->VaultGold / SCOST_KNIGHT;
+
+          if (Empire->Army.Followers < LimitingVariable)
+            LimitingVariable = Empire->Army.Followers;
+
+          // if less than 0, make it 0
+          if (LimitingVariable < 0)
+            LimitingVariable = 0;
+
+          NumToTrain = GetLong(ST_MMENUTRAIN5, 0, LimitingVariable);
+
+          if (NumToTrain)
+          {
+            sprintf(szString, ST_MMENUTRAIN6, NumToTrain, NumToTrain*SCOST_KNIGHT);
+            rputs(szString);
+
+            Empire->VaultGold -= (NumToTrain*SCOST_KNIGHT);
+
+            Empire->Army.Knights += NumToTrain;
+            Empire->Army.Followers -= NumToTrain;
+          }
+          break;
+        case 'Q' :      /* return to previous menu */
+          return;
+        case '?' :      /* redisplay options */
+          break;
+      }
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+  void ArmyAttack( struct Army *Attacker, struct Army *Defender,
+    struct AttackResult *Result )
+  {
+    _INT16 NumRounds, CurRound;
+    struct Army OrigAttacker, OrigDefender;
+    _INT16 AttackerSpeed, DefenderSpeed;
+    long AttackerOffense, DefenderOffense;
+    long AttackerDefense, DefenderDefense;
+    long AttackerVitality, DefenderVitality;
+    long Damage, Percent;
+    _INT16 Intensity, AttackerLoss, DefenderLoss;
+
+    // Initialize result now
+    Result->Success = FALSE;
+    Result->NoTarget = FALSE;
+    Result->PercentDamage = 0;
+
+    NumRounds = (Attacker->Strategy.AttackLength +
+      Defender->Strategy.DefendLength) / 2;
+
+    Intensity = (Attacker->Strategy.AttackIntensity + Defender->Strategy.DefendIntensity)/2;
+  //    od_printf("Intensity of battle is %d\n", Intensity);
+
+    // save original values
+    OrigAttacker = *Attacker;
+    OrigDefender = *Defender;
+
+    // figure out speeds
+    AttackerSpeed = ArmySpeed(Attacker);
+    DefenderSpeed = ArmySpeed(Defender);
+
+    // figure out offense
+    AttackerOffense = (ArmyOffense(Attacker)*AttackerSpeed*Attacker->Rating)/100;
+    DefenderOffense = (ArmyOffense(Defender)*DefenderSpeed*Defender->Rating)/100;
+
+    // figure out defense
+    AttackerDefense = (ArmyDefense(Attacker)*AttackerSpeed*Attacker->Rating)/100;
+    DefenderDefense = (ArmyDefense(Defender)*DefenderSpeed*Defender->Rating)/100;
+
+    // figure out vitality
+    AttackerVitality = ArmyVitality(Attacker);
+    DefenderVitality = ArmyVitality(Defender);
+
+    /*
+    od_printf("Attacker:\n %ld Offense\n %ld Defense\n %d speed \n %ld Vitality\n",
+      AttackerOffense, AttackerDefense, AttackerSpeed, AttackerVitality);
+    od_printf("Defender:\n %ld Offense\n %ld Defense\n %d speed \n %ld Vitality\n",
+      DefenderOffense, DefenderDefense, DefenderSpeed, DefenderVitality);
+    */
+
+    // if attacker has no energy to begin with, defender wins battle
+    if (AttackerVitality == 0)
+    {
+      //DisplayStr("You have no energy\n");
+      Result->PercentDamage = 0;
+      return;
+    }
+
+
+    // if no energy to begin with, attacker wins battle
+    if (DefenderVitality == 0)
+    {
+      //DisplayStr("Enemy has no energy\n");
+      Result->PercentDamage = 100;
+      Result->Success = TRUE;
+      return;
+    }
+
+    // go through rounds
+    for (CurRound = 0; CurRound < NumRounds; CurRound++)
+    {
+      // figure out damage to defender
+      Damage = ((AttackerOffense - DefenderDefense)*Intensity) / (DAMAGE_FACTOR*100);
+      if (Damage < 0)
+        Damage = 0;
+
+      DefenderVitality -= Damage;
+      if (DefenderVitality < 0)
+        DefenderVitality = 0;
+
+      // figure out damage to attacker
+      Damage = ((DefenderOffense - AttackerDefense)*Intensity) / (DAMAGE_FACTOR*100);
+      if (Damage < 0)
+        Damage = 0;
+
+      AttackerVitality -= Damage;
+      if (AttackerVitality < 0)
+        AttackerVitality = 0;
+
+
+      // figure out # of troops left after attack
+      Percent = (AttackerVitality*100)/ArmyVitality(&OrigAttacker);
+      Attacker->Footmen = (Percent*OrigAttacker.Footmen)/100;
+      Attacker->Axemen = (Percent*OrigAttacker.Axemen)/100;
+      Attacker->Knights = (Percent*OrigAttacker.Knights)/100;
+
+      Percent = (DefenderVitality*100)/ArmyVitality(&OrigDefender);
+      Defender->Footmen = (Percent*OrigDefender.Footmen)/100;
+      Defender->Axemen = (Percent*OrigDefender.Axemen)/100;
+      Defender->Knights = (Percent*OrigDefender.Knights)/100;
+
+      // *** Calculate stats for next round
+
+      // figure out speeds
+      AttackerSpeed = ArmySpeed(Attacker);
+      DefenderSpeed = ArmySpeed(Defender);
+
+      // figure out offense
+      AttackerOffense = (ArmyOffense(Attacker)*AttackerSpeed*Attacker->Rating)/100;
+      DefenderOffense = (ArmyOffense(Defender)*DefenderSpeed*Defender->Rating)/100;
+
+      // figure out defense
+      AttackerDefense = (ArmyDefense(Attacker)*AttackerSpeed*Attacker->Rating)/100;
+      DefenderDefense = (ArmyDefense(Defender)*DefenderSpeed*Defender->Rating)/100;
+
+      // figure out vitality
+      AttackerVitality = ArmyVitality(Attacker);
+      DefenderVitality = ArmyVitality(Defender);
+
+      // if either side has no energy, break
+      if (DefenderVitality == 0 || AttackerVitality == 0)
+      {
+        break;
+      }
+    }
+
+    // figure out percent damage done to each side
+    AttackerLoss = 100 - (ArmyVitality(Attacker)*100)/ArmyVitality(&OrigAttacker);
+    DefenderLoss = 100 - (ArmyVitality(Defender)*100)/ArmyVitality(&OrigDefender);
+
+  //    od_printf("Attacker's loss = %d\n\rDefender's Loss = %d\n\r", AttackerLoss, DefenderLoss);
+
+    Result->PercentDamage = DefenderLoss;
+
+    Result->AttackCasualties.Footmen += (OrigAttacker.Footmen - Attacker->Footmen);
+    Result->AttackCasualties.Axemen += (OrigAttacker.Axemen - Attacker->Axemen);
+    Result->AttackCasualties.Knights += (OrigAttacker.Knights - Attacker->Knights);
+
+    Result->DefendCasualties.Footmen += (OrigDefender.Footmen - Defender->Footmen);
+    Result->DefendCasualties.Axemen += (OrigDefender.Axemen - Defender->Axemen);
+    Result->DefendCasualties.Knights += (OrigDefender.Knights - Defender->Knights);
+
+    // if attacker's loss < defender's loss and defender's loss >= 50%,
+    // attacker won!
+    if (AttackerLoss < DefenderLoss && DefenderLoss >= 30)
+      Result->Success = TRUE;
+    else
+      Result->Success = FALSE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void EmpireAttack ( struct empire *AttackingEmpire, struct Army *AttackingArmy,
+    struct empire *DefendingEmpire, struct AttackResult *Result,
+    _INT16 Goal, _INT16 ExtentOfAttack)
+  {
+    struct Army DefendingArmy, ArmyKilledByTowers, ArmyStoppedByWalls;
+    _INT16 iTemp;
+
+    // ExtentOfAttack is used for stealing land, gold, and destroying
+    // it is the percentage of the attack (10-30% usually)
+
+    // intialize result
+    Result->Success = FALSE;
+    Result->NoTarget= FALSE;
+
+    Result->ReturningArmy = *AttackingArmy;
+    Result->AttackerType = AttackingEmpire->OwnerType;
+    Result->AttackCasualties.Footmen = 0;
+    Result->AttackCasualties.Axemen  = 0;
+    Result->AttackCasualties.Knights = 0;
+    Result->DefendCasualties.Footmen = 0;
+    Result->DefendCasualties.Axemen  = 0;
+    Result->DefendCasualties.Knights = 0;
+    strcpy(Result->szAttackerName, AttackingEmpire->szName);
+
+    for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+      Result->BuildingsDestroyed[iTemp] = 0;
+
+    Result->Goal = Goal;
+    Result->ExtentOfAttack = ExtentOfAttack;
+    Result->GoldStolen = 0;
+    Result->LandStolen = 0;
+
+    DefendingArmy.Strategy = DefendingEmpire->Army.Strategy;
+    DefendingArmy.Rating = DefendingEmpire->Army.Rating;
+
+    // amass correct number of troops
+    switch(Goal)
+    {
+      case G_OUSTRULER :    // oust the ruler, 60% of troops help out
+        DefendingArmy.Footmen = (DefendingEmpire->Army.Footmen*3)/5;
+        DefendingArmy.Axemen = (DefendingEmpire->Army.Axemen*3)/5;
+        DefendingArmy.Knights = (DefendingEmpire->Army.Knights*3)/5;
+        break;
+      case G_STEALLAND :    // steal land
+        // use 40% of troops + ExtentOfAttack, so 50% if getting 10% of land
+        DefendingArmy.Footmen =
+          (DefendingEmpire->Army.Footmen*(70+ExtentOfAttack))/100;
+        DefendingArmy.Axemen =
+          (DefendingEmpire->Army.Axemen*(70+ExtentOfAttack))/100;
+        DefendingArmy.Knights =
+          (DefendingEmpire->Army.Knights*(70+ExtentOfAttack))/100;
+        break;
+      case G_STEALGOLD :  // steal gold
+
+        // use 20% of troops + ExtentOfAttack (5-20% of treasury)
+        DefendingArmy.Footmen =
+          (DefendingEmpire->Army.Footmen*(80+ExtentOfAttack))/100;
+        DefendingArmy.Axemen =
+          (DefendingEmpire->Army.Axemen*(80+ExtentOfAttack))/100;
+        DefendingArmy.Knights =
+          (DefendingEmpire->Army.Knights*(80+ExtentOfAttack))/100;
+        break;
+      case G_DESTROY :  // destroy, get 80% + extent of damage (5-15%)
+        DefendingArmy.Footmen =
+          (DefendingEmpire->Army.Footmen*(80+ExtentOfAttack))/100;
+        DefendingArmy.Axemen =
+          (DefendingEmpire->Army.Axemen*(80+ExtentOfAttack))/100;
+        DefendingArmy.Knights =
+          (DefendingEmpire->Army.Knights*(80+ExtentOfAttack))/100;
+        break;
+    }
+
+    // add on a few more troops so that we can wipe 'em all out if need be
+    DefendingArmy.Footmen += 25;
+    DefendingArmy.Axemen  += 15;
+    DefendingArmy.Knights += 10;
+
+    if (DefendingArmy.Footmen > DefendingEmpire->Army.Footmen)
+      DefendingArmy.Footmen = DefendingEmpire->Army.Footmen;
+    if (DefendingArmy.Axemen > DefendingEmpire->Army.Axemen)
+      DefendingArmy.Axemen = DefendingEmpire->Army.Axemen;
+    if (DefendingArmy.Knights > DefendingEmpire->Army.Knights)
+      DefendingArmy.Knights = DefendingEmpire->Army.Knights;
+
+
+    // use walls here in future to prevent some of the troops from entering
+    ArmyStoppedByWalls.Footmen = 0;
+    ArmyStoppedByWalls.Axemen  = 0;
+    ArmyStoppedByWalls.Knights = 0;
+    for (iTemp = 0; iTemp < DefendingEmpire->Buildings[B_WALL]; iTemp++)
+    {
+          ArmyStoppedByWalls.Footmen += RANDOM(2);
+          ArmyStoppedByWalls.Axemen  += RANDOM(2);
+    }
+    if (ArmyStoppedByWalls.Footmen > AttackingArmy->Footmen)
+      ArmyStoppedByWalls.Footmen = AttackingArmy->Footmen;
+    if (ArmyStoppedByWalls.Axemen > AttackingArmy->Axemen)
+      ArmyStoppedByWalls.Axemen = AttackingArmy->Axemen;
+    if (ArmyStoppedByWalls.Knights > AttackingArmy->Knights)
+      ArmyStoppedByWalls.Knights = AttackingArmy->Knights;
+
+    Result->ReturningArmy.Footmen = ArmyStoppedByWalls.Footmen;
+    Result->ReturningArmy.Axemen  = ArmyStoppedByWalls.Axemen;
+    Result->ReturningArmy.Knights = ArmyStoppedByWalls.Knights;
+    AttackingArmy->Footmen -= ArmyStoppedByWalls.Footmen;
+    AttackingArmy->Axemen  -= ArmyStoppedByWalls.Axemen;
+    AttackingArmy->Knights -= ArmyStoppedByWalls.Knights;
+
+    // use towers here in future to attack some of the troops
+    // use ArmyKilledByTowers, then add this to the Result->AttackCasualties
+    // later
+    // make sure you reduce AttackingArmy with ArmyKilled...
+    ArmyKilledByTowers.Footmen = 0;
+    ArmyKilledByTowers.Axemen  = 0;
+    ArmyKilledByTowers.Knights = 0;
+    for (iTemp = 0; iTemp < DefendingEmpire->Buildings[B_TOWER]; iTemp++)
+    {
+      ArmyKilledByTowers.Footmen += RANDOM(3);
+      ArmyKilledByTowers.Axemen  += RANDOM(3);
+      ArmyKilledByTowers.Knights += RANDOM(2);
+    }
+    if (ArmyKilledByTowers.Footmen > AttackingArmy->Footmen)
+      ArmyKilledByTowers.Footmen = AttackingArmy->Footmen;
+    if (ArmyKilledByTowers.Axemen > AttackingArmy->Axemen)
+      ArmyKilledByTowers.Axemen = AttackingArmy->Axemen;
+    if (ArmyKilledByTowers.Knights > AttackingArmy->Knights)
+      ArmyKilledByTowers.Knights = AttackingArmy->Knights;
+
+    Result->AttackCasualties.Footmen += ArmyKilledByTowers.Footmen;
+    Result->AttackCasualties.Axemen  += ArmyKilledByTowers.Axemen;
+    Result->AttackCasualties.Knights += ArmyKilledByTowers.Knights;
+    AttackingArmy->Footmen -= ArmyKilledByTowers.Footmen;
+    AttackingArmy->Axemen  -= ArmyKilledByTowers.Axemen;
+    AttackingArmy->Knights -= ArmyKilledByTowers.Knights;
+
+    // attack now
+    ArmyAttack( AttackingArmy, &DefendingArmy, Result);
+
+    // returning army
+    Result->ReturningArmy.Footmen += AttackingArmy->Footmen;
+    Result->ReturningArmy.Axemen  += AttackingArmy->Axemen;
+    Result->ReturningArmy.Knights += AttackingArmy->Knights;
+
+  /*    // don't print results
+    od_printf("Your losses: %ld footmen, %ld axemen, %ld knights\n\r",
+      Result.AttackCasualties.Footmen, Result.AttackCasualties.Axemen, Result.AttackCasualties.Knights);
+    od_printf("His losses: %ld footmen, %ld axemen, %ld knights\n\r",
+      Result.DefendCasualties.Footmen, Result.DefendCasualties.Axemen, Result.DefendCasualties.Knights);
+  */
+  }
+
+
+
+
+  // according to result, do something
+  void ProcessAttackResult ( struct AttackResult *AttackResult )
+  {
+    char szNews[128], *szMessage, szString[255],
+    szDefenderType[40], szAttacker[40], szDefender[40];
+    _INT16 WhichBBS = 0, iTemp, Junk[2];  // <<-- Junk[] is used as dummy
+    _INT16 Percent, WhichAlliance, LandGained;
+    struct clan *TmpClan;
+    struct Alliance *Alliances[MAX_ALLIANCES];
+    BOOL ShowedOne;
+
+    // function will update defender's empire but NOT the attacker's
+
+
+    if (Game.Data->InterBBS)
+      for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+      {
+        if (IBBS.Data->Nodes[iTemp].Active == FALSE) continue;
+
+        if (iTemp+1 == AttackResult->BBSIDFrom)
+        {
+          WhichBBS = iTemp+1;
+          break;
+        }
+      }
+    else
+      WhichBBS = 1;
+
+    if (AttackResult->DefenderType == EO_VILLAGE)
+      strcpy(szDefenderType, "village");
+    else if (AttackResult->DefenderType == EO_ALLIANCE)
+      strcpy(szDefenderType, "alliance");
+    else if (AttackResult->DefenderType == EO_CLAN)
+      strcpy(szDefenderType, "clan");
+
+    if (AttackResult->InterBBS)
+    {
+      if (AttackResult->AttackerType == EO_VILLAGE)
+        sprintf(szAttacker, "The village of %s", AttackResult->szAttackerName);
+      else if (AttackResult->AttackerType == EO_CLAN)
+        sprintf(szAttacker, "The clan of %s from %s", AttackResult->szAttackerName,
+          IBBS.Data->Nodes[WhichBBS-1].Info.pszVillageName);
+    }
+    else
+    {
+      if (AttackResult->AttackerType == EO_VILLAGE)
+        strcpy(szAttacker, "The village");
+      else if (AttackResult->AttackerType == EO_CLAN)
+        sprintf(szAttacker, "%s", AttackResult->szAttackerName);
+      else if (AttackResult->AttackerType == EO_ALLIANCE)
+         sprintf(szAttacker, "The alliance of %s", AttackResult->szAttackerName);
+    }
+    switch (AttackResult->DefenderType)
+    {
+      case EO_VILLAGE :
+        strcpy(szDefender, "our village");
+        break;
+      case EO_CLAN :
+        GetClanNameID(szDefender, AttackResult->DefenderID);
+        break;
+      case EO_ALLIANCE :
+        GetAlliances(Alliances);
+        // figure out which one is the defender
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+        {
+          if (Alliances[iTemp] == NULL) break;
+          if (Alliances[iTemp]->ID == AttackResult->AllianceID)
+            break;
+        }
+        WhichAlliance = iTemp;
+        sprintf(szDefender, "the alliance of %s", Alliances[iTemp]->szName);
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+        break;
+    }
+
+    // start off news reel
+    // sprintf(szNews, ">> %s attacked %s and %s!\n   ", szAttacker, szDefender,
+    sprintf(szNews, ST_WNEWS0, szAttacker, szDefender,
+      AttackResult->Success ? "won" : "lost");
+
+    // add on the type of attack
+    switch (AttackResult->Goal)
+    {
+      case G_OUSTRULER :
+        if (AttackResult->Success)
+          // strcat(szNews, "They ousted our rulers!\n  ");
+          strcat(szNews, ST_WNEWS1);
+        break;
+      case G_STEALLAND :
+        if (AttackResult->Success && AttackResult->LandStolen)
+          // strcat(szNews, "They looted land.\n  ");
+          strcat(szNews, ST_WNEWS2);
+        break;
+      case G_STEALGOLD :
+        if (AttackResult->Success && AttackResult->GoldStolen)
+          // strcat(szNews, "They looted some gold.\n  ");
+          strcat(szNews, ST_WNEWS3);
+        break;
+      case G_DESTROY :
+        if (AttackResult->Success)
+          // strcat(szNews, "They caused much damage.\n  ");
+          strcat(szNews, ST_WNEWS4);
+        break;
+    }
+
+    szMessage = MakeStr(600);
+
+    // start message off
+    // sprintf(szMessage, "%s attacked your %s's empire!\nYour army defeated the following:\n",
+    sprintf(szMessage, ST_PAR0, szAttacker, szDefender);
+
+    // append what was lost and who you killed
+  //    sprintf(szString, " %ld Footmen\n %ld Axemen\n %ld Knights \n",
+    sprintf(szString, ST_WAR0,
+      AttackResult->AttackCasualties.Footmen,
+      AttackResult->AttackCasualties.Axemen,
+      AttackResult->AttackCasualties.Knights);
+    strcat(szMessage, szString);
+  //    sprintf(szString, "You lost the following:\n %ld Footmen\n %ld Axemen\n %ld Knights \n",
+      sprintf(szString, ST_WAR1,
+      AttackResult->DefendCasualties.Footmen,
+      AttackResult->DefendCasualties.Axemen,
+      AttackResult->DefendCasualties.Knights);
+    strcat(szMessage, szString);
+
+    // finally find out what was lost in terms of stuff
+    if (AttackResult->Success)
+    {
+      switch(AttackResult->Goal)
+      {
+        case G_OUSTRULER :  // ruler ousted!
+          // strcat(szMessage, " You were ousted from rule!\n");
+          strcat(szMessage, ST_PAR1);
+
+          // oust the ruler
+          Village.Data->RulingClanId[0] = -1;
+          Village.Data->RulingClanId[1] = -1;
+          Village.Data->szRulingClan[0] = 0;
+          Village.Data->GovtSystem = GS_DEMOCRACY;
+          Village.Data->RulingDays = 0;
+          break;
+        case G_STEALLAND :  // steal land, figure out how much land stolen
+          // tell him in message how much was lost
+          // half as much damage as regular attack
+
+          switch (AttackResult->DefenderType)
+          {
+            case EO_VILLAGE :
+              Percent = (AttackResult->PercentDamage*AttackResult->ExtentOfAttack)/200L;
+                          DestroyBuildings(Village.Data->Empire.Buildings,
+                AttackResult->BuildingsDestroyed, Percent, &LandGained);
+              // after destroying everything, Land is gained
+
+              AttackResult->LandStolen = ((Village.Data->Empire.Land + LandGained)*Percent)/100L;
+              break;
+            case EO_CLAN :
+              TmpClan = malloc(sizeof(struct clan));
+              CheckMem(TmpClan);
+              GetClan(AttackResult->DefenderID, TmpClan);
+              Percent = (AttackResult->PercentDamage*AttackResult->ExtentOfAttack)/200L;
+              DestroyBuildings(TmpClan->Empire.Buildings,
+                AttackResult->BuildingsDestroyed, Percent, &LandGained);
+
+              AttackResult->LandStolen = ((TmpClan->Empire.Land + LandGained)*Percent)/100L;
+              FreeClan(TmpClan);
+              break;
+            case EO_ALLIANCE :
+              GetAlliances(Alliances);
+              // figure out which one is the defender
+              for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+              {
+                if (Alliances[iTemp] == NULL) break;
+                if (Alliances[iTemp]->ID == AttackResult->AllianceID)
+                  break;
+              }
+              WhichAlliance = iTemp;
+
+              Percent = (AttackResult->PercentDamage*AttackResult->ExtentOfAttack)/200L;
+              DestroyBuildings(Alliances[WhichAlliance]->Empire.Buildings,
+                AttackResult->BuildingsDestroyed, Percent, &LandGained);
+
+              AttackResult->LandStolen = ((Alliances[WhichAlliance]->Empire.Land + LandGained)*Percent)/100L;
+
+              // free up mem used by alliances
+              for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+                if (Alliances[iTemp])
+                  free(Alliances[iTemp]);
+              break;
+          }
+          ShowedOne = FALSE;
+          for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+          {
+            if (AttackResult->BuildingsDestroyed[iTemp] == 0)
+              continue;
+
+            if (!ShowedOne)
+            {
+              // strcat(szMessage, "The following buildings were destroyed:\n");
+              strcat(szMessage, ST_PAR2);
+              ShowedOne = TRUE;
+            }
+            sprintf(szString, ST_WRESULTS10, AttackResult->BuildingsDestroyed[iTemp],
+              BuildingType[iTemp].szName);
+            strcat(szMessage, szString);
+          }
+          // sprintf(szString, " They stole %d land!\n", AttackResult->LandStolen);
+          if (AttackResult->LandStolen)
+          {
+            sprintf(szString, ST_PAR3, AttackResult->LandStolen);
+            strcat(szMessage, szString);
+          }
+          break;
+        case G_STEALGOLD :  // steal gold, do some stuff here later, for now, get 3%
+          switch (AttackResult->DefenderType)
+          {
+            case EO_VILLAGE :
+              AttackResult->GoldStolen =
+                              ((Village.Data->Empire.VaultGold/100L) * ((long)AttackResult->PercentDamage * (long)AttackResult->ExtentOfAttack)/100L);
+              break;
+            case EO_CLAN :
+              TmpClan = malloc(sizeof(struct clan));
+              CheckMem(TmpClan);
+              GetClan(AttackResult->DefenderID, TmpClan);
+              AttackResult->GoldStolen =
+                              ((TmpClan->Empire.VaultGold/100L) * ((long)AttackResult->PercentDamage * (long)AttackResult->ExtentOfAttack)/100L);
+              FreeClan(TmpClan);
+              break;
+            case EO_ALLIANCE :
+              GetAlliances(Alliances);
+              // figure out which one is the defender
+              for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+              {
+                if (Alliances[iTemp] == NULL) break;
+                if (Alliances[iTemp]->ID == AttackResult->AllianceID)
+                  break;
+              }
+              WhichAlliance = iTemp;
+
+              AttackResult->GoldStolen =
+                              ((Alliances[WhichAlliance]->Empire.VaultGold/100L) * ((long)AttackResult->PercentDamage * (long)AttackResult->ExtentOfAttack)/100L);
+
+              // free up mem used by alliances
+              for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+                if (Alliances[iTemp])
+                  free(Alliances[iTemp]);
+              break;
+          }
+          // sprintf(szString, " They stole %ld gold!\n", AttackResult->GoldStolen);
+          if (AttackResult->GoldStolen)
+          {
+            sprintf(szString, ST_PAR4, AttackResult->GoldStolen);
+            strcat(szMessage, szString);
+          }
+          break;
+        case G_DESTROY :  // destroy, figure out how much of his stuff was destroyed
+          switch (AttackResult->DefenderType)
+          {
+            case EO_VILLAGE :
+              Percent = (AttackResult->PercentDamage*AttackResult->ExtentOfAttack)/100L;
+              DestroyBuildings(Village.Data->Empire.Buildings,
+                AttackResult->BuildingsDestroyed, Percent, &LandGained);
+              break;
+            case EO_CLAN :
+              TmpClan = malloc(sizeof(struct clan));
+              CheckMem(TmpClan);
+              GetClan(AttackResult->DefenderID, TmpClan);
+              Percent = (AttackResult->PercentDamage*AttackResult->ExtentOfAttack)/100L;
+                          DestroyBuildings(TmpClan->Empire.Buildings,
+                AttackResult->BuildingsDestroyed, Percent, &LandGained);
+              FreeClan(TmpClan);
+              break;
+            case EO_ALLIANCE :
+              GetAlliances(Alliances);
+              // figure out which one is the defender
+              for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+              {
+                if (Alliances[iTemp] == NULL) break;
+                if (Alliances[iTemp]->ID == AttackResult->AllianceID)
+                  break;
+              }
+              WhichAlliance = iTemp;
+
+              Percent = (AttackResult->PercentDamage*AttackResult->ExtentOfAttack)/100L;
+              DestroyBuildings(Alliances[WhichAlliance]->Empire.Buildings,
+                AttackResult->BuildingsDestroyed, Percent, &LandGained);
+
+              // free up mem used by alliances
+              for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+                if (Alliances[iTemp])
+                  free(Alliances[iTemp]);
+              break;
+          }
+          // tell what they lost
+          // what destroyed
+          ShowedOne = FALSE;
+          for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+          {
+            if (AttackResult->BuildingsDestroyed[iTemp] == 0)
+              continue;
+
+            if (!ShowedOne)
+            {
+  //              strcat(szMessage, "The following buildings were destroyed:\n");
+              strcat(szMessage, ST_PAR2);
+              ShowedOne = TRUE;
+            }
+            sprintf(szString, ST_WRESULTS10, AttackResult->BuildingsDestroyed[iTemp],
+              BuildingType[iTemp].szName);
+            strcat(szMessage, szString);
+          }
+          break;
+      }
+    }
+
+    GenericMessage(szMessage, AttackResult->DefenderID, Junk, AttackResult->szAttackerName, FALSE);
+    News_AddNews(szNews);
+    News_AddNews("\n");
+
+    free(szMessage);
+  }
+
+  void DestroyBuildings ( _INT16 NumBuildings[MAX_BUILDINGS],
+    _INT16 NumDestroyed[MAX_BUILDINGS], _INT16 Percent, _INT16 *LandGained )
+  {
+    _INT16 LandUsed[MAX_BUILDINGS];
+    _INT16 NumRemaining[MAX_BUILDINGS];
+    char *WarZone;
+    _INT16 CurChar, CurType, CurBuilding, Start, End, DidHit, TotalEnergy,
+      CurHit, WhichToHit, NumFound, TypeToHit, iTemp;
+    long NumHits;
+
+  //    od_printf("\r\nBefore:  %d towers\r\n %d barracks\r\n %d walls\r\n",
+  //      NumBuildings[0], NumBuildings[1], NumBuildings[2]);
+
+    // initialize how many destroyed
+    for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+    {
+      NumDestroyed[iTemp] = 0;
+      NumRemaining[iTemp] = 0;
+    }
+
+    // figure out how much mem this takes
+    CurChar = 0;
+    for (CurType = 0; CurType < NUM_BUILDINGTYPES; CurType++)
+      for (CurBuilding = 0; CurBuilding < NumBuildings[CurType]; CurBuilding++)
+      {
+        // fill up with junk
+        CurChar += BuildingType[CurType].HitZones;
+      }
+
+      if (CurChar == 0)
+      {
+          // no buildings found!
+          *LandGained = 0;
+          return;
+      }
+
+    WarZone = malloc(CurChar);
+    CheckMem(WarZone);
+
+    TotalEnergy = CurChar;
+  //    od_printf("Total energy = %d\n\r", TotalEnergy);
+
+    // put buildings in there
+    CurChar = 0;
+    for (CurType = 0; CurType < NUM_BUILDINGTYPES; CurType++)
+      for (CurBuilding = 0; CurBuilding < NumBuildings[CurType]; CurBuilding++)
+      {
+        // fill up with junk
+        Start = CurChar;
+        End = CurChar + BuildingType[CurType].HitZones;
+        for (CurChar = Start; CurChar < End; CurChar++)
+          WarZone[CurChar] = CurType;
+      }
+
+    // damage them using percent
+
+    // figure out units of land each ones wastes :)
+    NumHits = 0;
+    for (CurType = 0; CurType < NUM_BUILDINGTYPES; CurType++)
+    {
+      LandUsed[CurType] = BuildingType[CurType].LandUsed*NumBuildings[CurType];
+      NumHits += LandUsed[CurType];
+    }
+    NumHits = (Percent*NumHits)/100;
+  //    od_printf("Num hits = %d\n\r", NumHits);
+
+    for (CurHit = 0; CurHit < NumHits;)
+    {
+      WhichToHit = RANDOM(TotalEnergy);
+      TypeToHit = WarZone[WhichToHit];
+
+      // do hit
+      if (LandUsed[TypeToHit] == 0)
+        continue;
+      else
+      {
+  //        od_printf("hit %d\n\r", TypeToHit);
+        LandUsed[TypeToHit]--;
+        CurHit++;
+      }
+    }
+
+    // figure out what we have left
+    for (CurType = 0; CurType < NUM_BUILDINGTYPES; CurType++)
+    {
+  //      od_printf("%d's energy: %d of %d\n\r",
+  //        CurType, LandUsed[CurType],
+  //        BuildingType[CurType].LandUsed*NumBuildings[CurType]);
+
+      NumRemaining[CurType] = LandUsed[CurType] /
+        BuildingType[CurType].LandUsed;
+
+      // round up here
+      iTemp = LandUsed[CurType] -
+          NumRemaining[CurType]*BuildingType[CurType].LandUsed;
+
+      if ( (iTemp*100)/BuildingType[CurType].LandUsed >= 50)
+      {
+        // round up
+        NumRemaining[CurType]++;
+      }
+
+      NumDestroyed[CurType] = NumBuildings[CurType] - NumRemaining[CurType];
+    }
+
+  //    od_printf("After:  %d towers\r\n %d barracks\r\n %d walls\r\n",
+  //      NumRemaining[0], NumRemaining[1], NumRemaining[2]);
+  //    door_pause();
+
+    *LandGained = 0;
+    for (CurType = 0; CurType < NUM_BUILDINGTYPES; CurType++)
+      *LandGained += (BuildingType[CurType].LandUsed*NumDestroyed[CurType]);
+
+    free(WarZone);
+	(void)DidHit;
+	(void)NumFound;
+  }
+
+  void ShowResults ( struct AttackResult *Result )
+  {
+    _INT16 iTemp;
+    BOOL ShowedOne;
+    char szString[128];
+
+    // reduce both armies
+    // sprintf(szString, "You lost %ld footmen, %ld axemen, and %ld knights\n\r",
+    sprintf(szString, ST_WRESULTS0,
+      Result->AttackCasualties.Footmen,
+      Result->AttackCasualties.Axemen,
+      Result->AttackCasualties.Knights);
+    rputs(szString);
+    // sprintf(szString, "You killed %ld footmen, %ld axemen, and %ld knights\n\r",
+    sprintf(szString, ST_WRESULTS1,
+      Result->DefendCasualties.Footmen,
+      Result->DefendCasualties.Axemen,
+      Result->DefendCasualties.Knights);
+    rputs(szString);
+
+    // if no one killed and no one lost, means unable to get through
+    if (Result->DefendCasualties.Footmen == 0 &&
+      Result->DefendCasualties.Axemen  == 0 &&
+      Result->DefendCasualties.Knights == 0 &&
+      Result->AttackCasualties.Footmen == 0 &&
+      Result->AttackCasualties.Axemen  == 0 &&
+          Result->AttackCasualties.Knights == 0 &&
+          (Result->DefendCasualties.Footmen ||
+           Result->DefendCasualties.Axemen ||
+           Result->DefendCasualties.Knights) )
+    {
+      // rputs("You were unable to penetrate their walls!\n");
+      rputs(ST_WRESULTS2);
+    }
+
+    // display results of battle to user
+    if (Result->Success)
+    {
+      // rputs("|07You came out |11victorious!\n");
+      rputs(ST_WRESULTS3);
+
+      switch(Result->Goal)
+      {
+        case G_OUSTRULER :
+          // rputs("You successfully ousted the ruler!\n\r");
+          rputs(ST_WRESULTS4);
+          break;
+        case G_STEALGOLD :
+          if (Result->GoldStolen)
+            // od_printf("You stole %ld gold\n\r", Result->GoldStolen);
+            sprintf(szString, ST_WRESULTS5, Result->GoldStolen);
+          else
+            // od_printf("You couldn't find any gold!\n\r");
+            sprintf(szString, ST_WRESULTS6);
+          rputs(szString);
+          break;
+        case G_STEALLAND :
+          if (Result->LandStolen)
+            // od_printf("You stole %d land\n\r", Result->LandStolen);
+            sprintf(szString, ST_WRESULTS7, Result->LandStolen);
+          else
+            // od_printf("You couldn't steal any land!\n\r");
+            sprintf(szString, ST_WRESULTS8);
+          rputs(szString);
+
+          // what destroyed
+          ShowedOne = FALSE;
+          for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+          {
+            if (Result->BuildingsDestroyed[iTemp] == 0)
+              continue;
+
+            if (!ShowedOne)
+            {
+              // rputs("You destroyed the following buildings:\n");
+              rputs(ST_WRESULTS9);
+              ShowedOne = TRUE;
+            }
+            // sprintf(szString, "%2d %s\n\r", Result->BuildingsDestroyed[iTemp],
+            sprintf(szString, ST_WRESULTS10, Result->BuildingsDestroyed[iTemp],
+              BuildingType[iTemp].szName);
+            rputs(szString);
+          }
+          if (!ShowedOne)
+            rputs(" No buildings were destroyed\n");
+          break;
+        case G_DESTROY :
+          // what destroyed
+          ShowedOne = FALSE;
+          for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+          {
+            if (Result->BuildingsDestroyed[iTemp] == 0)
+              continue;
+
+            if (!ShowedOne)
+            {
+              // rputs("You destroyed the following buildings:\n");
+              rputs(ST_WRESULTS11);
+              ShowedOne = TRUE;
+            }
+            // sprintf(szString, "%2d %s\n\r", Result->BuildingsDestroyed[iTemp],
+            sprintf(szString, ST_WRESULTS12, Result->BuildingsDestroyed[iTemp],
+              BuildingType[iTemp].szName);
+            rputs(szString);
+          }
+          if (!ShowedOne)
+            rputs(" No buildings were destroyed.\n");
+          break;
+      }
+    }
+    else
+    {
+      // rputs("|12You were defeated!\n");
+      rputs(ST_WRESULTS13);
+    }
+
+  }
+
+
+  // ------------------------------------------------------------------------- //
+
+  void GetNumTroops( struct Army *OriginalArmy, struct Army *AttackingArmy)
+  {
+    char szString[128], cInput;
+
+    // initialize it
+    *AttackingArmy = *OriginalArmy;
+    AttackingArmy->Footmen = 0;
+    AttackingArmy->Axemen = 0;
+    AttackingArmy->Knights = 0;
+
+    for (;;)
+    {
+      rputs(" |0BTroops To Ready for Battle\n");
+      rputs(ST_LONGLINE);
+
+      // show army stats
+      sprintf(szString, ST_ESTATS15, ArmySpeed(AttackingArmy));
+      rputs(szString);
+      sprintf(szString, ST_ESTATS16, ArmyOffense(AttackingArmy));
+      rputs(szString);
+      sprintf(szString, ST_ESTATS17, ArmyDefense(AttackingArmy));
+      rputs(szString);
+      sprintf(szString, ST_ESTATS18, ArmyVitality(AttackingArmy));
+      rputs(szString);
+
+      rputs("     |0CSoldiers    Owned  Readied\n");
+
+      // show troops currently going
+      sprintf(szString, ST_GTROOPS0,
+        OriginalArmy->Footmen, AttackingArmy->Footmen);
+      rputs(szString);
+      sprintf(szString, ST_GTROOPS1,
+        OriginalArmy->Axemen, AttackingArmy->Axemen);
+      rputs(szString);
+      sprintf(szString, ST_GTROOPS2,
+        OriginalArmy->Knights, AttackingArmy->Knights);
+      rputs(szString);
+      rputs(ST_GTROOPS3);
+      rputs(ST_LONGLINE);
+      rputs(" ");
+      rputs(ST_ENTEROPTION);
+      rputs("Done");
+
+      cInput = od_get_answer("ABC0\r\n][");
+
+      rputs("\b\b\b\b    \b\b\b\b|15");
+
+      if (cInput == '0' || cInput == '\r' || cInput == '\n')
+        break;
+
+      switch(cInput)
+      {
+        case ']' :
+          rputs("Send All\n\n");
+          AttackingArmy->Footmen = OriginalArmy->Footmen;
+          AttackingArmy->Axemen  = OriginalArmy->Axemen;
+          AttackingArmy->Knights = OriginalArmy->Knights;
+          break;
+        case '[' :
+          rputs("Send None\n\n");
+          AttackingArmy->Footmen = 0;
+          AttackingArmy->Axemen  = 0;
+          AttackingArmy->Knights = 0;
+          break;
+        case 'A' :
+          rputs("Footmen\n\n");
+          AttackingArmy->Footmen = GetLong(ST_GTROOPS4,
+            AttackingArmy->Footmen, OriginalArmy->Footmen);
+          break;
+        case 'B' :
+          rputs("Axemen\n\n");
+          AttackingArmy->Axemen= GetLong(ST_GTROOPS5,
+            AttackingArmy->Axemen, OriginalArmy->Axemen);
+          break;
+        case 'C' :
+          rputs("Knights\n\n");
+          AttackingArmy->Knights = GetLong(ST_GTROOPS6,
+            AttackingArmy->Knights, OriginalArmy->Knights);
+          break;
+      }
+      rputs("\n");
+    }
+    rputs("Done\n\n");
+
+    // later have him choose length of attack
+    AttackingArmy->Strategy = OriginalArmy->Strategy;
+  }
+
+  void StartEmpireWar ( struct empire *Empire )
+  {
+    struct Army AttackingArmy, DefendingArmy;
+    struct Alliance *Alliances[MAX_ALLIANCES];
+    struct AttackResult Result;
+    struct clan *TmpClan;
+    char *pszVillage = "1 A Village",
+       *pszAlliance = "2 An Alliance",
+       *pszClan = "3 A Clan",
+       *pszOustRuler = "0 Oust the Ruler of the Village",
+       *pszStealLand = "1 Capture Land",
+       *pszStealGold = "2 Capture Gold",
+       *pszDestroy =   "3 Destroy Buildings";
+    char *pszWhoToAttack[3], *aszVillageNames[MAX_IBBSNODES],
+      *aszAllianceNames[MAX_ALLIANCES], *apszGoals[4], szNews[128];
+    _INT16 TypeOfDefender, NumOfTypes, iTemp, NumBBSes, BBSIndex[MAX_IBBSNODES];
+    _INT16 WhichVillage, NumAlliances, WhichAlliance, NumGoals, Goal, ExtentOfAttack = 0;
+    _INT16 ClanID[2], LandGained, Decrease;
+
+    if (!PClan->WarHelp)
+    {
+      PClan->WarHelp = TRUE;
+      Help("War Help", ST_WARHLP);
+      rputs("\n%P");
+    }
+
+    // choose who to attack:
+
+    if (Game.Data->ClanEmpires == FALSE)
+    {
+      pszWhoToAttack[0] = pszVillage;
+      pszWhoToAttack[1] = pszAlliance;
+      NumOfTypes = 2;
+    }
+    else
+    {
+      pszWhoToAttack[0] = pszVillage;
+      pszWhoToAttack[1] = pszAlliance;
+      pszWhoToAttack[2] = pszClan;
+      NumOfTypes = 3;
+    }
+
+    GetStringChoice(pszWhoToAttack, NumOfTypes, ST_WEMPIRE0,
+      &TypeOfDefender, TRUE, DT_LONG, TRUE);
+
+    if (TypeOfDefender == -1)
+    {
+      rputs(ST_ABORTED);
+        return;
+    }
+
+    // if a village, choose which
+    if (TypeOfDefender == EO_VILLAGE)
+    {
+      // choose which village to attack
+      for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+      {
+        aszVillageNames[iTemp] = NULL;
+      }
+
+      // put our village in the list first IF the empire is not a village
+      if (Empire->OwnerType != EO_VILLAGE)
+      {
+        aszVillageNames[0] = Village.Data->szName;
+        // get rest of the other villages and skip ours
+        NumBBSes = 1;
+
+        if (Game.Data->InterBBS)
+          for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+          {
+            if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+              continue;
+
+            if (iTemp+1 == IBBS.Data->BBSID)
+              break;
+          }
+        else
+          iTemp = 0;
+
+        BBSIndex[0] = iTemp+1;
+      }
+      else
+        NumBBSes = 0;
+
+      if (Game.Data->InterBBS)
+        for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+        {
+          if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+            continue;
+
+          if (iTemp+1 == IBBS.Data->BBSID)
+            continue;
+
+          aszVillageNames[NumBBSes] = IBBS.Data->Nodes[iTemp].Info.pszVillageName;
+          BBSIndex[NumBBSes] = iTemp+1;
+          NumBBSes++;
+        }
+
+      // choose a village
+
+      GetStringChoice(aszVillageNames, NumBBSes, ST_WEMPIRE1,
+        &WhichVillage, TRUE, DT_WIDE, TRUE);
+
+      if (WhichVillage == -1)
+      {
+        rputs(ST_ABORTED);
+        return;
+      }
+
+      // choose number of troops
+      GetNumTroops(&Empire->Army, &AttackingArmy);
+
+      if (AttackingArmy.Footmen == 0 &&
+        AttackingArmy.Axemen  == 0 &&
+        AttackingArmy.Knights == 0)
+      {
+        rputs(ST_ABORTED);
+        return;
+      }
+
+      // choose type of attack (what is goal?)
+      // attacking village, so up to 4 goals
+      NumGoals = 4;
+      apszGoals[0] = pszOustRuler;
+      apszGoals[1] = pszStealLand;
+      apszGoals[2] = pszStealGold;
+      apszGoals[3] = pszDestroy;
+
+      // choose one, ask user if sure
+      for (;;)
+      {
+        GetStringChoice(apszGoals, NumGoals, ST_WEMPIRE2,
+          &Goal, TRUE, DT_LONG, TRUE);
+
+        if (Goal == -1)
+        {
+          // choose against it, so quit
+          rputs(ST_ABORTED);
+          return;
+        }
+
+        // ask user and show help
+        Help(apszGoals[Goal], ST_WARHLP);
+        if (YesNo(ST_WEMPIRE3) == YES)
+          break;
+      }
+
+      // in future, choose length of attack, etc.
+      switch (Goal)
+      {
+        case G_OUSTRULER :
+          ExtentOfAttack = 50;
+          break;
+        case G_STEALLAND :  // find out how much to steal
+          // ExtentOfAttack = GetLong(ST_WAR2, 5, 10);
+          ExtentOfAttack = 10;
+          if (!ExtentOfAttack)
+            return;
+          break;
+        case G_STEALGOLD :
+          // ExtentOfAttack = GetLong(ST_WAR3, 8, 15);
+          ExtentOfAttack = 15;
+          if (!ExtentOfAttack)
+            return;
+          break;
+        case G_DESTROY :
+          // ExtentOfAttack = GetLong(ST_WAR4, 5, 15);
+          ExtentOfAttack = 15;
+          if (!ExtentOfAttack)
+            return;
+          break;
+      }
+
+      // if OUR village, proceed normally in attack
+      if ( (Game.Data->InterBBS && BBSIndex[WhichVillage] == IBBS.Data->BBSID)
+        || (Game.Data->InterBBS == FALSE && WhichVillage == 0))
+      {
+        // amass village's troops corresponding to type of attack
+        // do attack now, tell user result, write changes
+
+        // rputs("Our village!\n");
+
+        // if no ruler, tell him
+        if (Village.Data->RulingClanId[0] == -1 && Goal == G_OUSTRULER)
+        {
+          // rputs("There is no ruler to oust.  The attack is aborted.\n");
+          rputs(ST_WEMPIRE4);
+          return;
+        }
+
+        // initialize result beforehand
+        Result.InterBBS = FALSE;
+        Result.DefenderType = EO_VILLAGE;
+        Result.BBSIDFrom = IBBS.Data->BBSID;
+        Result.BBSIDTo = IBBS.Data->BBSID;
+        Result.AttackerID[0] = PClan->ClanID[0];
+        Result.AttackerID[1] = PClan->ClanID[1];
+        Result.DefenderID[0] = Village.Data->RulingClanId[0];
+        Result.DefenderID[1] = Village.Data->RulingClanId[1];
+        Result.Goal = Goal;
+        Result.AllianceID = -1;
+
+        EmpireAttack (Empire, &AttackingArmy, &Village.Data->Empire, &Result, Goal, ExtentOfAttack);
+
+        // process result -- this writes messages, updates news
+        ProcessAttackResult(&Result);
+        ShowResults(&Result);
+
+        // update attacker's army
+        Empire->Army.Footmen -= Result.AttackCasualties.Footmen;
+        Empire->Army.Axemen  -= Result.AttackCasualties.Axemen;
+        Empire->Army.Knights -= Result.AttackCasualties.Knights;
+
+        // update defender's army
+        Village.Data->Empire.Army.Footmen -= Result.DefendCasualties.Footmen;
+        Village.Data->Empire.Army.Axemen  -= Result.DefendCasualties.Axemen;
+        Village.Data->Empire.Army.Knights -= Result.DefendCasualties.Knights;
+
+        // "give" the defender land from which his buildings came from
+        LandGained = 0;
+        for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+        {
+          LandGained += (Result.BuildingsDestroyed[iTemp]*BuildingType[iTemp].LandUsed);
+        }
+        Village.Data->Empire.Land += LandGained;
+
+        // update his losses
+        Village.Data->Empire.VaultGold -= Result.GoldStolen;
+        Village.Data->Empire.Land -= Result.LandStolen;
+
+        for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+        {
+          Village.Data->Empire.Buildings[iTemp]
+            -= Result.BuildingsDestroyed[iTemp];
+        }
+
+        // give attacker his land
+        Empire->Land += Result.LandStolen;
+        Empire->VaultGold += Result.GoldStolen;
+      }
+      else
+      {
+        // create a packet and send it to that village
+        ClanID[0] = -1; // both unused
+        ClanID[1] = -1;
+
+        IBBS_SendAttackPacket(Empire, &AttackingArmy, Goal,
+          ExtentOfAttack, EO_VILLAGE, ClanID, BBSIndex[WhichVillage]);
+
+        // reduce his army now
+        Empire->Army.Footmen -= AttackingArmy.Footmen;
+        Empire->Army.Axemen  -= AttackingArmy.Axemen;
+        Empire->Army.Knights -= AttackingArmy.Knights;
+
+              if (Empire->OwnerType == EO_VILLAGE)
+                  Empire->AttacksToday++;
+        return;
+      }
+    }
+    else if (TypeOfDefender == EO_ALLIANCE)
+    {
+      // get alliances and choose one
+
+      GetAlliances(Alliances);
+
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        if (Alliances[iTemp] == NULL)
+          break;
+        else
+          aszAllianceNames[iTemp] = Alliances[iTemp]->szName;
+      }
+      NumAlliances = iTemp;
+
+      if (NumAlliances == 0)
+      {
+        // rputs("No alliances found!\n");
+        rputs(ST_WEMPIRE5);
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+
+        return;
+      }
+
+      GetStringChoice(aszAllianceNames, NumAlliances, ST_WEMPIRE6,
+        &WhichAlliance, TRUE, DT_WIDE, TRUE);
+
+      if (WhichAlliance == -1)
+      {
+        rputs(ST_ABORTED);
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+
+        return;
+      }
+
+          if (stricmp(Empire->szName, Alliances[WhichAlliance]->szName) == 0)
+          {
+              rputs("You cannot attack your own alliance!\n%P");
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+
+        return;
+          }
+
+      // choose number of troops
+      GetNumTroops(&Empire->Army, &AttackingArmy);
+
+      if (AttackingArmy.Footmen == 0 &&
+        AttackingArmy.Axemen  == 0 &&
+        AttackingArmy.Knights == 0)
+      {
+        rputs(ST_ABORTED);
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+
+        return;
+      }
+
+      // choose type of attack (what is goal?)
+      NumGoals = 3;
+      apszGoals[0] = pszStealLand;
+      apszGoals[1] = pszStealGold;
+      apszGoals[2] = pszDestroy;
+
+      // choose one, ask user if sure
+      for (;;)
+      {
+        GetStringChoice(apszGoals, NumGoals, ST_WEMPIRE2,
+          &Goal, TRUE, DT_LONG, TRUE);
+
+        if (Goal == -1)
+        {
+          // choose against it, so quit
+          rputs(ST_ABORTED);
+
+          // free up mem used by alliances
+          for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+            if (Alliances[iTemp])
+              free(Alliances[iTemp]);
+
+          return;
+        }
+
+        // ask user and show help
+        Help(apszGoals[Goal], ST_WARHLP);
+        if (YesNo(ST_WEMPIRE3) == YES)
+          break;
+      }
+      Goal++;     // must add 1 since 0 is not used
+
+      // in future, choose length of attack, etc.
+      switch (Goal)
+      {
+        case G_STEALLAND :  // find out how much to steal
+          ExtentOfAttack = 10;
+          // ExtentOfAttack = GetLong(ST_WAR2, 5, 10);
+          if (!ExtentOfAttack)
+          {
+            // free up mem used by alliances
+            for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+              if (Alliances[iTemp])
+                free(Alliances[iTemp]);
+            return;
+          }
+          break;
+        case G_STEALGOLD :
+          // ExtentOfAttack = GetLong(ST_WAR3, 8, 15);
+          ExtentOfAttack = 15;
+          if (!ExtentOfAttack)
+          {
+            // free up mem used by alliances
+            for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+              if (Alliances[iTemp])
+                free(Alliances[iTemp]);
+            return;
+          }
+          break;
+        case G_DESTROY :
+          // ExtentOfAttack = GetLong(ST_WAR4, 5, 15);
+          ExtentOfAttack = 15;
+          if (!ExtentOfAttack)
+          {
+            // free up mem used by alliances
+            for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+              if (Alliances[iTemp])
+                free(Alliances[iTemp]);
+            return;
+          }
+          break;
+      }
+
+      // initialize result beforehand
+      Result.InterBBS = FALSE;
+      Result.DefenderType = EO_ALLIANCE;
+      Result.BBSIDFrom = Config->BBSID;
+      Result.BBSIDTo = Config->BBSID;
+      Result.AttackerID[0] = PClan->ClanID[0];
+      Result.AttackerID[1] = PClan->ClanID[1];
+      Result.DefenderID[0] = Alliances[WhichAlliance]->CreatorID[0];
+      Result.DefenderID[1] = Alliances[WhichAlliance]->CreatorID[1];
+      Result.Goal = Goal;
+      Result.AllianceID = Alliances[WhichAlliance]->ID;
+
+      // defenderID unused for villages
+      EmpireAttack (Empire, &AttackingArmy, &Alliances[WhichAlliance]->Empire,
+        &Result, Goal, ExtentOfAttack);
+
+      // process result (calculates total loss of land, etc.)
+      ProcessAttackResult(&Result);
+
+      // display results of battle to user
+      ShowResults (&Result);
+
+      // "give" the defender land from which his buildings came from
+      LandGained = 0;
+      for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+      {
+        LandGained += (Result.BuildingsDestroyed[iTemp]*BuildingType[iTemp].LandUsed);
+      }
+      Alliances[WhichAlliance]->Empire.Land += LandGained;
+
+      // update attacker's army
+      Empire->Army.Footmen -= Result.AttackCasualties.Footmen;
+      Empire->Army.Axemen  -= Result.AttackCasualties.Axemen;
+      Empire->Army.Knights -= Result.AttackCasualties.Knights;
+
+      // update defender's attack
+      Alliances[WhichAlliance]->Empire.Army.Footmen -= Result.DefendCasualties.Footmen;
+      Alliances[WhichAlliance]->Empire.Army.Axemen  -= Result.DefendCasualties.Axemen;
+      Alliances[WhichAlliance]->Empire.Army.Knights -= Result.DefendCasualties.Knights;
+
+      // update his losses
+      Alliances[WhichAlliance]->Empire.VaultGold -= Result.GoldStolen;
+      Alliances[WhichAlliance]->Empire.Land -= Result.LandStolen;
+
+      for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+      {
+        Alliances[WhichAlliance]->Empire.Buildings[iTemp]
+          -= Result.BuildingsDestroyed[iTemp];
+      }
+
+      // give attacker his land
+      Empire->Land += Result.LandStolen;
+      Empire->VaultGold += Result.GoldStolen;
+
+      // update info to file
+      UpdateAlliances(Alliances);
+
+      // free up mem used by alliances
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+        if (Alliances[iTemp])
+          free(Alliances[iTemp]);
+
+    }
+    else if (TypeOfDefender == EO_CLAN)
+    {
+      // choose clan using GetClanID()
+
+      // attack...
+
+      if (GetClanID( ClanID, FALSE, FALSE, -1, -1 ) == FALSE)
+      {
+        return;
+      }
+
+      TmpClan = malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+      GetClan(ClanID, TmpClan);
+
+      // if still in protection, tell user
+
+      if (TmpClan->Protection)
+      {
+        rputs("|07That clan empire is still in protection and cannot be attacked.\n%P");
+        FreeClan(TmpClan);
+        return;
+      }
+
+      // choose number of troops
+      GetNumTroops(&Empire->Army, &AttackingArmy);
+
+      if (AttackingArmy.Footmen == 0 &&
+        AttackingArmy.Axemen  == 0 &&
+        AttackingArmy.Knights == 0)
+      {
+        rputs(ST_ABORTED);
+        FreeClan(TmpClan);
+        return;
+      }
+
+      // choose type of attack (what is goal?)
+      NumGoals = 3;
+      apszGoals[0] = pszStealLand;
+      apszGoals[1] = pszStealGold;
+      apszGoals[2] = pszDestroy;
+
+      // choose one, ask user if sure
+      for (;;)
+      {
+        GetStringChoice(apszGoals, NumGoals, ST_WEMPIRE2,
+          &Goal, TRUE, DT_LONG, TRUE);
+
+        if (Goal == -1)
+        {
+          // choose against it, so quit
+          rputs(ST_ABORTED);
+          FreeClan(TmpClan);
+          return;
+        }
+
+        // ask user and show help
+        Help(apszGoals[Goal], ST_WARHLP);
+        if (YesNo(ST_WEMPIRE3) == YES)
+          break;
+      }
+      Goal++;     // must add 1 since 0 is not used
+
+      // choose length of attack, etc.
+      switch (Goal)
+      {
+        case G_STEALLAND :  // find out how much to steal
+          // ExtentOfAttack = GetLong(ST_WAR2, 5, 10);
+          ExtentOfAttack = 10;
+          if (!ExtentOfAttack)
+          {
+            FreeClan(TmpClan);
+            return;
+          }
+          break;
+        case G_STEALGOLD :
+          // ExtentOfAttack = GetLong(ST_WAR3, 8, 15);
+          ExtentOfAttack = 15;
+          if (!ExtentOfAttack)
+          {
+            FreeClan(TmpClan);
+            return;
+          }
+          break;
+        case G_DESTROY :
+          // ExtentOfAttack = GetLong(ST_WAR4, 5, 15);
+          ExtentOfAttack = 15;
+          if (!ExtentOfAttack)
+          {
+            FreeClan(TmpClan);
+            return;
+          }
+          break;
+      }
+
+      // initialize result beforehand
+      Result.InterBBS = FALSE;
+      Result.DefenderType = EO_CLAN;
+      Result.BBSIDFrom = Config->BBSID;
+      Result.BBSIDTo = Config->BBSID;
+      Result.AttackerID[0] = PClan->ClanID[0];
+      Result.AttackerID[1] = PClan->ClanID[1];
+      Result.DefenderID[0] = ClanID[0];
+      Result.DefenderID[1] = ClanID[1];
+      Result.AllianceID = Empire->AllianceID;
+      Result.Goal = Goal;
+      Result.AllianceID = -1;
+
+      // defenderID unused for villages
+      EmpireAttack (Empire, &AttackingArmy, &TmpClan->Empire,
+        &Result, Goal, ExtentOfAttack);
+
+      // process result (calculates total loss of land, etc.)
+      ProcessAttackResult(&Result);
+
+      ShowResults (&Result);
+
+      // "give" the defender land from which his buildings came from
+      LandGained = 0;
+      for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+      {
+        LandGained += (Result.BuildingsDestroyed[iTemp]*BuildingType[iTemp].LandUsed);
+      }
+      TmpClan->Empire.Land += LandGained;
+
+      // update attacker's army
+      Empire->Army.Footmen -= Result.AttackCasualties.Footmen;
+      Empire->Army.Axemen  -= Result.AttackCasualties.Axemen;
+      Empire->Army.Knights -= Result.AttackCasualties.Knights;
+
+      // update defender's attack
+      TmpClan->Empire.Army.Footmen -= Result.DefendCasualties.Footmen;
+      TmpClan->Empire.Army.Axemen  -= Result.DefendCasualties.Axemen;
+      TmpClan->Empire.Army.Knights -= Result.DefendCasualties.Knights;
+
+      // update his losses
+      TmpClan->Empire.VaultGold -= Result.GoldStolen;
+      TmpClan->Empire.Land -= Result.LandStolen;
+
+      for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+      {
+        TmpClan->Empire.Buildings[iTemp] -= Result.BuildingsDestroyed[iTemp];
+      }
+
+      // give attacker his land
+      Empire->Land += Result.LandStolen;
+      Empire->VaultGold += Result.GoldStolen;
+
+      // update info to file
+      Clan_Update(TmpClan);
+      FreeClan(TmpClan);
+
+    }
+
+    // reduce attacks
+    if (Empire->OwnerType == EO_VILLAGE)
+      Empire->AttacksToday++;
+    else
+      PClan->Empire.AttacksToday++;
+
+    // update attacker's army rating
+    Decrease = ExtentOfAttack/5 + 2;
+    Empire->Army.Rating -= Decrease;
+    if (Empire->Army.Rating < 0)
+      Empire->Army.Rating = 0;
+
+    // ** choose length of attack, etc.
+
+    // -> if interbbs attack, generate packet destined for bbs
+      // update this empire's stats (reduce army, etc.)
+      // that bbs will run the empireattack function and send back the
+      // results
+      // when results return, update the empire...
+
+
+    // give points for win, take away some for loss
+    if (Empire->OwnerType == EO_CLAN)
+    {
+      if (Result.Success)
+        PClan->Points += 50;
+      else
+        PClan->Points -= 25;
+    }
+
+    door_pause();
+	(void)DefendingArmy;
+	(void)szNews;
+  }
+
+
+// ------------------------------------------------------------------------- //
+  void SpyMenu ( struct empire *Empire )
+  {
+    struct Alliance *Alliances[MAX_ALLIANCES];
+    struct clan *TmpClan;
+    char *pszVillage = "1 A Village",
+       *pszAlliance = "2 An Alliance",
+       *pszClan = "3 A Clan",
+       *aszVillageNames[MAX_IBBSNODES],
+       *pszWhoToSpy[3],
+       *aszAllianceNames[MAX_ALLIANCES], szSpierName[40], szMessage[128];
+    _INT16 NumOfTypes, iTemp, NumBBSes, BBSIndex[MAX_IBBSNODES];
+    _INT16 WhichVillage, NumAlliances, WhichAlliance, TypeToSpyOn;
+    char szString[255];
+    _INT16 ClanID[2], Junk[2];
+
+    if (!PClan->SpyHelp)
+    {
+      PClan->SpyHelp = TRUE;
+      Help("Spy Help", ST_EMPIREHLP);
+      rputs("\n%P");
+    }
+
+    if (Empire->SpiesToday == MAX_SPIES)
+    {
+      // rputs("You have spied too much already today.\n%P");
+      rputs(ST_SPY0);
+      return;
+    }
+
+    if (Empire->OwnerType == EO_VILLAGE)
+      strcpy(szSpierName, "the village");
+    else if (Empire->OwnerType == EO_CLAN)
+      sprintf(szSpierName, "%s", Empire->szName);
+    else if (Empire->OwnerType == EO_ALLIANCE)
+      sprintf(szSpierName, "the alliance of %s", Empire->szName);
+
+    // choose who to spy on:
+    if (Game.Data->ClanEmpires == FALSE)
+    {
+      pszWhoToSpy[0] = pszVillage;
+      pszWhoToSpy[1] = pszAlliance;
+      NumOfTypes = 2;
+    }
+    else
+    {
+      pszWhoToSpy[0] = pszVillage;
+      pszWhoToSpy[1] = pszAlliance;
+      pszWhoToSpy[2] = pszClan;
+      NumOfTypes = 3;
+    }
+
+    GetStringChoice(pszWhoToSpy, NumOfTypes, ST_WEMPIRE0,
+      &TypeToSpyOn, TRUE, DT_LONG, TRUE);
+
+    if (TypeToSpyOn == -1)
+    {
+      rputs(ST_ABORTED);
+      return;
+    }
+
+    // if a village, choose which
+    if (TypeToSpyOn == EO_VILLAGE)
+    {
+      // choose which village to attack
+      for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+      {
+        aszVillageNames[iTemp] = NULL;
+      }
+
+      // put our village in the list first IF the empire is not a village
+      if (Empire->OwnerType != EO_VILLAGE)
+      {
+        aszVillageNames[0] = Village.Data->szName;
+        // get rest of the other villages and skip ours
+        NumBBSes = 1;
+
+        if (Game.Data->InterBBS)
+          for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+          {
+            if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+              continue;
+
+            if (iTemp+1 == IBBS.Data->BBSID)
+              break;
+          }
+        else
+          iTemp = 0;
+
+        BBSIndex[0] = iTemp+1;
+      }
+      else
+        NumBBSes = 0;
+
+      if (Game.Data->InterBBS)
+        for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+        {
+          if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+            continue;
+
+          if (iTemp+1 == IBBS.Data->BBSID)
+            continue;
+
+          aszVillageNames[NumBBSes] = IBBS.Data->Nodes[iTemp].Info.pszVillageName;
+          BBSIndex[NumBBSes] = iTemp+1;
+          NumBBSes++;
+        }
+
+      // choose a village
+
+      GetStringChoice(aszVillageNames, NumBBSes, ST_WEMPIRE1,
+        &WhichVillage, TRUE, DT_WIDE, TRUE);
+
+      if (WhichVillage == -1)
+      {
+        rputs(ST_ABORTED);
+        return;
+      }
+      // sprintf(szString, "It will cost you %ld gold to spy.  The empire has %ld gold.\nContinue?",
+      sprintf(szString, ST_SPY1, SPY_COST, Empire->VaultGold);
+      if (YesNo(szString) == NO)
+      {
+        return;
+      }
+      if (Empire->VaultGold < SPY_COST)
+      {
+        rputs(ST_FMENUNOAFFORD);
+        return;
+      }
+      else
+        Empire->VaultGold -= SPY_COST;
+
+      if ( (Game.Data->InterBBS && BBSIndex[WhichVillage] == IBBS.Data->BBSID)
+        || (Game.Data->InterBBS == FALSE && WhichVillage == 0))
+      {
+        // see if we can spy, if so, spy on 'em now using EmpireStats
+        // increment spies per day in future
+        if ( (Empire->Buildings[B_AGENCY]+RANDOM(5)) >
+            (Village.Data->Empire.Buildings[B_SECURITY]+RANDOM(3)) )
+        {
+          // success!
+          // rputs("Your spy is successful!\n");
+          rputs(ST_SPY2);
+          Empire_Stats(&Village.Data->Empire);
+        }
+        else
+        {
+          // rputs("Your spy failed and was captured!\n");
+          rputs(ST_SPY3);
+
+          if (Village.Data->RulingClanId[0] != -1)
+          {
+            // sprintf(szMessage, " You caught a spy attempting to gain info on the village's empire.\n The spy was from %s.\n",
+            sprintf(szMessage, ST_SPY4,
+              szSpierName);
+            GenericMessage(szMessage, Village.Data->RulingClanId, Junk, "", FALSE);
+          }
+        }
+      }
+      else
+      {
+        // send an IBBS spy packet
+        IBBS_SendSpy( Empire, BBSIndex[WhichVillage] );
+      }
+    }
+    else if (TypeToSpyOn == EO_ALLIANCE)
+    {
+      // get alliances and choose one
+
+      GetAlliances(Alliances);
+
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        if (Alliances[iTemp] == NULL)
+          break;
+        else
+          aszAllianceNames[iTemp] = Alliances[iTemp]->szName;
+      }
+      NumAlliances = iTemp;
+
+      if (NumAlliances == 0)
+      {
+        rputs("No alliances found!\n");
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+
+        return;
+      }
+
+      GetStringChoice(aszAllianceNames, NumAlliances, ST_WEMPIRE6,
+        &WhichAlliance, TRUE, DT_WIDE, TRUE);
+
+      if (WhichAlliance == -1)
+      {
+        rputs(ST_ABORTED);
+
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+
+        return;
+      }
+
+      // sprintf(szString, "It will cost you %ld gold to spy.  The empire has %ld gold.\nContinue?",
+      sprintf(szString, ST_SPY1, SPY_COST, Empire->VaultGold);
+      if (YesNo(szString) == NO)
+      {
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+        return;
+      }
+      if (Empire->VaultGold < SPY_COST)
+      {
+        // free up mem used by alliances
+        for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+          if (Alliances[iTemp])
+            free(Alliances[iTemp]);
+        rputs(ST_FMENUNOAFFORD);
+        return;
+      }
+      else
+        Empire->VaultGold -= SPY_COST;
+
+      // spy on them here if possible
+      // see if we can spy, if so, spy on 'em now using EmpireStats
+      // increment spies per day in future
+      if ( (Empire->Buildings[B_AGENCY]+RANDOM(5)) >
+          (Alliances[WhichAlliance]->Empire.Buildings[B_SECURITY]+RANDOM(3)) )
+      {
+        // success!
+        // rputs("Your spy is successful!\n");
+        rputs(ST_SPY2);
+        Empire_Stats(&Alliances[WhichAlliance]->Empire);
+      }
+      else
+      {
+        // rputs("Your spy failed and was captured!\n");
+        rputs(ST_SPY3);
+
+        sprintf(szMessage, ST_SPY5,
+          Alliances[WhichAlliance]->szName, szSpierName);
+        GenericMessage(szMessage, Alliances[WhichAlliance]->CreatorID, Junk, "", FALSE);
+      }
+
+      // free up mem used by alliances
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+        if (Alliances[iTemp])
+          free(Alliances[iTemp]);
+    }
+    else if (TypeToSpyOn == EO_CLAN)
+    {
+      // choose clan using GetClanID()
+
+      if (GetClanID( ClanID, FALSE, FALSE, -1, -1 ) == FALSE)
+      {
+        return;
+      }
+
+      // sprintf(szString, "It will cost you %ld gold to spy.  The empire has %ld gold.\nContinue?",
+      sprintf(szString, ST_SPY1, SPY_COST, Empire->VaultGold);
+      if (YesNo(szString) == NO)
+      {
+        return;
+      }
+      if (Empire->VaultGold < SPY_COST)
+      {
+        rputs(ST_FMENUNOAFFORD);
+        return;
+      }
+      else
+        Empire->VaultGold -= SPY_COST;
+
+      TmpClan = malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+      GetClan(ClanID, TmpClan);
+
+      // spy on them here if possible
+      // see if we can spy, if so, spy on 'em now using EmpireStats
+      // increment spies per day in future
+      if ( (Empire->Buildings[B_AGENCY]+RANDOM(5)) >
+          (TmpClan->Empire.Buildings[B_SECURITY]+RANDOM(3)) )
+      {
+        // success!
+        rputs(ST_SPY2);
+        Empire_Stats(&TmpClan->Empire);
+      }
+      else
+      {
+        rputs(ST_SPY3);
+
+        sprintf(szMessage, ST_SPY6, szSpierName);
+        GenericMessage(szMessage, TmpClan->ClanID, Junk, "", FALSE);
+      }
+
+      FreeClan(TmpClan);
+    }
+    Empire->SpiesToday++;
+  }
+
+// ------------------------------------------------------------------------- //
+  void Empire_Manage ( struct empire *Empire )
+  {
+    char *szTheOptions[9], szString[128];
+
+    LoadStrings(1260, 9, szTheOptions);
+
+    if (!PClan->EmpireHelp)
+    {
+      PClan->EmpireHelp = TRUE;
+      Help("Empire Help", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      /* show 'menu' */
+      rputs(ST_MEMPIRE0);
+      rputs(ST_LONGLINE);
+      sprintf(szString, ST_MEMPIRE1, Empire->VaultGold);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE2, Empire->Army.Rating);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE3, Empire->Land);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE4, Empire->WorkerEnergy);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE5, Empire->Buildings[B_SECURITY]);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE6, Empire->Buildings[B_AGENCY]);
+      rputs(szString);
+      sprintf(szString, ST_MEMPIRE10,Empire->Buildings[B_DEVELOPERS]);
+      rputs(szString);
+
+      switch(GetChoice("Empire Menu", ST_ENTEROPTION, szTheOptions, "BMAQ?SDLH", 'Q', TRUE))
+      {
+        case 'H' :  // help
+          GeneralHelp(ST_EMPIREHLP);
+          break;
+        case 'L' :  // buy land
+          DevelopLand(Empire);
+          break;
+        case 'D' :  // donate to empire
+          if (Empire->OwnerType == EO_CLAN)
+            // you can't donate to your own clan
+            rputs(ST_MEMPIRE7);
+          else
+            DonateToEmpire(Empire);
+          break;
+        case 'B' :  // build structure
+          StructureMenu( Empire );
+          break;
+        case 'M' :  // manage army
+          if (Empire->Buildings[B_BARRACKS] == 0)
+            // rputs("You need a barracks first!\n");
+            rputs(ST_MEMPIRE8);
+          else
+            ManageArmy( Empire );
+          break;
+        case 'A' :  // attack empire
+          if (PClan->Protection && Empire->OwnerType == EO_CLAN)
+          {
+            rputs("|07You cannot attack another empire while in protection.\n%P");
+            break;
+          }
+
+          if (Empire->Buildings[B_BARRACKS] == 0)
+            rputs(ST_MEMPIRE8);
+          else
+          {
+            // if this is the user, tell him "You can only command X
+            // attacks per day"
+            if (Empire->OwnerType == EO_VILLAGE)
+            {
+              if (Empire->AttacksToday == MAX_VILLAGEEMPIREATTACKS)
+              {
+                // rputs("The village army can only handle 5 attacks per day.\n");
+                rputs(ST_MEMPIRE32);
+                break;
+              }
+              StartEmpireWar( Empire );
+            }
+            else
+            {
+              if (PClan->Empire.AttacksToday == MAX_EMPIREATTACKS)
+              {
+                // rputs("You can only command 5 attacks per day.\n");
+                rputs(ST_MEMPIRE33);
+                break;
+              }
+              StartEmpireWar( Empire );
+            }
+          }
+          break;
+        case 'S' :  // spy on empire
+          if (Empire->Buildings[B_AGENCY] == 0)
+            // rputs("You need an intelligence agency first!\n");
+            rputs(ST_MEMPIRE9);
+          else
+            SpyMenu( Empire );
+          break;
+        case 'Q' :      /* return to previous menu */
+          return;
+        case '?' :      /* redisplay options */
+          break;
+      }
+    }
+  }
+
diff --git a/src/doors/clans-src/empire.h b/src/doors/clans-src/empire.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e64422565c4be22330aa745e2cb97eb4ddd7990
--- /dev/null
+++ b/src/doors/clans-src/empire.h
@@ -0,0 +1,20 @@
+
+  void Empire_Stats ( struct empire *Empire );
+
+  void Empire_Maint ( struct empire *Empire );
+
+  void Empire_Create ( struct empire *Empire, BOOL UserEmpire );
+
+  void Empire_Manage ( struct empire *Empire );
+
+  void DonateToEmpire( struct empire *Empire );
+
+
+  _INT16 ArmySpeed( struct Army *Army );
+  long ArmyOffense( struct Army *Army );
+  long ArmyDefense( struct Army *Army );
+  long ArmyVitality( struct Army *Army );
+
+  void ProcessAttackResult ( struct AttackResult *AttackResult );
+  void ProcessAttackPacket ( struct AttackPacket *AttackPacket );
+  void ProcessResultPacket ( struct AttackResult *Result );
diff --git a/src/doors/clans-src/event.c b/src/doors/clans-src/event.c
new file mode 100644
index 0000000000000000000000000000000000000000..3a46682f7e51f7f5b8ed6dc3e99962539795ad3e
--- /dev/null
+++ b/src/doors/clans-src/event.c
@@ -0,0 +1,153 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Event ADT
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "door.h"
+#include "help.h"
+#include "quests.h"
+
+
+extern struct clan *PClan;
+extern struct Language *Language;
+extern struct Quest Quests[MAX_QUESTS];
+
+  void GoQuest ( void )
+  {
+    _INT16 iTemp, TotalQuests = 0, WhichQuest, NumQuestsDone, QuestIndex[64];
+    BOOL QuestDone, QuestKnown;
+    char KnownBitSet, DoneBitSet;
+    char szString[50], cInput;
+
+    // tell him how many quests he's done right here for now since i'm too lazy
+    for (iTemp = 0, NumQuestsDone = 0; iTemp < MAX_QUESTS; iTemp++)
+    {
+      if (PClan->QuestsDone[ iTemp/8 ] & (1 << (iTemp%8)))
+        NumQuestsDone++;
+    }
+
+    for (;;)
+    {
+      sprintf(szString, " |0CQuests Completed:  |0B%d\n", NumQuestsDone);
+      rputs(szString);
+      rputs(ST_LONGLINE);
+
+      /* List quests known and not completed */
+      /* <pause> where needed */
+      TotalQuests = 0;
+      for (iTemp = 0; iTemp < MAX_QUESTS; iTemp++)
+      {
+        KnownBitSet =
+          (PClan->QuestsKnown[ iTemp/8 ] & (1 << (iTemp%8)) ||
+          (Quests[iTemp].Known && Quests[iTemp].Active));
+        DoneBitSet  = PClan->QuestsDone[ iTemp/8 ] & (1 << (iTemp%8));
+
+        // quest known? AND not complete?
+        if ( KnownBitSet && !DoneBitSet && Quests[iTemp].pszQuestName)
+        {
+          // show quest then
+          sprintf(szString, " |0A(|0B%c|0A) |0C%s\n", TotalQuests + 'A',
+            Quests[iTemp].pszQuestName);
+          rputs(szString);
+          QuestIndex[TotalQuests] = iTemp;
+          TotalQuests++;
+        }
+      }
+
+      if (TotalQuests == 0)
+      {
+        rputs("\n|12You do not know of any quests.\n%P");
+        return;
+      }
+
+      rputs(ST_LONGLINE);
+      rputs(" |0GWhich quest? (Enter=abort)|0E> |0F");
+      /* get choice from user on which quest to complete */
+      for (;;)
+      {
+        cInput = toupper(od_get_key(TRUE));
+
+        if (cInput == '\r' || cInput == '\n')
+        {
+          rputs(ST_ABORTED);
+          return;
+        }
+
+        /* run QUEST.EVT block here */
+        WhichQuest = cInput - 'A';
+        if (WhichQuest >= 0 && WhichQuest < TotalQuests)
+        {
+          break;
+        }
+      }
+
+      if (Quests[ QuestIndex[WhichQuest] ].pszQuestIndex == NULL)
+      {
+        rputs("\n|12Quest not found.\n%P");
+        return;
+      }
+
+      QuestKnown = PClan->QuestsKnown[ QuestIndex[WhichQuest]/8 ] & (char)(1 << (QuestIndex[WhichQuest]%8)) ||
+        (Quests[QuestIndex[WhichQuest]].Known && Quests[QuestIndex[WhichQuest]].Active);
+      QuestDone  = PClan->QuestsDone[ QuestIndex[WhichQuest]/8 ] & (char)(1 << (QuestIndex[WhichQuest]%8));
+
+      //od_printf("Comparing with %d\n", (1 << (QuestIndex[WhichQuest]%8)));
+
+      if (QuestKnown == FALSE || QuestDone || !Quests[QuestIndex[WhichQuest]].pszQuestName)
+      {
+        rputs("\n|12Quest not found.\n%P");
+        return;
+      }
+
+      // display name of quest
+      rputs(Quests[QuestIndex[WhichQuest]].pszQuestName); rputs("\n\n");
+
+      // show help
+      Help(Quests[ QuestIndex[WhichQuest] ].pszQuestName, "quests.hlp");
+      if (YesNo("\n|0SGo on this quest?") == YES)
+        break;
+
+      rputs("\n");
+    }
+
+    PClan->QuestToday = TRUE;
+
+    /* if successful (returns TRUE), set that quest bit to done */
+    if (RunEvent(FALSE,
+      Quests[QuestIndex[WhichQuest]].pszQuestFile, Quests[QuestIndex[WhichQuest]].pszQuestIndex,
+      NULL, NULL))
+    {
+      // set bit since quest completed
+      PClan->QuestsDone[ QuestIndex[WhichQuest]/8 ] |= (1<<(QuestIndex[WhichQuest]%8));
+    }
+    door_pause();
+  }
diff --git a/src/doors/clans-src/fight.c b/src/doors/clans-src/fight.c
new file mode 100644
index 0000000000000000000000000000000000000000..89b305224798e9f8b8542239214b1d102a70ff20
--- /dev/null
+++ b/src/doors/clans-src/fight.c
@@ -0,0 +1,2179 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+# ifdef _MSC_VER
+#  include <malloc.h>
+# else
+#  include <alloc.h>
+# endif
+#endif
+
+#include <string.h>
+
+#include "structs.h"
+#include "mstrings.h"
+#include "door.h"
+#include "user.h"
+#include "help.h"
+#include "language.h"
+#include "input.h"
+#include "spells.h"
+#include <OpenDoor.h>
+#include "myopen.h"
+#include "items.h"
+#include "news.h"
+#include "mail.h"
+#include "video.h"
+
+
+#define ATTACKER            0
+#define DEFENDER            1
+#define MAX_ROUNDS          50
+#define MAX_MONSTERS        255
+
+#define PLAYERTEAM          0
+
+
+extern struct Language *Language;
+extern struct Spell *Spells[MAX_SPELLS];
+extern struct clan *PClan;
+extern struct village Village;
+
+struct move
+{
+  _INT16 Action, Target, SpellNum, ScrollNum;
+};
+
+struct order
+{
+  _INT16 TeamNum, MemberNum;
+};
+
+// ------------------------------------------------------------------------- //
+
+  void Fight_Heal ( struct clan *Clan )
+  {
+    _INT16 CurMember;
+
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (Clan->Member[CurMember] && Clan->Member[CurMember]->Status == Here)
+        Clan->Member[CurMember]->HP = Clan->Member[CurMember]->MaxHP;
+    }
+  }
+
+  void Fight_GetBattleOrder ( struct order *BattleOrder, struct clan *Team[2])
+  {
+    struct {
+      _INT16 WhichTeam;
+      _INT16 WhichPlayer;
+      _INT16 WhichSortData;
+      _INT16 AgiValue;
+    } CurHighest;
+    struct {
+      _INT16 WhichTeam;
+      _INT16 WhichPlayer;
+      _INT16 AgiValue;                   // his "agility+energy" ranking
+      _INT16 InList;                     // set if already in sort list
+    } SortData[MAX_MEMBERS * 2];
+    _INT16 CurSortMember, CurMember, CurTeam, CurOrder, TotalMembers;
+    struct pc *TempPC;
+
+
+    CurSortMember = 0;
+    for (CurTeam = 0; CurTeam < 2; CurTeam++)
+      for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+      {
+        if (Team[CurTeam]->Member[CurMember] &&
+            Team[CurTeam]->Member[CurMember]->Status == Here)
+        {
+          TempPC = Team[CurTeam]->Member[CurMember];
+
+          SortData[CurSortMember].AgiValue =
+            GetStat(TempPC, stAgility) + (TempPC->HP*10)/TempPC->MaxHP + RANDOM(2);
+          SortData[CurSortMember].WhichTeam = CurTeam;
+          SortData[CurSortMember].WhichPlayer = CurMember;
+          SortData[CurSortMember].InList = FALSE;
+
+          CurSortMember++;
+        }
+      }
+
+    // now sort them
+    TotalMembers = NumMembers(Team[0], TRUE) + NumMembers(Team[1], TRUE);
+
+    if (TotalMembers != CurSortMember)
+      DisplayStr(">>> TotalMembers != CurSortMember!\n%P");
+
+    for (CurOrder = 0; CurOrder < TotalMembers; CurOrder++)
+    {
+      // initialize sort data for this iteration (loop)
+      CurHighest.WhichTeam = -1;
+      CurHighest.WhichPlayer = -1;
+      CurHighest.WhichSortData = -1;
+      CurHighest.AgiValue = -1;
+
+      for (CurSortMember = 0; CurSortMember < TotalMembers; CurSortMember++)
+      {
+        // see who is the highest in value
+        if (SortData[CurSortMember].AgiValue > CurHighest.AgiValue &&
+            SortData[CurSortMember].InList == FALSE)
+        {
+          // Found a higher one
+          CurHighest.WhichTeam =      SortData[CurSortMember].WhichTeam;
+          CurHighest.WhichPlayer =    SortData[CurSortMember].WhichPlayer;
+          CurHighest.AgiValue =       SortData[CurSortMember].AgiValue;
+          CurHighest.WhichSortData =  CurSortMember;
+        }
+      }
+
+      if (CurHighest.WhichSortData == -1)
+      {
+        break;
+      }
+      else
+      {
+        // record that turn
+        BattleOrder[CurOrder].TeamNum = CurHighest.WhichTeam;
+        BattleOrder[CurOrder].MemberNum = CurHighest.WhichPlayer;
+        SortData[ CurHighest.WhichSortData ].InList = TRUE;
+
+        // od_printf("Using %s\n\r", Team[ Turn[CurOrder].WhichTeam ]->Member[ Turn[CurOrder].WhichPlayer ]->szName);
+      }
+    }
+
+  }
+
+
+  void Fight_ManaRegenerate( struct pc *PC )
+  {
+    /* if at max, return */
+    if (PC->SP == PC->MaxSP)
+      return;
+
+    /* regenerate according to Wisdom attribute */
+    PC->SP += ((GetStat(PC, ATTR_WISDOM)*(RANDOM(15)+5))/150 + 1);
+
+    if (PC->SP >= PC->MaxSP)
+      PC->SP = PC->MaxSP;
+  }
+
+  BOOL Fight_IsIncapacitated(struct pc *PC)
+  {
+    /* return TRUE if dude is incapacitated */
+
+    _INT16 iTemp;
+    BOOL Result = FALSE;
+
+    /* scan spellsineffect */
+
+    for (iTemp = 0; iTemp < 10; iTemp++)
+    {
+      if (PC->SpellsInEffect[iTemp].SpellNum == -1)
+        continue;
+
+      /* see if this is incapacitate spell, if so return TRUE and tell dudes */
+      if (Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->TypeFlag & SF_INCAPACITATE)
+      {
+        Result = TRUE;
+
+        /* tell dudes */
+        rputs(Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->pszStatusStr);
+        rputs("\n");
+
+        break;
+      }
+    }
+
+    return Result;
+  }
+
+  _INT16 Fight_ChooseVictim( struct clan *EnemyClan )
+  {
+    _INT16 LowestEnergy, TempEnergyPercentage, EnemyTarget = 0;
+    _INT16 NumPCs, CurPC;
+    _INT16 iTemp, Target;
+    BOOL FoundTarget = FALSE;
+
+    if (RANDOM(100) < 60)
+    {
+      /* attack guy with lowest HP percentage */
+
+      //od_printf("Choosing guy with lowest HP\n\r");
+
+      LowestEnergy = 110; /* set lowest energy percentage to 110% */
+
+      for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      {
+        if (EnemyClan->Member[iTemp] && EnemyClan->Member[iTemp]->Status == Here)
+        {
+          TempEnergyPercentage =
+            (EnemyClan->Member[iTemp]->HP * 100)/EnemyClan->Member[iTemp]->MaxHP;
+
+          if (TempEnergyPercentage < LowestEnergy)
+          {
+            EnemyTarget = iTemp;
+            LowestEnergy = TempEnergyPercentage;
+            FoundTarget = TRUE;
+          }
+        }
+      }
+      /* found who to attack */
+      Target = EnemyTarget;
+
+      if (FoundTarget == FALSE)
+      {
+        rputs("Bug #1A\n%P");
+      }
+    }
+    else
+    {
+      /* attack anyone at random */
+      //od_printf("Choosing guy at random\n\r");
+
+      /* find how many PCs in enemy clan */
+      NumPCs = NumMembers(EnemyClan, TRUE);
+
+      /* choose one at random */
+      EnemyTarget = RANDOM(NumPCs);
+
+      /* since the player listing may skip some spaces, we must
+         "seek" to that player in the member listing and find
+         out what number he is */
+      CurPC = -1;
+      for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      {
+        if (EnemyClan->Member[iTemp] && EnemyClan->Member[iTemp]->Status == Here)
+          CurPC++;
+
+        if (CurPC == EnemyTarget)
+        {
+          FoundTarget = TRUE;
+          break;
+        }
+      }
+      Target = iTemp;
+
+      if (FoundTarget == FALSE)
+      {
+        rputs("Bug #1B\n%P");
+      }
+    }
+
+
+    return Target;
+  }
+
+  _INT16 NumUndeadMembers(struct clan *Clan)
+  {
+    _INT16 iTemp;
+    _INT16 NumUndead = 0;
+
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (Clan->Member[iTemp] && Clan->Member[iTemp]->Undead &&
+        Clan->Member[iTemp]->Status == Here)
+        NumUndead++;
+    }
+
+    return NumUndead;
+  }
+
+
+  void Fight_GetNPCAction (struct pc *NPC, struct clan *EnemyClan, struct move *Move )
+  {
+    _INT16 iTemp, NumSpellsTried, TotalSpells;
+    _INT16 LowestEnergy, TempEnergyPercentage;
+    BOOL SomeoneNeedsHeal, FoundHealSpell, FoundSpell;
+    _INT16 WhoNeedsHeal = 0, HealSpellNum = 0, WhichSpell = 0;
+
+
+    /* see if anyone needs healing in the clan, skip undead! */
+    SomeoneNeedsHeal = FALSE;
+    LowestEnergy = 60;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (NPC->MyClan->Member[iTemp] == NULL)
+        continue;
+
+      if (!NPC->MyClan->Member[iTemp]->Undead && NPC->MyClan->Member[iTemp]->Status == Here)
+      {
+        TempEnergyPercentage = (NPC->MyClan->Member[iTemp]->HP * 100) /
+                                NPC->MyClan->Member[iTemp]->MaxHP;
+
+        if (TempEnergyPercentage < 50)
+        {
+          /* this guy needs healing */
+          SomeoneNeedsHeal = TRUE;
+
+          if (TempEnergyPercentage < LowestEnergy)
+          {
+            WhoNeedsHeal = iTemp;
+            LowestEnergy = TempEnergyPercentage;
+          }
+        }
+      }
+    }
+
+
+    /* this is used to see if he should run or not */
+    // EnergyPercentage = (NPC->HP * 100)/NPC->MaxHP;
+
+    /* see if any spells available */
+    if (NPC->SpellsKnown[0] != 0)
+    {
+      /* Yes, knows at least one spell */
+
+      /* see if any heal spells and can cast 'em */
+      FoundHealSpell = FALSE;
+      for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      {
+        if (NPC->SpellsKnown[iTemp] == 0)
+          break;  /* no more spells to check */
+
+        if ( Spells[ NPC->SpellsKnown[iTemp] - 1 ]->TypeFlag & SF_HEAL )
+        {
+          /* see if can cast it */
+          if (NPC->SP >= Spells[ NPC->SpellsKnown[iTemp] - 1]->SP)
+          {
+            FoundHealSpell = TRUE;
+            HealSpellNum = NPC->SpellsKnown[iTemp] - 1;
+            break;
+          }
+        }
+      }
+
+      /* if FoundHealSpell is TRUE, that means a heal spell was found
+         and it CAN be cast.  Decide now whether to cast or not using
+         randomness */
+      if (FoundHealSpell && SomeoneNeedsHeal && RANDOM(100) < 55 )
+      {
+        /* 55% of the time, he'll heal him if he can */
+        Move->Action = acCast;
+        Move->Target = WhoNeedsHeal;
+        Move->SpellNum = HealSpellNum;
+
+        //rputs("|15Enemy casts HEAL!\n");
+
+        return;
+      }
+      else
+      {
+        /* see what other spells are available, cast 'em if
+           enough SP and randomness allows it */
+
+        /* keep going through spells at random till gone through all
+           of 'em */
+
+        /* see how many spells that guy has first */
+        for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+        {
+          if (NPC->SpellsKnown[iTemp] == 0)
+            break;
+        }
+        TotalSpells = iTemp;
+
+        NumSpellsTried = 0;
+        FoundSpell = FALSE;
+        while (NumSpellsTried < TotalSpells)
+        {
+          /* choose spell at random*/
+          WhichSpell = RANDOM(TotalSpells);
+
+          /* see if this spell can be cast  and is NOT a heal spell */
+          if (NPC->SP >= Spells[ NPC->SpellsKnown[WhichSpell] - 1]->SP &&
+              !(Spells[ NPC->SpellsKnown[WhichSpell] - 1]->TypeFlag & SF_HEAL))
+          {
+            /* if so, set FoundSpell to true and break from loop */
+            FoundSpell = TRUE;
+            break;
+          }
+
+          /* else increment numspellstried and continue */
+          NumSpellsTried++;
+        }
+
+        /* if spell found, see if we can cast this, see
+           what type of spell to choose whether or not to cast */
+        if (FoundSpell)
+        {
+          /* according to spell type, see if we can using randomness */
+          if ((Spells[ NPC->SpellsKnown[WhichSpell] - 1]->TypeFlag &
+              SF_RAISEUNDEAD) && (RANDOM(10) == 0))
+          {
+            // od_printf("Gonna cast %s\n\r", Spells[NPC->SpellsKnown[WhichSpell] - 1]->szName);
+
+            /* 1 in 10 chance of casting this spell */
+
+            /* raise undead spell cast */
+            Move->Action = acCast;
+            Move->Target = 0;        /* target means nothing with this spell */
+            Move->SpellNum = NPC->SpellsKnown[WhichSpell] - 1;
+            return;
+          }
+          if ((Spells[ NPC->SpellsKnown[WhichSpell] - 1]->TypeFlag &
+              SF_BANISHUNDEAD) && RANDOM(5) == 0 &&
+              NumUndeadMembers(EnemyClan) != 0)
+          {
+            // od_printf("Gonna cast %s\n\r", Spells[NPC->SpellsKnown[WhichSpell] - 1]->szName);
+
+            /* ALSO check to see if other clan even has undead */
+            /* 1 in 5 chance of casting this spell */
+
+            /* banish undead spell cast */
+            Move->Action = acCast;
+            Move->Target = 0;        /* target means nothing with this spell */
+            Move->SpellNum = NPC->SpellsKnown[WhichSpell] - 1;
+            return;
+          }
+          if ((Spells[ NPC->SpellsKnown[WhichSpell] - 1]->TypeFlag &
+              SF_DAMAGE) && RANDOM(3) == 0)
+          {
+            // od_printf("Gonna cast %s\n\r", Spells[NPC->SpellsKnown[WhichSpell] - 1]->szName);
+
+            /* 1 in 3 chance of casting this spell */
+
+            /* damage spell */
+            Move->Action = acCast;
+            Move->Target = Fight_ChooseVictim(EnemyClan);
+            Move->SpellNum = NPC->SpellsKnown[WhichSpell] - 1;
+            return;
+          }
+          if ( ((Spells[ NPC->SpellsKnown[WhichSpell] - 1]->TypeFlag &
+               SF_MODIFY) || (Spells[ NPC->SpellsKnown[WhichSpell] - 1]->TypeFlag &
+               SF_INCAPACITATE)) && RANDOM(5) == 0)
+          {
+            // od_printf("Gonna cast %s\n\r", Spells[NPC->SpellsKnown[WhichSpell] - 1]->szName);
+
+            /* of course, in future, we'd see who is the strongest
+               dude on other team before casting */
+            /* 1 in 13 chance of casting this spell */
+
+            Move->Action = acCast;
+
+            if (Spells[ NPC->SpellsKnown[WhichSpell] - 1]->Friendly)
+            {
+              /* modify/incapacitate cast */
+              Move->Target = Fight_ChooseVictim(NPC->MyClan);
+              // FIXME:
+//                        od_printf("Gonna cast %s on %s\n\r", Spells[NPC->SpellsKnown[WhichSpell] - 1]->szName,
+//                            NPC->MyClan->Member[*Target]->szName);
+            }
+            else
+            {
+              Move->Target = Fight_ChooseVictim(EnemyClan);
+//                        od_printf("Gonna cast %s on %s\n\r", Spells[NPC->SpellsKnown[WhichSpell] - 1]->szName,
+//                            EnemyClan->Member[*Target]->szName);
+            }
+
+
+            Move->SpellNum = NPC->SpellsKnown[WhichSpell] - 1;
+            return;
+          }
+
+          /* if all this failed, fall through and attack enemy instead */
+        }
+      }
+    }
+
+
+    Move->Action = acAttack;
+
+    /* choose who to attack */
+    Move->Target = Fight_ChooseVictim(EnemyClan);
+
+    /* otherwise attack */
+    // od_printf("Gonna attack %s\n\r", EnemyClan->Member[*Target]->szName);
+  }
+
+  void Fight_Stats ( struct clan *PlayerClan, struct clan *MobClan, struct pc *WhichPC )
+  {
+    _INT16 CurMember, MembersShown;
+    char szString[128];
+
+    rputs("\n");
+    MembersShown = 0;
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+      if (PlayerClan->Member[CurMember] && PlayerClan->Member[CurMember]->Status != RanAway)
+      {
+        if (PlayerClan->Member[CurMember]->HP <= 0)
+          continue;   // skip him
+
+        if ((MembersShown%4) == 0 && MembersShown)
+          rputs("\n");
+
+        if (PlayerClan->Member[CurMember] == WhichPC)
+          rputs("|17");
+
+        if ((PlayerClan->Member[CurMember]->HP*100)/PlayerClan->Member[CurMember]->MaxHP
+            <= 50)
+          rputs("|06");
+        else if ((PlayerClan->Member[CurMember]->HP*100)/PlayerClan->Member[CurMember]->MaxHP
+            <= 75)
+          rputs("|12");
+        else
+          rputs("|07");
+
+        sprintf(szString, " %s %d/%d ", PlayerClan->Member[CurMember]->szName,
+          PlayerClan->Member[CurMember]->HP,
+          PlayerClan->Member[CurMember]->MaxHP);
+        rputs(szString);
+
+        if (PlayerClan->Member[CurMember] == WhichPC)
+          rputs("|16");
+
+        MembersShown++;
+      }
+
+    rputs("\n\n");
+    MembersShown = 0;
+      for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+        if (MobClan->Member[CurMember] && MobClan->Member[CurMember]->Status != RanAway)
+          //MobClan->Member[CurMember]->HP > 0)
+        {
+          if (MobClan->Member[CurMember]->HP <= 0)
+            continue;   // skip him
+
+          if ((MembersShown%4) == 0 && MembersShown)
+            rputs("\n");
+
+          if ((MobClan->Member[CurMember]->HP*100)/MobClan->Member[CurMember]->MaxHP
+              <= 50)
+            rputs("|06");
+          else if ((MobClan->Member[CurMember]->HP*100)/MobClan->Member[CurMember]->MaxHP
+              <= 75)
+            rputs("|12");
+          else
+            rputs("|13");
+
+          sprintf(szString, " %s ", MobClan->Member[CurMember]->szName);
+          rputs(szString);
+          MembersShown++;
+        }
+    rputs("\n\n");
+  }
+
+  _INT16 FirstAvailable( struct clan *Clan )
+  {
+    _INT16 CurMember;
+
+    /* see if that guy is available to attack, if not, attack somebody else */
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+      if (Clan->Member[CurMember] && Clan->Member[CurMember]->Status == Here)
+        break;
+
+    if (CurMember == MAX_MEMBERS)   /* nobody there in that clan! */
+    {
+      return (-1);
+    }
+    else
+      return CurMember;
+  }
+
+
+  _INT16 Fight_GetTarget( struct clan *MobClan, _INT16 Default )
+  {
+    _INT16 CurMember, MemberNumber, CurIndex;
+    _INT16 Index[MAX_MEMBERS];             // indexes who's around to fight
+    _INT16 TotalMembers;
+    char cInput, szString[128];
+
+    // get list of those who are alive
+    CurIndex = 0;
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (MobClan->Member[CurMember] == NULL ||
+          MobClan->Member[CurMember]->HP <= 0)
+        continue;
+
+      Index[CurIndex] = CurMember;
+
+      CurIndex++;
+    }
+    TotalMembers = CurIndex;        // total members who are alive
+
+    rputs(ST_FIGHTTARGET1);
+
+    if (Default && Default-1 < TotalMembers)
+      MemberNumber = Index[Default-1];
+    else
+      for (;;)
+      {
+        cInput = toupper(od_get_key(TRUE));
+
+        if (cInput == '?')
+        {
+          rputs("List\n");
+
+          // list who's here
+          for (CurIndex = 0; CurIndex < TotalMembers; CurIndex++)
+          {
+            sprintf(szString, "(%c) %s\n",
+              CurIndex+'A', MobClan->Member[ Index[CurIndex] ]->szName);
+            rputs(szString);
+          }
+          rputs(ST_FIGHTTARGET1);
+        }
+        else if (cInput == '\r' || cInput == '\n')
+        {
+          MemberNumber = FirstAvailable(MobClan);
+          break;
+        }
+        else
+        {
+          if (isdigit(cInput))
+            CurIndex = cInput - '1';
+          else
+            CurIndex = cInput - 'A';
+
+          if (CurIndex >= TotalMembers || CurIndex < 0)
+            continue;
+
+          MemberNumber = Index[CurIndex];
+          break;
+          }
+        }
+
+    sprintf(szString, "%s\n\n", MobClan->Member[ MemberNumber ]->szName);
+    rputs(szString);
+    return MemberNumber;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+
+  BOOL CanRun ( struct clan *RunningClan, struct clan *StayingClan )
+  {
+    /* returns TRUE if RunningClan can run away */
+    _INT16 RunningVariable, StayingVariable;
+    _INT16 AllAgilities, AllDexterities, AvgWisdom, iTemp, TotalWisdom;
+    _INT16 TotalMembers;
+
+    TotalMembers = NumMembers(RunningClan, TRUE);
+
+    AllAgilities = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (RunningClan->Member[iTemp] != NULL &&
+          RunningClan->Member[iTemp]->Undead == FALSE)
+        AllAgilities += GetStat(RunningClan->Member[iTemp], ATTR_AGILITY);
+    }
+    AllDexterities = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (RunningClan->Member[iTemp] != NULL &&
+          RunningClan->Member[iTemp]->Undead == FALSE)
+        AllDexterities += GetStat(RunningClan->Member[iTemp], ATTR_DEXTERITY);
+    }
+    TotalWisdom = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (RunningClan->Member[iTemp] != NULL &&
+          RunningClan->Member[iTemp]->Undead == FALSE)
+        TotalWisdom += GetStat(RunningClan->Member[iTemp], ATTR_WISDOM);
+    }
+    AvgWisdom = TotalWisdom / TotalMembers;
+
+    RunningVariable = AllAgilities + AllDexterities + AvgWisdom + TotalMembers*3
+                        + RANDOM(15);
+
+
+    TotalMembers = NumMembers(StayingClan, TRUE);
+
+    AllAgilities = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (StayingClan->Member[iTemp] != NULL &&
+          StayingClan->Member[iTemp]->Undead == FALSE)
+        AllAgilities += GetStat(StayingClan->Member[iTemp], ATTR_AGILITY);
+    }
+    AllDexterities = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (StayingClan->Member[iTemp] != NULL &&
+          StayingClan->Member[iTemp]->Undead == FALSE)
+        AllDexterities += GetStat(StayingClan->Member[iTemp], ATTR_DEXTERITY);
+    }
+    TotalWisdom = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+        if (StayingClan->Member[iTemp] != NULL &&
+            StayingClan->Member[iTemp]->Undead == FALSE)
+          TotalWisdom += GetStat(StayingClan->Member[iTemp], ATTR_WISDOM);
+    }
+    AvgWisdom = TotalWisdom / TotalMembers;
+
+    StayingVariable = AllAgilities + AllDexterities + AvgWisdom + TotalMembers*3
+                        + RANDOM(15);
+
+    if (RunningVariable > StayingVariable)
+      return TRUE;
+    else
+      return FALSE;
+}
+
+
+  BOOL Fight_Dead ( struct clan *Clan )
+  {
+    BOOL FoundLiving = FALSE;
+    _INT16 CurMember;
+
+    // See if player clan dead or has no living members
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+      if (Clan->Member[CurMember] &&
+          Clan->Member[CurMember]->Undead == FALSE &&
+          Clan->Member[CurMember]->Status == Here)
+      {
+        FoundLiving = TRUE;
+        break;
+      }
+
+    if (NumMembers(Clan, TRUE) == 0 || FoundLiving == FALSE)
+    {
+      rputs(ST_FIGHTDEFEAT);
+      return TRUE;
+    }
+    else
+    {
+      return FALSE;
+    }
+  }
+
+  void Fight_BattleAttack( struct pc *Attacker, struct clan *VictimClan, _INT16 Who,
+    BOOL SkipOutput)
+  {
+    _INT16 CurMember, Damage, PercentGold;
+    char szString[128];
+    long XPGained, GoldGained, TaxedGold;
+
+    if (Attacker->MyClan == PClan)
+      rputs(ST_FIGHTYOURCOLOR);
+    else
+      rputs(ST_FIGHTENEMYCOLOR);
+
+    /* see if that guy is available to attack, if not, attack somebody else */
+    if (VictimClan->Member[Who] == NULL ||
+        VictimClan->Member[Who]->Status != Here)
+    {
+      /* find somebody else since this guy ain't here! */
+      CurMember = FirstAvailable(VictimClan);
+
+      if (CurMember == -1)
+        return;
+      else
+        Who = CurMember;
+    }
+
+    /* Figure out if attack lands on other victim */
+    if ( (GetStat(Attacker, stDexterity) + RANDOM(4) + RANDOM(4) + 2) <
+         (GetStat(VictimClan->Member[Who], stAgility) + RANDOM(4)) )
+    {
+      if (SkipOutput == FALSE)
+      {
+        sprintf(szString, ST_FIGHTMISS, Attacker->szName);
+        rputs(szString);
+      }
+    }
+    else
+    {
+      Damage = ((GetStat(Attacker, stStrength)/2)*(RANDOM(40)+80))/100   -
+               GetStat(VictimClan->Member[Who], stArmorStr);
+
+      if (Damage <= 0)
+        Damage = 1;
+
+      if (SkipOutput == FALSE)
+      {
+        sprintf(szString, ST_FIGHTATTACK, Attacker->szName, VictimClan->Member[Who]->szName, Damage);
+        rputs(szString);
+      }
+
+      /* experience goes here */
+      XPGained = Damage/3 + 1;
+
+      if (SkipOutput == FALSE)
+      {
+        sprintf(szString, ST_FIGHTXP, XPGained);
+        rputs(szString);
+      }
+
+      Attacker->Experience += XPGained;
+
+      if (!SkipOutput)
+        rputs("\n\n");
+
+      VictimClan->Member[Who]->HP -= Damage;
+    }
+
+    if (VictimClan->Member[Who]->HP <= 0)
+    {
+      //od_printf("in battleattack\n\r");
+
+      /* according to how bad the hit was, figure out status */
+      if (VictimClan->szName[0] == 0)
+      {
+        VictimClan->Member[Who]->Status = Dead;
+        sprintf(szString, ST_FIGHTKILLED, VictimClan->Member[Who]->szName,
+          VictimClan->Member[Who]->Difficulty);
+
+        /* give xp because of death */
+        Attacker->Experience += (VictimClan->Member[Who]->Difficulty);
+      }
+      else if (VictimClan->Member[Who]->HP < -15)
+      {
+        VictimClan->Member[Who]->Status = Dead;
+        sprintf(szString, ST_FIGHTKILLED, VictimClan->Member[Who]->szName,
+          VictimClan->Member[Who]->Level*2);
+
+        /* loses percentage of MaxHP */
+        VictimClan->Member[Who]->MaxHP = (VictimClan->Member[Who]->MaxHP * (RANDOM(10)+90))/100;
+
+        /* give xp because of death */
+        Attacker->Experience += (VictimClan->Member[Who]->Level*2);
+      }
+      else if (VictimClan->Member[Who]->HP < -5)
+      {
+        VictimClan->Member[Who]->Status = Unconscious;
+        sprintf(szString, ST_FIGHTMORTALWOUND, VictimClan->Member[Who]->szName,
+          VictimClan->Member[Who]->Level);
+
+        /* loses percentage of MaxHP */
+        VictimClan->Member[Who]->MaxHP = (VictimClan->Member[Who]->MaxHP * (RANDOM(10)+90))/100;
+
+        Attacker->Experience += (VictimClan->Member[Who]->Level);
+      }
+      else
+      {
+        VictimClan->Member[Who]->Status = Unconscious;
+        sprintf(szString, ST_FIGHTKNOCKEDOUT, VictimClan->Member[Who]->szName,
+          VictimClan->Member[Who]->Level);
+
+        Attacker->Experience += VictimClan->Member[Who]->Level;
+      }
+      rputs(szString);
+
+      /* give gold to clan */
+      if (Attacker->MyClan == PClan)
+      {
+        if (VictimClan->Member[Who]->Difficulty != -1)
+        {
+          GoldGained = VictimClan->Member[Who]->Difficulty*((long)RANDOM(10) + 20L) + 50L + (long)RANDOM(20);
+          sprintf(szString, ST_FIGHTGETGOLD, GoldGained);
+          rputs(szString);
+
+          /* take some away due to taxes */
+          TaxedGold = (long) (GoldGained * Village.Data->TaxRate)/100L;
+          if (TaxedGold)
+          {
+            sprintf(szString, ST_FIGHTTAXEDGOLD, TaxedGold);
+            rputs(szString);
+          }
+
+          if ( (GoldGained-TaxedGold) > 0)
+          {
+            PClan->Empire.VaultGold += (GoldGained-TaxedGold);
+            Village.Data->Empire.VaultGold += TaxedGold;
+          }
+        }
+      }
+
+      // if that character was an undead dude, free him up
+      if (VictimClan->Member[Who]->Undead)
+      {
+        // BUGFIX:
+        free(VictimClan->Member[Who]);
+        VictimClan->Member[Who] = NULL;
+      }
+
+    }
+	(void)PercentGold;
+  }
+
+
+  BOOL Fight_DoMove ( struct pc *AttackerPC, struct move Move, struct clan *Defender,
+    BOOL FightToDeath, _INT16 CurRound )
+    /*
+     * returns TRUE if user ran away
+     *
+     */
+  {
+    // do action
+    if (Move.Action == acCast)
+    {
+      /* cast spell */
+      Spells_CastSpell(AttackerPC, Defender, Move.Target, Move.SpellNum);
+    }
+    else if (Move.Action == acSkip)
+    {
+      // do nothing
+    }
+    else if (Move.Action == acRead)
+    {
+      /* read scroll */
+      Items_ReadScroll(AttackerPC, Defender, Move.Target, Move.ScrollNum);
+    }
+    else if (Move.Action == acAttack)
+    {
+      Fight_BattleAttack(AttackerPC, Defender, Move.Target, FightToDeath);
+    }
+    else if (Move.Action == acRun)
+    {
+      // if FightToDeath and they chose to run, then allow
+      // them to regardless of whether or not they can
+      if (CanRun(AttackerPC->MyClan, Defender) ||
+          (FightToDeath && CurRound >= MAX_ROUNDS))
+      {
+        rputs(ST_FIGHTRUNAWAY);
+        return TRUE;
+      }
+      else
+      {
+        // cannot run away
+        rputs(ST_FIGHTNORUN);
+      }
+    }
+
+    return FALSE;
+  }
+
+  _INT16 GetTarget2( struct clan *Clan, _INT16 Default )
+  {
+    _INT16 CurMember, MemberNumber, CurIndex;
+    _INT16 Index[MAX_MEMBERS];             // indexes who's around to fight
+    _INT16 TotalMembers;
+    char cInput, szString[50];
+
+    // get list of those who are alive
+    CurIndex = 0;
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (Clan->Member[CurMember] == NULL || Clan->Member[CurMember]->HP <= 0)
+        continue;
+
+      Index[CurIndex] = CurMember;
+
+      CurIndex++;
+    }
+    TotalMembers = CurIndex;    // total members who are alive
+
+
+    // list who's here
+    for (CurIndex = 0; CurIndex < TotalMembers; CurIndex++)
+    {
+      if (Clan == PClan)
+        sprintf(szString, ST_FIGHTTARGETLIST1, CurIndex+'A', Clan->Member[Index[CurIndex]]->szName,
+          Clan->Member[Index[CurIndex]]->HP, Clan->Member[Index[CurIndex]]->MaxHP);
+      else
+        sprintf(szString, ST_FIGHTTARGETLIST2, CurIndex+'A', Clan->Member[Index[CurIndex]]->szName);
+
+      rputs(szString);
+    }
+
+    rputs("|0SUse on whom? (|0B?=List|0S): |0F");
+
+    for (;;)
+    {
+      cInput = toupper(od_get_key(TRUE));
+
+      if (cInput == '?')
+      {
+        rputs("List\n");
+
+        // list who's here
+        for (CurIndex = 0; CurIndex < TotalMembers; CurIndex++)
+        {
+          if (Clan == PClan)
+            sprintf(szString, ST_FIGHTTARGETLIST1, CurIndex+'A', Clan->Member[Index[CurIndex]]->szName,
+              Clan->Member[Index[CurIndex]]->HP, Clan->Member[Index[CurIndex]]->MaxHP);
+          else
+            sprintf(szString, ST_FIGHTTARGETLIST2, CurIndex+'A', Clan->Member[Index[CurIndex]]->szName);
+
+          rputs(szString);
+        }
+        rputs("|0SUse on whom? (|0B?=List|0S): |0F");
+
+      }
+      else if (cInput == '\r' || cInput == 'Q' || cInput == '\n')
+      {
+        MemberNumber = FirstAvailable(Clan);
+        return -1;
+      }
+      else
+      {
+        if (isdigit(cInput))
+          CurIndex = cInput - '1';
+        else
+          CurIndex = cInput - 'A';
+
+        if (CurIndex >= TotalMembers || CurIndex < 0)
+          continue;
+
+        MemberNumber = Index[CurIndex];
+        break;
+      }
+    }
+
+    sprintf(szString, "%s\n\n", Clan->Member[ MemberNumber ]->szName);
+    rputs(szString);
+    return MemberNumber;
+  }
+
+
+  BOOL Fight_ReadyScroll( struct pc *PC, struct clan *TargetClan, struct move *Move )
+  {
+    _INT16 ItemIndex, SpellChosen;
+
+    // list items
+    ListItems(PC->MyClan);
+
+    // choose one
+    ItemIndex = (_INT16)GetLong("|0SWhich scroll to read?", 0, MAX_ITEMS_HELD);
+
+    // if not chosen properly, return 0
+    if (ItemIndex == 0)
+    {
+      rputs (ST_ABORTED);
+      return 0;
+    }
+
+    ItemIndex--;
+
+    if (PC->MyClan->Items[ItemIndex].Available == FALSE ||
+        PC->MyClan->Items[ItemIndex].cType != I_SCROLL)
+    {
+      rputs(ST_INVALIDITEM);
+      return 0;
+    }
+
+    // see if can even use that scroll
+    if (ItemPenalty(PC, &PC->MyClan->Items[ItemIndex]))
+    {
+      rputs("That character cannot use that item!\n%P");
+      return 0;
+    }
+
+    // choose target now as if this was a regular spell
+
+    SpellChosen = PC->MyClan->Items[ItemIndex].SpellNum;
+    Move->ScrollNum = ItemIndex;
+
+    /* get target */
+    if (Spells[SpellChosen]->Target)
+    {
+      if (Spells[SpellChosen]->Friendly)
+      {
+        /* choose from your players */
+        Move->Target = GetTarget2(PC->MyClan, 0);
+      }
+      else
+      {
+        /* choose from enemies */
+        Move->Target = GetTarget2(TargetClan, 0);
+      }
+      if (Move->Target == -1)
+      {
+        rputs(ST_ABORTED);
+        rputs("\n");
+        return FALSE;
+      }
+    }
+    else
+      Move->Target = 0;
+
+    return 1;   // sucess
+  }
+
+  BOOL Fight_ChooseSpell( struct pc *PC, struct clan *VictimClan, struct move *Move )
+  {
+    _INT16 iTemp, SpellChosen;
+    char szKeys[MAX_SPELLS + 5], szString[80], Choice;
+    _INT16 NumSpellsKnown;
+
+    /* so we have szKeys[] = "?QABCDEFGHI..." */
+    szKeys[0] = '?';
+    szKeys[1] = 'Q';
+    szKeys[2] = '\r';
+    szKeys[3] = '\n';
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      szKeys[iTemp + 4] = 'A' + iTemp;
+    szKeys[iTemp+3] = 0;
+
+    rputs("\n");
+
+
+    /* if no spells, tell user to go away */
+
+    /* ---- assume all spells known for now */
+
+    NumSpellsKnown = 0;
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+    {
+      if (PC->SpellsKnown[iTemp])
+        NumSpellsKnown++;
+    }
+
+    if (NumSpellsKnown == 0)
+    {
+      rputs(ST_CSPELL0);
+      return FALSE;
+    }
+
+
+    for (;;)
+    {
+      /* list spells known */
+      for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      {
+        if (PC->SpellsKnown[iTemp] == 0)
+        {
+          szKeys[iTemp + 4] = 0;
+          break;
+        }
+
+        sprintf(szString, ST_CSPELL1, iTemp+'A',
+          PC->SP >= Spells[ PC->SpellsKnown[iTemp]-1 ]->SP ? "|0C" : "|08",
+          Spells[ PC->SpellsKnown[iTemp]-1 ]->szName,
+          Spells[ PC->SpellsKnown[iTemp]-1 ]->SP);
+        rputs(szString);
+      }
+
+      // show more options
+      rputs(ST_CSPELL2);
+
+      /* get input */
+      rputs(ST_CSPELL3);
+
+      // if default spell chosen, do that instead
+      if (Move->SpellNum == -1)
+        Choice = od_get_answer(szKeys);
+      else
+        Choice = Move->SpellNum + 'A';
+
+      if (Choice == '?')
+      {
+        rputs("Help\n\n");
+        Help("Spells", ST_SPELLHLP);
+        door_pause();
+        rputs("\n");
+      }
+      else if (Choice == 'Q' || Choice == '\r' || Choice == '\n')
+      {
+        rputs(ST_ABORTED);
+        rputs("\n");
+        return FALSE;
+      }
+      else
+      {
+        SpellChosen = PC->SpellsKnown[ Choice - 'A' ] - 1;
+
+        rputs(Spells[SpellChosen]->szName);
+        rputs("\n\n");
+
+        /* show info */
+        Help(Spells[SpellChosen]->szName, ST_SPELLHLP);
+
+        /* see if can even use that spell */
+        if (PC->SP < Spells[SpellChosen]->SP)
+        {
+          // can't cast spell, not enough SP
+          rputs(ST_CSPELL4);
+          return FALSE;
+        }
+
+        // ask if they really want to cast it for sure
+        if (YesNo(ST_CSPELL5) == YES)
+          break;
+        else    // aborted it
+          Move->SpellNum = -1;
+      }
+    }
+
+    Move->SpellNum = SpellChosen;
+
+    /* get target */
+    if (Spells[SpellChosen]->Target)
+    {
+      if (Spells[SpellChosen]->Friendly)
+      {
+        /* choose from your players */
+        Move->Target = GetTarget2(PC->MyClan, 0);
+      }
+      else
+      {
+        /* choose from enemies */
+        Move->Target = GetTarget2(VictimClan, 0);
+      }
+      if (Move->Target == -1)
+      {
+        rputs(ST_ABORTED);
+        rputs("\n");
+        return FALSE;
+      }
+    }
+    else
+      Move->Target = 0;
+
+    /* use up SP */
+    PC->SP -= Spells[SpellChosen]->SP;
+
+    /* if successful spell choice */
+    return TRUE;
+  }
+
+
+  _INT16 Fight_Fight ( struct clan *Attacker, struct clan *Defender,
+                     BOOL HumanEnemy, BOOL CanRun, BOOL AutoFight )
+    /*
+     * Returns TRUE if Attacker won.
+     *
+     */
+  {
+    struct clan *Team[2];
+    char *Options[20], szString[255];
+    struct order BattleOrder[MAX_MEMBERS*2];
+    struct move Move;
+    _INT16 TotalMembers, CurMember, Choice, CurRound = 0;
+    BOOL FightToDeath = FALSE, DoneMove;
+
+    Team[0] = Attacker;
+    Team[1] = Defender;
+
+    if (AutoFight)
+      FightToDeath = TRUE;
+
+    LoadStrings(1000, 20, Options);
+
+
+    // replenish both sides' energy
+    Fight_Heal(Defender);
+    Fight_Heal(Attacker);
+
+    // header stuff goes here
+    if (HumanEnemy)
+    {
+      sprintf(szString, ST_FIGHTVSHEADER, Attacker->szName, Defender->szName);
+      rputs(szString);
+    }
+
+    // main loop
+    for (;;CurRound++)
+    {
+      TotalMembers = NumMembers(Attacker, TRUE) + NumMembers(Defender, TRUE);
+
+      // figure out order of battle
+      Fight_GetBattleOrder(BattleOrder, Team);
+
+      for (CurMember = 0; CurMember < TotalMembers; CurMember++)
+      {
+        // if that player is non-existant, skip him
+        if (Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ] == NULL ||
+            Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->Status != Here)
+          continue;
+
+        // otherwise:
+        Spells_UpdatePCSpells(Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]);
+        Fight_ManaRegenerate(Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]);
+
+        if (Fight_IsIncapacitated(Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]))
+          continue;
+
+        if (BattleOrder[CurMember].TeamNum == DEFENDER ||
+            (BattleOrder[CurMember].TeamNum == ATTACKER && FightToDeath) ||
+            Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->Undead)
+        {
+          if (CurRound >= MAX_ROUNDS && BattleOrder[CurMember].TeamNum == PLAYERTEAM)
+          {
+            // run away
+            Move.Action = acRun;
+            rputs("\n\n|0CSeeing as the enemy will not yield, you choose to retreat.\n\n");
+          }
+          else
+            Fight_GetNPCAction(Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ],
+              Team[ !BattleOrder[CurMember].TeamNum ], &Move);
+        }
+        else
+        {
+          // it's a human and fight to death off
+
+          DoneMove = FALSE;
+
+          while (!DoneMove)
+          {
+            // show stats
+            Fight_Stats(Attacker, Defender, Attacker->Member[ BattleOrder[CurMember].MemberNum ]);
+
+            rputs(ST_FIGHTOPTIONS);
+
+            sprintf(szString, ST_FIGHTPSTATS, Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->szName,
+              Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->HP, Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->MaxHP,
+              Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->SP, Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->MaxSP);
+            rputs(szString);
+
+            // show options
+            switch(Choice = GetChoice("", "|0E> |0F", Options, "SAR123456789IPK?F#ED", 'D', FALSE))
+            {
+              case 'S' :  // specific move
+              case '1' :
+              case '2' :
+              case '3' :
+              case '4' :
+              case '5' :
+              case '6' :
+              case '7' :
+              case '8' :
+              case '9' :
+                if (Choice == 'S')
+                  Choice = 0;
+                else
+                  Choice -= '0';
+
+                /* ask who to attack */
+                if ((Move.Target = Fight_GetTarget(Team[ !BattleOrder[CurMember].TeamNum ], Choice)) != -1)
+                {
+                    DoneMove = TRUE;
+                    Move.Action = acAttack;
+                }
+                break;
+              case 'A' :  // attack
+                /* ask who to attack */
+                Move.Target = 0;
+                Move.Action = acAttack;
+                DoneMove = TRUE;
+                break;
+              case 'R' :  // run away
+                if (HumanEnemy)
+                {
+                  rputs(ST_FIGHTNORUN2);
+                  break;
+                }
+                else if (CanRun == FALSE)
+                {
+                  rputs("|12** |14You cannot run in this battle.\n");
+                  break;
+                }
+                else
+                {
+                  Move.Action = acRun;
+                  DoneMove = TRUE;
+                }
+                break;
+              case 'I' :  // parry blow
+                Move.Action = acSkip;
+                DoneMove = TRUE;
+                break;
+              case 'P' :
+                ShowPlayerStats(Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ], FALSE);
+                door_pause();
+                break;
+              case 'K' :
+                Move.SpellNum = -1;
+                if (Fight_ChooseSpell( Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ],
+                    Team[ !BattleOrder[CurMember].TeamNum ], &Move) )
+                {
+                  Move.Action = acCast;
+                  DoneMove = TRUE;
+                }
+                break;
+              case '?' :
+                GeneralHelp(ST_COMBATHLP);
+                break;
+              case 'F' :
+                Move.Action = acAttack;
+                Move.Target = 0;
+                FightToDeath = TRUE;
+                DoneMove = TRUE;
+                break;
+              case '#' :
+                rputs("\n|07Please enter the number of the enemy to attack.\n%P\n");
+                break;
+              case 'E' :
+                if (Fight_ReadyScroll( Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ], Team[ !BattleOrder[CurMember].TeamNum ], &Move) )
+                {
+                  Move.Action = acRead;
+                  DoneMove = TRUE;
+                }
+                break;
+              case 'D' :  // default action
+                // if spell, see if can cast
+                if (Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->DefaultAction >= 10)
+                {
+                  Move.SpellNum = Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->DefaultAction - 10;
+
+                  if (Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->SP >=
+                      Spells[Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ]->SpellsKnown[Move.SpellNum] - 1]->SP)
+                  {
+                    // spell does exist, do it
+                    if (Fight_ChooseSpell( Team[ BattleOrder[CurMember].TeamNum ]->Member[ BattleOrder[CurMember].MemberNum ],
+                      Team[ !BattleOrder[CurMember].TeamNum ], &Move) )
+                    {
+                      Move.Action = acCast;
+                      DoneMove = TRUE;
+                    }
+                  }
+                  else    // do regular attack
+                  {
+                    Move.Target = 0;
+                    Move.Action = acAttack;
+                    DoneMove = TRUE;
+                  }
+                }
+                else    // do regular attack
+                {
+                  Move.Target = 0;
+                  Move.Action = acAttack;
+                  DoneMove = TRUE;
+                }
+                break;
+            }
+          }
+        }
+
+        if (Fight_DoMove(Team[BattleOrder[CurMember].TeamNum]->Member[ BattleOrder[CurMember].MemberNum ], Move,
+          Team[ !BattleOrder[CurMember].TeamNum ], FightToDeath, CurRound))
+          return FT_RAN; // ran away
+
+        // attacker is considered dead if no more living members EXCLUDING undead
+        if (Fight_Dead(Attacker))
+          return FT_LOST;
+        else if (NumMembers(Defender, TRUE) == 0)
+          return FT_WON;
+
+        // otherwise, keep fighting
+      }
+    }
+
+  }
+
+  void Fight_CheckLevelUp ( void )
+  {
+    /* sees if any clansmen need to raise a level.  if so, grant them
+       a training point each */
+    char szString[128];
+    _INT16 CurMember;
+    long XPRequired[MAX_LEVELS];
+    _INT16 iTemp, Level, Points;
+    BOOL LevelUpFound = FALSE, FirstTime = TRUE;
+
+    /* figure XP required per level */
+    for (Level = 1; Level < MAX_LEVELS; Level++)
+    {
+      XPRequired[Level] = 50L;
+
+      for (iTemp = 1; iTemp <= Level; iTemp++)
+        XPRequired[Level] += ((long)(iTemp-1)*75L);
+    }
+
+    /* for each member, see if xp is higher than the xp required for the
+       next level */
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      /* if so, tell user "blah has raised a level".  raise his level,
+         graint him RANDOM(1) + 1 training points */
+
+
+      if (PClan->Member[CurMember])
+      {
+        /* see if enough XP */
+
+        if ( PClan->Member[CurMember]->Experience >=
+             XPRequired[PClan->Member[CurMember]->Level+1])
+        {
+          if (FirstTime)
+            rputs("\n");
+
+          FirstTime = FALSE;
+
+          /* Enough XP, raise level and give training point */
+          Points = RANDOM(4) + 10;
+
+          PClan->Member[CurMember]->Level++;
+          PClan->Member[CurMember]->TrainingPoints += Points;
+
+          // sprintf(szString, "|10>> |15%s |02raises to level |14%d |02and gains %d training points!\n",
+          sprintf(szString, ST_LEVELUP, PClan->Member[CurMember]->szName,
+            PClan->Member[CurMember]->Level, Points);
+          rputs(szString);
+
+          LevelUpFound = TRUE;
+        }
+      }
+    }
+    if (LevelUpFound && !PClan->TrainHelp)
+    {
+      rputs("\n\n");
+      PClan->TrainHelp = TRUE;
+      Help("Level Raise", ST_NEWBIEHLP);
+    }
+
+    /* tell him (in helpform) that he can go train at a training center */
+
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 GetDifficulty ( _INT16 Level )
+  {
+    _INT16 Difficulty = 0;
+
+    if (Level <= 2 )
+      Difficulty = 5 + RANDOM(3);
+    else if (Level <= 4 )
+      Difficulty = 7 + RANDOM(4);
+    else if (Level <= 6 )
+      Difficulty = 20 + RANDOM(10);
+    else if (Level <= 10 )
+      Difficulty = 30 + RANDOM(10);
+    else if (Level <= 15 )
+      Difficulty = 45 + RANDOM(15);
+    else if (Level <= 20 )
+      Difficulty = 90 + RANDOM(30);
+
+    return Difficulty;
+  }
+
+  struct clan *MallocClan ( void )
+  {
+    struct clan *Clan;
+    _INT16 iTemp;
+
+    Clan = malloc(sizeof(struct clan));
+    CheckMem(Clan);
+
+    /* NULL-pointer each member of clan for now */
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      Clan->Member[iTemp] = NULL;
+
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+      Clan->Items[iTemp].Available = FALSE;
+
+    Clan->szName[0] = 0;
+
+    return Clan;
+  }
+
+  _INT16 Fight_GetMonster(struct pc *Monster, _INT16 MinDifficulty, _INT16 MaxDifficulty,
+      char *szFileName)
+  {
+    _INT16 *MonIndex;
+    _INT16 iTemp, ValidMonsters;
+    _INT16 *ValidMonIndex, MonsterChosen;
+    struct FileHeader FileHeader;
+    char szString[128];
+
+    MyOpen(szFileName, "rb", &FileHeader);
+
+    if (!FileHeader.fp)
+    {
+      sprintf(szString, "Error:  couldn't open %s!\n", szFileName);
+      rputs(szString);
+      od_exit(0, FALSE);
+    }
+
+    MonIndex =      malloc(sizeof(_INT16) * MAX_MONSTERS);
+    ValidMonIndex = malloc(sizeof(_INT16) * MAX_MONSTERS);
+    CheckMem(MonIndex);
+    CheckMem(ValidMonIndex);
+
+    /* read index */
+    fread(MonIndex, sizeof(_INT16) * MAX_MONSTERS, 1, FileHeader.fp);
+
+    /* calculate how many guys there are that are within range */
+    ValidMonsters = 0;
+    for (iTemp = 0; iTemp < MAX_MONSTERS; iTemp++)
+    {
+      if (MonIndex[iTemp] == 0)   /* done looking */
+        break;
+
+      if (MonIndex[iTemp] >= MinDifficulty && MonIndex[iTemp] <= MaxDifficulty)
+      {
+        ValidMonIndex[ValidMonsters] = iTemp;
+        ValidMonsters++;
+      }
+    }
+
+    if (ValidMonsters == 0)
+    {
+      rputs("Error:  No valid monsters!!\n%P");
+      free(MonIndex);
+      free(ValidMonIndex);
+      fclose(FileHeader.fp);
+      return -1;
+    }
+
+    //od_printf("%d valid monsters found.\n\r", ValidMonsters);
+
+    iTemp = RANDOM(ValidMonsters);
+    MonsterChosen = ValidMonIndex[ iTemp ];
+
+    //od_printf("Using #%d in the file.\n\r", MonsterChosen);
+
+    /* fseek there and read it in */
+  //   fseek(FileHeader.fp, (long)MonsterChosen * sizeof(struct pc), SEEK_CUR);
+
+    fseek(FileHeader.fp,
+        ((long)sizeof(_INT16) * MAX_MONSTERS + ((long)MonsterChosen * sizeof(struct pc)) + FileHeader.lStart),
+        SEEK_SET);
+    fread(Monster, sizeof(struct pc), 1, FileHeader.fp);
+
+    fclose(FileHeader.fp);
+
+    /* randomize stats */
+    for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+    {
+      Monster->Attributes[iTemp] = (Monster->Attributes[iTemp] * (RANDOM(60)+80))/100;
+    }
+    Monster->HP = (Monster->HP* (RANDOM(30)+80))/100;
+    Monster->MaxHP = Monster->HP;
+
+    free(MonIndex);
+    free(ValidMonIndex);
+
+    return 0;
+  }
+
+
+
+  void Fight_LoadMonsters ( struct clan *Clan, _INT16 Level, char *szFileName )
+  {
+    _INT16 MinDifficulty, MaxDifficulty, Difficulty, CurDiff, iTemp,
+        CurMonster;
+
+    // figure out difficulty value
+    Difficulty = GetDifficulty(Level);
+
+    MinDifficulty = Level - 2 - RANDOM(3);
+    if (MinDifficulty < 1)
+        MinDifficulty = 1;
+    MaxDifficulty = Level + 1 + RANDOM(3);
+    if (MaxDifficulty > 20)
+        MaxDifficulty = 20;
+
+    // keep getting monsters of level(s) we want until totalsum reached
+    CurMonster = 0;
+    CurDiff = 0;
+    while (CurDiff < Difficulty)
+    {
+      Clan->Member[CurMonster] = malloc(sizeof(struct pc));
+      CheckMem(Clan->Member[CurMonster]);
+
+      if (Fight_GetMonster(Clan->Member[CurMonster], MinDifficulty, MaxDifficulty, szFileName) == -1)
+      {
+        free(Clan->Member[CurMonster]);
+        Clan->Member[CurMonster] = NULL;
+        continue;
+      }
+
+      /* set its spells to -1 */
+      for (iTemp = 0; iTemp < 10; iTemp++)
+        Clan->Member[CurMonster]->SpellsInEffect[iTemp].SpellNum = -1;
+
+      Clan->Member[CurMonster]->MyClan = Clan;
+
+      CurDiff += Clan->Member[CurMonster]->Difficulty;
+
+      CurMonster++;
+    }
+  }
+
+  void RemoveUndead ( struct clan *Clan )
+  {
+    _INT16 CurMember;
+
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (Clan->Member[CurMember] && Clan->Member[CurMember]->Undead)
+      {
+        free(Clan->Member[CurMember]);
+        Clan->Member[CurMember] = NULL;
+      }
+    }
+  }
+
+  void FreeClan( struct clan *Clan )
+  {
+    _INT16 CurMember;
+
+    // free members first
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (Clan->Member[CurMember])
+      {
+        free(Clan->Member[CurMember]);
+        Clan->Member[CurMember] = NULL;
+      }
+    }
+
+    free(Clan);
+    Clan = NULL;
+  }
+
+  long MineFollowersGained ( _INT16 Level )
+  {
+    long NumFollowers = 0;
+
+    if (Level <= 5)
+      NumFollowers = 4 + RANDOM(3);
+    else if (Level > 5 && Level <= 10)
+      NumFollowers = 7 + RANDOM(3);
+    else if (Level > 10 && Level <= 15)
+      NumFollowers = 11 + RANDOM(3);
+    else if (Level > 15 && Level <= 20)
+      NumFollowers = 14 + RANDOM(3);
+
+    return NumFollowers;
+  }
+
+
+  void Fight_GiveFollowers( _INT16 Level )
+  {
+    long NumConscripted, NumFollowers;
+    char szString[128];
+
+    NumFollowers = MineFollowersGained(Level);
+    NumConscripted = (NumFollowers*Village.Data->ConscriptionRate)/100L;
+
+    if (NumFollowers || NumConscripted)
+    {
+      sprintf(szString, ST_FIGHTOVER1, NumFollowers, NumConscripted);
+      rputs(szString);
+    }
+
+    NumFollowers -= NumConscripted;
+    if (NumFollowers < 0)
+      NumFollowers = 0;
+
+    Village.Data->Empire.Army.Followers += NumConscripted;
+    PClan->Empire.Army.Followers += NumFollowers;
+
+  }
+
+  _INT16 GetOpenItemSlot ( struct clan *Clan )
+  {
+    // return -1 if no more open slots
+
+    _INT16 iTemp;
+
+    // see if he has room to carry it
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+    {
+      if (Clan->Items[iTemp].Available == FALSE)
+        break;
+    }
+    if (iTemp == MAX_ITEMS_HELD)
+    {
+      /* no more room in inventory */
+      return -1;
+    }
+    else
+      return iTemp;
+  }
+
+  void TakeItemsFromClan ( struct clan *Clan, char *szMsg )
+  {
+    _INT16 ItemIndex, OneItemFound, EmptySlot;
+    _INT16 DefaultItemIndex, iTemp, WhoEquip, ItemsTaken = 0;
+    char szString[100];
+    BOOL SomethingTaken = FALSE;
+
+    sprintf(szString, "You may take %d items from that clan.\n\r", MAX_ITEMSTAKEN);
+    rputs(szString);
+
+    for (;;)
+    {
+      rputs(ST_ISTATS0);
+
+      switch (od_get_answer("?XLQT\r\n "))
+      {
+        case '?' :
+          rputs("Help\n\n");
+          Help("Take Item Help", ST_MENUSHLP);
+          break;
+        case ' ' :
+        case '\r':
+        case '\n':
+        case 'Q' :
+          rputs("Quit\n");
+          return;
+        case 'T' :
+          // take an item
+          rputs("Take item\n");
+
+          EmptySlot = GetOpenItemSlot(PClan);
+          if (EmptySlot == -1)
+          {
+            rputs(ST_ITEMNOMOREROOM);
+            break;
+          }
+
+          if (ItemsTaken == MAX_ITEMSTAKEN)
+          {
+            rputs("You have already taken the maximum number of items.\n");
+            break;
+          }
+
+          ItemIndex = (_INT16) GetLong("|0STake which item?", 0, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          if (Clan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_INVALIDITEM);
+            break;
+          }
+
+          // take that item now
+          // if it is equipped, stop equipping it
+          if (Clan->Items[ItemIndex].UsedBy)
+          {
+            switch (Clan->Items[ItemIndex].cType)
+            {
+              case I_WEAPON :
+                Clan->Member[  Clan->Items[ItemIndex].UsedBy - 1 ]->Weapon = 0;
+                break;
+              case I_ARMOR :
+                Clan->Member[  Clan->Items[ItemIndex].UsedBy - 1 ]->Armor = 0;
+                break;
+              case I_SHIELD :
+                Clan->Member[  Clan->Items[ItemIndex].UsedBy - 1 ]->Shield = 0;
+                break;
+              }
+              Clan->Items[ItemIndex].UsedBy = 0;
+            }
+            // add it to our items
+            PClan->Items[EmptySlot] = Clan->Items[ItemIndex];
+
+            // get rid of it in theirs
+            Clan->Items[ItemIndex].Available = FALSE;
+
+            // increment counter
+            ItemsTaken++;
+
+            sprintf(szString, "%s taken!\n\r", Clan->Items[ItemIndex].szName);
+            rputs(szString);
+
+            // add onto szMsg
+            if (SomethingTaken == FALSE)
+            {
+              // nothing was taken before this item, means there is no
+              // header yet for szMsg
+              strcat(szMsg, "\n\n The following items were taken:\n\n");
+            }
+
+            SomethingTaken = TRUE;
+            sprintf(szString, " %s\n", Clan->Items[ItemIndex].szName);
+            strcat(szMsg, szString);
+            break;
+        case 'X' :  /* examine item */
+            rputs(ST_ISTATS1);
+
+          /* see if anything to examine */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (Clan->Items[iTemp].Available)
+						break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            rputs(ST_ISTATS2);
+            break;
+          }
+
+          /* find first item in inventory */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (Clan->Items[iTemp].Available)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            DefaultItemIndex = 1;
+          }
+          else
+            DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS3, DefaultItemIndex, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (Clan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+          ShowItemStats(&Clan->Items[ItemIndex], Clan);
+          break;
+        case 'L' :
+          rputs(ST_ISTATS5);
+          ListItems(Clan);
+          break;
+      }
+    }
+	(void)WhoEquip;
+	(void)OneItemFound;
+  }
+
+
+
+  void Fight_Clan( void )
+  {
+    struct clan *EnemyClan;
+    _INT16 ClanID[2], FightResult;
+    _INT16 iTemp, TotalDifficulty, CurMember;
+    char szString[128], *szMessage;
+
+    /* if all guys dead, tell guy can't fight */
+    if (NumMembers(PClan, TRUE) == 0)
+    {
+      rputs(ST_FIGHT0);
+      return;
+    }
+
+    rputs("|07Clans with Living Members:\n");
+    if (GetClanID( ClanID, TRUE, FALSE, -1, FALSE) == FALSE)
+    {
+      return;
+    }
+
+    /* see if already fought him today */
+    for (iTemp = 0; iTemp < MAX_CLANCOMBAT; iTemp++)
+    {
+      if (PClan->ClanCombatToday[iTemp][0] == ClanID[0] &&
+        PClan->ClanCombatToday[iTemp][1] == ClanID[1])
+      {
+        rputs(ST_FIGHTCLANALREADY);
+        return;
+      }
+    }
+
+    EnemyClan = MallocClan();
+
+    GetClan(ClanID, EnemyClan);
+
+    // if enemy clan is "away", don't fight
+    if (EnemyClan->WorldStatus == WS_GONE)
+    {
+      rputs("|07That clan is currently not in town.\n%P");
+      FreeClan(EnemyClan);
+      return;
+    }
+
+    // if enemy clan is all "dead", don't fight
+    if (NumMembers(EnemyClan, TRUE) == 0)
+    {
+      rputs("|07That clan currently has no living members.  You cannot fight them.\n%P");
+      FreeClan(EnemyClan);
+      return;
+    }
+
+    /* record fight so he can't do it again */
+    for (iTemp = 0; iTemp < MAX_CLANCOMBAT; iTemp++)
+    {
+      if (PClan->ClanCombatToday[iTemp][0] == -1)
+      {
+        break;
+      }
+    }
+    PClan->ClanCombatToday[iTemp][0] = ClanID[0];
+    PClan->ClanCombatToday[iTemp][1] = ClanID[1];
+
+    PClan->ClanFights--;
+
+    /* total difficulty for later on */
+    TotalDifficulty = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (EnemyClan->Member[iTemp])
+        TotalDifficulty += EnemyClan->Member[iTemp]->Level;
+    }
+
+    /* set all spells to 0 */
+    Spells_ClearSpells(PClan);
+    Spells_ClearSpells(EnemyClan);
+
+    /* fight 'em here using the function for fighting */
+    FightResult = Fight_Fight(PClan, EnemyClan, TRUE, FALSE, FALSE);
+
+    /* set all spells to 0 */
+    Spells_ClearSpells(PClan);
+    Spells_ClearSpells(EnemyClan);
+
+    // reset their HPs if they are alive
+    Fight_Heal(PClan);
+    Fight_Heal(EnemyClan);
+
+    RemoveUndead(PClan);
+    RemoveUndead(EnemyClan);
+
+    /* do stuff because of win/loss */
+
+    /* figure out number of followers from Difficulty of battle */
+    if (FightResult == FT_WON)
+    {
+      /* put in news you won */
+      sprintf(szString, ST_NEWSFIGHT1, EnemyClan->szName, PClan->szName);
+      News_AddNews(szString);
+
+      /* tell that guy about loss */
+      szMessage = MakeStr(500);
+      sprintf(szMessage, ST_NEWSFIGHT2, PClan->szName);
+
+      // allow user to take an item
+      TakeItemsFromClan(EnemyClan, szMessage);
+
+      GenericMessage(szMessage, EnemyClan->ClanID, PClan->ClanID, PClan->szName, FALSE);
+      free(szMessage);
+
+      /* give points for win in battle */
+      PClan->Points += 20;
+    }
+    else if (FightResult == FT_LOST)
+    {
+      /* put in news you lost */
+      sprintf(szString, ST_NEWSFIGHT3, PClan->szName, EnemyClan->szName);
+      News_AddNews(szString);
+
+      /* tell that guy about loss */
+      szMessage = MakeStr(500);
+      sprintf(szMessage, ST_NEWSFIGHT4, PClan->szName);
+      GenericMessage(szMessage, EnemyClan->ClanID, PClan->ClanID, PClan->szName, FALSE);
+      free(szMessage);
+
+      PClan->Points -= 15;
+    }
+    else
+    {
+      // ran away
+      /* put in news you lost */
+      sprintf(szString, ST_NEWSFIGHT5, PClan->szName, EnemyClan->szName);
+      News_AddNews(szString);
+
+      /* tell that guy about loss */
+      sprintf(szString, ST_NEWSFIGHT6, PClan->szName);
+      GenericMessage(szString, EnemyClan->ClanID, PClan->ClanID, PClan->szName, FALSE);
+
+      PClan->Points -= 20;
+    }
+
+    Clan_Update(EnemyClan);
+
+    /* get result of fight and do stuff */
+    FreeClan(EnemyClan);
+
+    /* fix it so they didn't run away */
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (PClan->Member[CurMember] && PClan->Member[CurMember]->Status == RanAway)
+        PClan->Member[CurMember]->Status = Here;
+    }
+
+    Fight_CheckLevelUp();
+    door_pause();
+  }
+
+  void Fight_Monster( _INT16 Level, char *szFileName )
+    /*
+     * Fights monster in the mines
+     *
+     */
+  {
+    unsigned long MemBefore;
+    _INT16 CurMember, FightResult;
+    struct clan *EnemyClan;
+
+
+#ifdef PRELAB
+    od_printf("@@Mem: %lu\n\r", MemBefore = farcoreleft());
+
+    rputs("Cheat ON\n");
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+      if (PClan->Member[CurMember])
+      {
+        PClan->Member[CurMember]->HP = PClan->Member[CurMember]->MaxHP;
+        PClan->Member[CurMember]->Status = Here;
+      }
+
+#endif
+
+    if (!PClan->CombatHelp)
+    {
+      PClan->CombatHelp = TRUE;
+      Help("Combat", ST_NEWBIEHLP);
+    }
+
+    // reduce # of fights left
+    PClan->FightsLeft--;
+
+    // load monsters into enemy clan
+
+    EnemyClan = MallocClan();
+    Fight_LoadMonsters(EnemyClan, Level, szFileName);
+
+
+    od_clr_scr();
+    FightResult = Fight_Fight ( PClan, EnemyClan, FALSE, TRUE, FALSE);
+
+    Fight_Heal(PClan);
+    Spells_ClearSpells(PClan);
+
+    RemoveUndead(PClan);
+
+    FreeClan(EnemyClan);
+
+    if (FightResult == FT_WON)
+    {
+      Fight_GiveFollowers(Level);
+
+      PClan->Points += 10;
+    }
+    else
+    {
+      // lose points -- same for running AND losing
+      PClan->Points -= 10;
+    }
+
+    // fix up status so players aren't set as running away
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (PClan->Member[CurMember] &&
+          PClan->Member[CurMember]->Status == RanAway)
+      {
+        PClan->Member[CurMember]->Status = Here;
+      }
+    }
+
+    Fight_CheckLevelUp();
+
+#ifdef PRELAB
+    od_printf("@@Mem: %lu, %lu\n\r", MemBefore, farcoreleft());
+#endif
+    (void)MemBefore;
+  }
diff --git a/src/doors/clans-src/fight.h b/src/doors/clans-src/fight.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3b8b5c858eb5bfc92ebb0a96b48a7b0e784ca00
--- /dev/null
+++ b/src/doors/clans-src/fight.h
@@ -0,0 +1,14 @@
+
+  void Fight_Monster( _INT16 Level, char *szFileName );
+
+  void FreeClan( struct clan *Clan );
+  struct clan *MallocClan ( void );
+
+  void Fight_CheckLevelUp ( void );
+
+  _INT16 Fight_Fight ( struct clan *Attacker, struct clan *Defender,
+                     BOOL HumanEnemy, BOOL CanRun, BOOL AutoFight );
+
+  void Fight_Clan( void );
+
+  void Fight_Heal ( struct clan *Clan );
diff --git a/src/doors/clans-src/game.c b/src/doors/clans-src/game.c
new file mode 100644
index 0000000000000000000000000000000000000000..cfad7ac2c31708b281ce59d0e95fe82b478a8200
--- /dev/null
+++ b/src/doors/clans-src/game.c
@@ -0,0 +1,201 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Game ADT (stores game instance data)
+ *
+ */
+
+
+#include <stdio.h>
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+#ifdef __FreeBSD__
+#include <stdlib.h>
+#else
+#include <malloc.h>
+#endif
+
+#include "system.h"
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "misc.h"
+#include "crc.h"
+#include "myopen.h"
+#include "news.h"
+#include "door.h"
+#include "video.h"
+
+struct game Game = { FALSE, NULL };
+extern struct system System;
+extern struct Language *Language;
+extern __BOOL Verbose;
+
+// ------------------------------------------------------------------------- //
+
+  __BOOL Game_Read ( void )
+    /*
+     * Reads in the GAME.DAT file.  If not found, returns FALSE.
+     */
+  {
+    FILE *fp;
+
+    fp = _fsopen("game.dat", "rb", SH_DENYWR);
+    if (!fp)  return FALSE;
+
+    EncryptRead(Game.Data, sizeof(struct game_data), fp, XOR_GAME);
+    fclose(fp);
+    return TRUE;
+  }
+
+  void Game_Write ( void )
+    /*
+     * Writes the game.dat file.
+     */
+  {
+    FILE *fp;
+
+    Game.Data->CRC = CRCValue(Game.Data, sizeof(struct game_data) - sizeof(long));
+
+    fp = _fsopen("game.dat", "wb", SH_DENYRW);
+    if (fp)
+    {
+      EncryptWrite(Game.Data, sizeof(struct game_data), fp, XOR_GAME);
+      fclose(fp);
+    }
+  }
+
+  void Game_Destroy ( void )
+    /*
+     * Frees mem held by Game
+     */
+  {
+    free(Game.Data);
+    Game.Initialized = FALSE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Game_Settings ( void )
+  {
+    char szString[128];
+
+    sprintf(szString, ST_GSETTINGS0, Game.Data->szDateGameStart);
+    rputs(szString);
+    /* REP:
+    sprintf(szString, ST_GSETTINGS1, Game.Data->EliminationMode ? "On" : "Off");
+    rputs(szString);
+    */
+    sprintf(szString, ST_GSETTINGS2, Game.Data->MaxPermanentMembers);
+    rputs(szString);
+
+    if (Game.Data->InterBBS)
+    {
+      sprintf(szString, ST_GSETTINGS3, Game.Data->ClanTravel ? "allowed" : "disabled");
+      rputs(szString);
+    }
+
+    sprintf(szString, ST_GSETTINGS4, Game.Data->ClanEmpires ? "allowed" : "disabled");
+    rputs(szString);
+
+    sprintf(szString, ST_GSETTINGS5, Game.Data->MineFights);
+    rputs(szString);
+    sprintf(szString, ST_GSETTINGS6, Game.Data->ClanFights);
+    rputs(szString);
+    sprintf(szString, ST_GSETTINGS7, Game.Data->DaysOfProtection);
+    rputs(szString);
+    door_pause();
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void Game_Start ( void )
+    /*
+     * Function is called when the game starts up for FIRST time (i.e. when
+     * the StartGameDate is reached.
+     */
+  {
+    // this sets up all the necessary stuff to start the game
+    News_AddNews(ST_NEWSLOCALRESET);
+    Game.Data->GameState = 0;
+
+    Game_Write();
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void Game_Init ( void )
+    /*
+     * Initializes Game by reading in the GAME.DAT file.  If file not found,
+     * outputs error message and returns to DOS.
+     */
+  {
+    if (Verbose)
+    {
+      DisplayStr("> Game_Init()\n");
+      delay(500);
+    }
+
+    Game.Data = malloc(sizeof(struct game_data));
+    CheckMem(Game.Data);
+    Game.Initialized = TRUE;
+
+    if (!Game_Read())
+    {
+      Game_Destroy();
+      System_Error("GAME.DAT not found!  Please run reset.exe\n");
+    }
+
+    // ensure CRC is correct
+    if (CheckCRC(Game.Data, sizeof(struct game_data) - sizeof(long), Game.Data->CRC) == FALSE)
+    {
+      Game_Destroy();
+      System_Error("Game data corrupt!\n");
+    }
+
+    // If game has not yet begun and is waiting for day to start
+    if (Game.Data->GameState == 1)
+    {
+      // if today is game's start date
+      if (DaysBetween(Game.Data->szDateGameStart, System.szTodaysDate) >= 0)
+      {
+        // today is the start of new game
+        Game_Start();
+      }
+    }
+  }
+
+  void Game_Close ( void )
+    /*
+     * Deinitializes Game.
+     */
+  {
+    if (Game.Initialized == FALSE) return;
+
+    Game_Write();
+    Game_Destroy();
+  }
diff --git a/src/doors/clans-src/game.h b/src/doors/clans-src/game.h
new file mode 100644
index 0000000000000000000000000000000000000000..b85e49c2d39d6e7127d6139f4a376ea414e4a267
--- /dev/null
+++ b/src/doors/clans-src/game.h
@@ -0,0 +1,15 @@
+
+  void Game_Init ( void );
+    /*
+     * Initializes Game by reading in the GAME.DAT file.  If file not found,
+     * outputs error message and returns to DOS.
+     */
+
+  void Game_Close ( void );
+    /*
+     * Deinitializes Game.
+     */
+
+  void Game_Settings ( void );
+
+  void Game_Start ( void );
diff --git a/src/doors/clans-src/gpl.txt b/src/doors/clans-src/gpl.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5b6e7c66c276e7610d4a73c70ec1a1f7c1003259
--- /dev/null
+++ b/src/doors/clans-src/gpl.txt
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/doors/clans-src/help.c b/src/doors/clans-src/help.c
new file mode 100644
index 0000000000000000000000000000000000000000..86f438570fc21433420c761d0087d61aff69c2f2
--- /dev/null
+++ b/src/doors/clans-src/help.c
@@ -0,0 +1,337 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#include <sys/mman.h>
+#include <termios.h>
+#endif
+
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "input.h"
+#include "myopen.h"
+#include "door.h"
+
+extern struct Language *Language;
+
+// ------------------------------------------------------------------------- //
+
+
+  void Help ( char *Topic, char *File )
+    /*
+     * Given the Topic and File, the help is shown.
+     */
+  {
+    char *Lines[22], *string;
+    _INT16 cTemp, Found = FALSE, CurLine, NumLines;
+    long MaxBytes;
+    BOOL EndOfTopic = FALSE, Pause = FALSE;
+    struct FileHeader FileHeader;
+
+
+    // fp = fopen(File, "r");
+    MyOpen(File, "rt", &FileHeader);
+    if (!FileHeader.fp)
+    {
+      rputs(ST_NOHELP);
+      return;
+    }
+
+    for (cTemp = 0; cTemp < 22; cTemp++)
+    {
+      Lines[cTemp] = malloc(255);
+      CheckMem(Lines[cTemp]);
+    }
+
+    string = MakeStr(255);
+
+    /* search for topic */
+    while (!Found)
+    {
+      MaxBytes = FileHeader.lEnd - ftell(FileHeader.fp) + EXTRABYTES;
+      if (MaxBytes > 254)
+        MaxBytes = 254;
+
+      if (fgets(string, (_INT16) MaxBytes, FileHeader.fp) == NULL)
+      {
+        fclose(FileHeader.fp);
+        rputs(ST_NOHELP);
+        rputs("\n");
+
+        for (cTemp = 0; cTemp < 22; cTemp++)
+          free(Lines[cTemp]);
+        free(string);
+        return;
+      }
+
+      if (string[0] == '^')
+      {
+        // get rid of \n
+        if (string[ strlen(string) - 1] == '\n')
+          string[ strlen(string) - 1] = 0;
+        if (string[ strlen(string) - 1] == '\r')
+          string[ strlen(string) - 1] = 0;
+
+        /* see if topic is correct */
+        // if (strspn(&string[1], Topic) == strlen(Topic))
+        if (stricmp(&string[1], Topic) == 0)
+        {
+          Found = TRUE;
+        }
+      }
+    }
+
+    while (EndOfTopic == FALSE)
+    {
+      /* read in up to 22 lines */
+      for (CurLine = 0; CurLine < 22; CurLine++)
+      {
+        MaxBytes = FileHeader.lEnd - ftell(FileHeader.fp) + EXTRABYTES;
+
+        if (MaxBytes > 254)
+          MaxBytes = 254;
+
+        if (MaxBytes == 1)
+          break;
+
+        fgets(Lines[CurLine], (_INT16)MaxBytes, FileHeader.fp);
+
+        // Lines[CurLine][ MaxBytes - EXTRABYTES + 1] = 0;
+
+        if (Lines[CurLine][0] == '^')
+        {
+          // get rid of \n
+          if (Lines[CurLine][ strlen(Lines[CurLine]) - 1] == '\n')
+            Lines[CurLine][ strlen(Lines[CurLine]) - 1] = 0;
+          if (Lines[CurLine][ strlen(Lines[CurLine]) - 1] == '\r')
+            Lines[CurLine][ strlen(Lines[CurLine]) - 1] = 0;
+
+          if (stricmp(&Lines[CurLine][1], ST_HELPEND) == 0)
+          {
+            EndOfTopic = TRUE;
+            break;
+          }
+          else if (stricmp(&Lines[CurLine][1], ST_HELPPAUSE) == 0)
+          {
+            Pause = TRUE;
+            break;
+          }
+        }
+      }
+      NumLines = CurLine;
+
+      /* display it */
+      for (CurLine = 0; CurLine < NumLines; CurLine++)
+      {
+        // break on input
+        if (od_get_key(FALSE))
+        {
+          rputs(ST_ABORTED);
+          break;
+        }
+
+        rputs(Lines[CurLine]);
+      }
+
+      if (Pause)
+      {
+        door_pause();
+        Pause = FALSE;
+      }
+      /* else pause normally if 22 lines */
+      else if (CurLine == 22 && Door_AllowScreenPause() )
+      {
+        rputs(ST_MORE);
+        od_sleep(0);
+        if (toupper(od_get_key(TRUE)) == 'N')
+        {
+          rputs("\r                       \r");
+          break;
+        }
+        rputs("\r                       \r");
+
+        CurLine = 0;
+      }
+    }
+
+    fclose(FileHeader.fp);
+
+    for (cTemp = 0; cTemp < 22; cTemp++)
+      free(Lines[cTemp]);
+    free(string);
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void GeneralHelp ( char *pszFileName )
+    /*
+     * Given the File, all help topics are shown and user can freely choose
+     * and read them.
+     */
+  {
+    char *Topics[50], *Line;
+    _INT16 NumTopics, cTemp, WhichTopic, iTemp;
+    long MaxBytes;
+    struct FileHeader HelpFile;
+    __BOOL ShowInitially;
+
+    /* read the topics in */
+    // fpHelpFile = fopen(pszFileName, "rt");
+    MyOpen(pszFileName, "rt", &HelpFile);
+    if (!HelpFile.fp)
+    {
+      rputs(ST_NOHELPFILE);
+      return;
+    }
+
+    Line = MakeStr(255);
+
+    for (iTemp = 0; iTemp < 50; iTemp++)
+      Topics[iTemp] = NULL;
+
+    NumTopics = 0;
+    for(;;)
+    {
+      // see if end of file
+      if ( ftell(HelpFile.fp) >= HelpFile.lEnd )
+      {
+        break;
+      }
+
+      // od_printf("%ld  %ld\n", ftell(HelpFile.fp), HelpFile.lEnd);
+
+      // get how many more bytes to read as max
+      MaxBytes = HelpFile.lEnd - ftell(HelpFile.fp) + EXTRABYTES;
+      if (MaxBytes > 254)
+        MaxBytes = 254;
+
+      if (MaxBytes == 1)
+      {
+        break;
+      }
+
+      if (fgets(Line, (_INT16) MaxBytes, HelpFile.fp) == NULL)
+      {
+        break;
+      }
+
+      // Line[ MaxBytes - EXTRABYTES + 1] = 0;
+
+      if (Line[0] == '^')
+      {
+        /* get rid of \n */
+        if (Line[ strlen(Line) - 1] == '\n')
+          Line[ strlen(Line) - 1] = 0;
+        if (Line[ strlen(Line) - 1] == '\r')
+          Line[ strlen(Line) - 1] = 0;
+
+        if (stricmp(&Line[1], ST_HELPPAUSE) == 0)
+          continue; /* skip it, it's a pause */
+        else if (stricmp(&Line[1], ST_HELPEND) != 0)
+        {
+          Topics[NumTopics] = MakeStr(strlen(&Line[1]) + 1);
+          strcpy(Topics[NumTopics], &Line[1]);
+          NumTopics++;
+        }
+      }
+    }
+
+    fclose(HelpFile.fp);
+
+    ShowInitially = TRUE;
+    for (;;)
+    {
+      // choose which topic
+      GetStringChoice (Topics, NumTopics, ST_HELPHINT, &WhichTopic, ShowInitially, DT_WIDE, TRUE);
+      ShowInitially = FALSE;
+
+      if (WhichTopic == -1)
+        break;
+
+      Help(Topics[WhichTopic], pszFileName);
+      rputs("\n");
+    }
+
+    /* free memory */
+    for (cTemp = 0; cTemp < NumTopics; cTemp++)
+    {
+      if (Topics[cTemp])
+        free(Topics[cTemp]);
+    }
+    free(Line);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void MainHelp ( void )
+    /*
+     * The main help database (from PreGame menu).
+     *
+     */
+  {
+    char *szAvailableTopics[9] = {
+      "Items",
+      "Races and Classes",
+      "General Help",
+      "Combat",
+      "Strategy",
+      "Newbie Help",
+      "Stats Help",
+      "Quit",
+      "Redisplay Menu"};
+    char *szFiles[7];
+    _INT16 iTemp;
+
+    szFiles[0] = ST_ITEMHLP;
+    szFiles[1] = ST_RACESHLP;
+    szFiles[2] = ST_CLANSHLP;
+    szFiles[3] = ST_COMBATHLP;
+    szFiles[4] = ST_STRATHLP;
+    szFiles[5] = ST_NEWBIEHLP;
+    szFiles[6] = ST_STATSHLP;
+
+    /* choose main topic */
+    for (;;)
+      switch(iTemp = GetChoice("Help Menu", "|0GChoose Help Topic|0E> |0F", szAvailableTopics, "1234567Q?", 'Q', TRUE))
+      {
+        case '1' :
+        case '2' :
+        case '3' :
+        case '4' :
+        case '5' :
+        case '6' :
+        case '7' :
+          GeneralHelp( szFiles[ iTemp - '1' ] );
+          break;
+        case 'Q' :
+          return;
+        case '?' :
+          break;
+      }
+  }
diff --git a/src/doors/clans-src/help.h b/src/doors/clans-src/help.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdfd3efd8139d781a24ebfe8e00c91b8ae45f411
--- /dev/null
+++ b/src/doors/clans-src/help.h
@@ -0,0 +1,17 @@
+
+  void MainHelp ( void );
+    /*
+     * The main help database (from PreGame menu).
+     *
+     */
+
+  void Help ( char *Topic, char *File );
+    /*
+     * Given the Topic and File, the help is shown.
+     */
+
+  void GeneralHelp ( char *pszFileName );
+    /*
+     * Given the File, all help topics are shown and user can freely choose
+     * and read them.
+     */
diff --git a/src/doors/clans-src/ibbs.c b/src/doors/clans-src/ibbs.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f0ca46fd4cb378c2ee130bb30c73f286e8eed4f
--- /dev/null
+++ b/src/doors/clans-src/ibbs.c
@@ -0,0 +1,3664 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * IBBS ADT
+ *
+ * Portions of this code are taken from the IBBS samples provided
+ * by Brian Pirie for the OpenDoors library.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifndef __unix__
+#include <malloc.h>
+#endif
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <dos.h>
+#include <share.h>
+#ifndef _MSC_VER
+# include <dir.h>
+#else
+# include <io.h>
+#endif
+#endif
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "video.h"
+#include "k_ibbs.h"
+#include "parsing.h"
+#include "system.h"
+#include "myopen.h"
+#include "packet.h"
+#include "interbbs.h"
+#include "misc.h"
+#include "door.h"
+#include "news.h"
+#include "mail.h"
+#include "scores.h"
+#include "game.h"
+#include "fight.h"
+#include "user.h"
+#include "empire.h"
+#include "input.h"
+#include "help.h"
+#include "village.h"
+#include "alliance.h"
+#include "myibbs.h"
+
+#define MT_NORMAL 		0
+#define MT_CRASH		1
+#define MT_HOLD 		2
+
+#define RECONDAYS		5
+
+#ifdef _WIN32
+int findfirst(const char *, struct ffblk *, int);
+int findnext(struct ffblk *);
+void convert_attribute(char *, DWORD);
+int search_and_construct_ffblk(WIN32_FIND_DATA *, struct ffblk *, BOOL);
+
+struct ffblk {
+	char ff_reserved[21];
+	char ff_attrib;
+	unsigned short ff_ftime;
+	unsigned short ff_fdate;
+	long ff_fsize;
+	char ff_name[13];
+	HANDLE ff_findhandle; /* Added for Win32's API */
+	char   ff_findattribute; /* Added for attribute matching on Win32 */
+};
+
+#ifndef _A_VOLID
+# define _A_VOLID 0x08 /* not normally used in Win32 */
+#endif
+
+/* File Attributes */
+#define FA_NORMAL _A_NORMAL /* 0x00 */
+#define FA_RDONLY _A_RDONLY /* 0x01 */
+#define FA_HIDDEN _A_HIDDEN /* 0x02 */
+#define FA_SYSTEM _A_SYSTEM /* 0x04 */
+#define FA_LABEL  _A_VOLID  /* 0x08 */
+#define FA_DIREC  _A_SUBDIR /* 0x10 */
+#define FA_ARCH   _A_ARCH   /* 0x20 */
+#endif
+
+extern struct clan *PClan;
+extern struct config *Config;
+extern struct Language *Language;
+extern struct game Game;
+extern struct system System;
+extern struct village Village;
+extern struct BuildingType BuildingType[NUM_BUILDINGTYPES];
+extern BOOL Verbose;
+
+struct ibbs IBBS = { FALSE, NULL };
+BOOL NoMSG[MAX_IBBSNODES];
+
+void IBBS_SendPacketFile ( _INT16 DestID, char *pszSendFile );
+void IBBS_AddToGame( struct clan *Clan, BOOL WasLost );
+void IBBS_SendPacket ( _INT16 PacketType, long PacketLength, void *PacketData,
+                          _INT16 DestID );
+_INT16 file_copy(char *from, char *to);
+_INT16 file_append(char *from, char *to);
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Open file specified, copy entire contents and send as data in packet with
+   the type specified in 'PacketType' to 'DestID'
+*/
+  void IBBS_SendFileInPacket ( _INT16 DestID, _INT16 PacketType, char *szFileName )
+  {
+    FILE *fp;
+    char *cpBuffer;
+    _INT16 CurBBS;
+    long lFileSize;
+
+    if (IBBS.Initialized == FALSE)
+    {
+      System_Error("IBBS not initialized for call.\n");
+    }
+
+    fp = _fsopen(szFileName, "rb", SH_DENYRW);
+    if (!fp)
+      return;
+
+    // find out length of file
+    fseek(fp, 0L, SEEK_END);
+    lFileSize = ftell(fp);
+
+    // allocate memory for it
+    cpBuffer = malloc(lFileSize);
+    CheckMem(cpBuffer);
+
+    // now read it in
+    fseek(fp, 0L, SEEK_SET);
+    fread(cpBuffer, lFileSize, sizeof(char), fp);
+
+    fclose(fp);
+
+    IBBS_SendPacket (PacketType, lFileSize, cpBuffer, DestID);
+
+    free(cpBuffer);
+	(void)CurBBS;
+  }
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Make sure destination ID is valid, send userlist.dat to that BBS
+*/
+  void IBBS_SendUserList ( _INT16 DestID )
+  {
+    //printf("Sending userlist to %d\n", DestID);
+    if (IBBS.Data->Nodes[DestID-1].Active)
+        IBBS_SendFileInPacket(DestID, PT_ULIST, "userlist.dat");
+  }
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Copy the entire world.ndx file.
+   Cycle the BBS List and send the world.ndx to all active nodes.  Do not
+   send it to this BBS
+*/  
+  void IBBS_DistributeNDX ( void )
+  {
+    FILE *fpNDX;
+    char *cpBuffer;
+    _INT16 CurBBS;
+    long lFileSize;
+
+    DisplayStr("Distributing new NDX file, please wait...\n");
+
+    fpNDX = fopen("world.ndx", "rb");
+    if (!fpNDX)
+    {
+      DisplayStr("world.ndx not found!\n");
+      return;
+    }
+
+    // find out length of file
+    fseek(fpNDX, 0L, SEEK_END);
+    lFileSize = ftell(fpNDX);
+
+    // allocate memory for it
+    cpBuffer = malloc(lFileSize);
+    CheckMem(cpBuffer);
+
+    // now read it in
+    fseek(fpNDX, 0L, SEEK_SET);
+    fread(cpBuffer, lFileSize, sizeof(char), fpNDX);
+
+    fclose(fpNDX);
+
+    for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+    {
+      if (IBBS.Data->Nodes[CurBBS].Active == FALSE)
+        continue;
+
+      // skip if it's your own BBS
+      if (CurBBS+1 == IBBS.Data->BBSID)
+        continue;
+
+      IBBS_SendPacket (PT_NEWNDX, lFileSize, cpBuffer, CurBBS+1);
+    }
+
+    free(cpBuffer);
+  }
+
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Cycle the BBS List to find all active nodes.  If the BBSID of the current
+   entry does not equal this BBS's ID, send a packet containing type of
+   PT_SUBUSER and the passed UserInfo structure as the data.  Note: BBSIDs are
+   1 based, not zero.
+*/
+  void LeagueKillUser ( struct UserInfo *User )
+  {
+    // create packet for all BBSes saying "this user just committed suicide
+    // on my board so remove him from your userlist"
+    _INT16 CurBBS;
+
+    // for each BBS in the list, send him a packet
+    // must skip BBS #1 since that's this BBS (main BBS)
+    for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+    {
+      if (IBBS.Data->Nodes[CurBBS].Active == FALSE)
+        continue;
+
+      // skip if it's your own BBS
+      if (CurBBS+1 == IBBS.Data->BBSID)
+        continue;
+
+      IBBS_SendPacket(PT_SUBUSER, sizeof(struct UserInfo), User, CurBBS+1);
+    }
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   [TargetType]
+   - EO_VILLAGE:  Copy the village's name to the result target name
+   - EO_CLAN   :  Verify Clan exists, if not set target as "-No longer exists-"
+                  otherwise set target as name.
+   Copy today's date to the result packet's date.
+   Copy identifications from the attempt packet to the result packet
+   This includes MasterID, ClanID and the BBSFrom/ToID.
+   Do a random between the spy's intelligence level and the building's security
+   level, if it's greater then set success and copy empire data.  Otherwise:
+     If target was Village, send a message to ruler that a spy was caught.
+     If target was clan, send a message to the clan that a spy was caught.
+     Set the result packet success as FALSE.
+   Send an InterBBS packet as PT_SPYRESULT, SpyResultPacket as the data.
+*/
+  void IBBS_ProcessSpy( struct SpyAttemptPacket *Spy )
+  {
+    struct SpyResultPacket SpyResult;
+    struct Packet Packet;
+    struct empire *Empire = NULL;
+    struct clan *TmpClan;
+    BOOL NoTarget = FALSE;
+    char *szMessage;
+    _INT16 Junk[2];
+    FILE *fp;
+
+    szMessage = MakeStr(600);
+    TmpClan = NULL;
+
+    // load up empire
+    switch(Spy->TargetType)
+    {
+      case EO_VILLAGE :
+        Empire = &Village.Data->Empire;
+        strcpy(SpyResult.szTargetName, Empire->szName);
+        break;
+      case EO_CLAN :
+        TmpClan = malloc(sizeof(struct clan));
+        CheckMem(TmpClan);
+        if (GetClan(Spy->ClanID, TmpClan) == FALSE)
+        {
+          NoTarget = TRUE;
+          strcpy(SpyResult.szTargetName, "-No longer exists-");
+        }
+        else
+          strcpy(SpyResult.szTargetName, TmpClan->Empire.szName);
+        Empire = &TmpClan->Empire;
+        break;
+    }
+
+    strcpy(SpyResult.szTheDate, System.szTodaysDate);
+    SpyResult.MasterID[0] = Spy->MasterID[0];
+    SpyResult.MasterID[1] = Spy->MasterID[1];
+    SpyResult.BBSFromID = Spy->BBSFromID;
+    SpyResult.BBSToID = Spy->BBSToID;
+
+    if ( NoTarget == FALSE && (Spy->IntelligenceLevel+RANDOM(5)) >
+      (Empire->Buildings[B_SECURITY]+RANDOM(3)) )
+    {
+      // success
+      SpyResult.Success = TRUE;
+      SpyResult.Empire = *Empire;
+    }
+    else
+    {
+      // failure if no target OR otherwise
+      SpyResult.Success = FALSE;
+
+      if (Spy->TargetType == EO_VILLAGE)
+      {
+        // sprintf(szMessage, " You caught a spy attempting to gain info on the village's empire.\n The spy was from %s.\n",
+        sprintf(szMessage, ST_SPY4, Spy->szSpierName);
+        GenericMessage(szMessage, Village.Data->RulingClanId, Junk, "", FALSE);
+      }
+      else if (Spy->TargetType == EO_CLAN && NoTarget == FALSE)
+      {
+        // sprintf(szMessage, " You caught a spy attempting to gain info on the village's empire.\n The spy was from %s.\n",
+        sprintf(szMessage, ST_SPY6, Spy->szSpierName);
+        GenericMessage(szMessage, TmpClan->ClanID, Junk, "", FALSE);
+      }
+    }
+
+    if (TmpClan)
+      FreeClan(TmpClan);
+
+    free(szMessage);
+
+    IBBS_SendPacket ( PT_SPYRESULT, sizeof(struct SpyResultPacket), &SpyResult,
+                          Spy->BBSFromID);
+	(void)Packet;
+	(void)fp;
+  }
+
+/* Function Procedure:
+   If the attempt was successful:
+     Send a message to the spier with the following information:
+     - Name of Target
+     - VaultGold
+     - Land
+     - All Army Stats (Troops and Statistics)
+     - All Building types and their names
+   else
+     Send failure message to spier
+*/
+  void IBBS_ProcessSpyResult( struct SpyResultPacket *SpyResult )
+  {
+    char *szMessage, szString[128];
+    _INT16 Junk[2], iTemp;
+
+    szMessage = MakeStr(600);
+
+
+    if (SpyResult->Success)
+    {
+      // sprintf(szMessage, "Your spies sent to %s were successful and return with information:\n\nGold:  %ld\nLand:  %d\n\nTroops:  %ld footmen, %ld axemen, %ld knights\n\nBuildings:",
+      sprintf(szMessage, ST_SPY7, SpyResult->Empire.szName,
+        SpyResult->Empire.VaultGold,
+        SpyResult->Empire.Land, SpyResult->Empire.Army.Footmen,
+        SpyResult->Empire.Army.Axemen, SpyResult->Empire.Army.Knights,
+        ArmySpeed(&SpyResult->Empire.Army),
+        ArmyOffense(&SpyResult->Empire.Army),
+        ArmyDefense(&SpyResult->Empire.Army),
+        ArmyVitality(&SpyResult->Empire.Army));
+
+      // buildings now
+
+      for (iTemp = 0; iTemp < NUM_BUILDINGTYPES; iTemp++)
+      {
+        if (SpyResult->Empire.Buildings[iTemp] == 0)
+          continue;
+
+        sprintf(szString, " %2d %s\n", SpyResult->Empire.Buildings[iTemp],
+          BuildingType[iTemp].szName);
+        strcat(szMessage, szString);
+      }
+
+      GenericMessage(szMessage, SpyResult->MasterID, Junk, "", FALSE);
+    }
+    else
+    {
+      sprintf(szMessage, "Your spy attempt on %s failed.\n", SpyResult->szTargetName);
+
+      GenericMessage(szMessage, SpyResult->MasterID, Junk, "", FALSE);
+    }
+
+    free(szMessage);
+  }
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   If the BBS specified is active, sent the type:
+   PT_DELUSER with UserInfo structure attached.  This tells the recipient BBS
+   to remove the user with the ID specified.
+*/
+  void IBBS_SendDelUser(_INT16 BBSID, struct UserInfo *User)
+  {
+    // run ONLY by main bbs
+    // this will send a packet to a given bbs, telling the bbs to delete
+    // the user with the clanid supplied
+
+    if (IBBS.Data->Nodes[BBSID-1].Active)
+        IBBS_SendPacket (PT_DELUSER, sizeof(struct UserInfo), User, BBSID);
+  }
+
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Scan USERLIST.DAT for the specified ClanID, if found return TRUE, else FALSE
+*/
+  BOOL ClanIDInList( _INT16 ClanID[2] )
+  {
+    FILE *fpUList;
+    BOOL Found = FALSE;
+    struct UserInfo User;
+
+    fpUList = _fsopen("userlist.dat", "rb", SH_DENYWR);
+    if (!fpUList)
+    {
+      // no user list found, assume not in list then
+      return FALSE;
+    }
+
+    // scan through file until end
+    for (;;)
+    {
+      if (EncryptRead(&User, sizeof(struct UserInfo), fpUList, XOR_ULIST) == 0)
+        break;
+
+      // see if this user's name is same as one we're looking for
+      if (User.ClanID[0] == ClanID[0] && User.ClanID[1] == ClanID[1])
+      {
+        Found = TRUE;
+        break;
+      }
+    }
+
+    fclose(fpUList);
+
+    return Found;
+  }
+/* Function Procedure:
+  Verify the ClanID is on this system, otherwise ignore call
+  Read all the users in USERLIST.DAT; find and remove the specified Clan.
+*/
+  void RemoveFromUList(_INT16 ClanID[2])
+  {
+    // open file for r+b
+    // scan file for ClanID
+    // set user as deleted
+    // close file
+
+    FILE *fpOldUList, *fpNewUList;
+    struct UserInfo User;
+
+    // if this guy is NOT in our list, then we don't need to do this
+    if (ClanIDInList(ClanID) == FALSE)
+      return;
+
+    // open user file
+    fpOldUList = _fsopen("userlist.dat", "rb", SH_DENYWR);
+    if (!fpOldUList)    // no user list at all
+        return;
+
+    fpNewUList = _fsopen("tmp.$$$", "wb", SH_DENYRW);
+    // FIXME: assume file is opened
+
+    for (;;)
+    {
+      if (EncryptRead(&User, sizeof(struct UserInfo), fpOldUList, XOR_ULIST) == 0)
+        break;
+
+//    printf("Read in %s\n", User.szName);
+
+      // for each user in file, see if same as ClanID
+      if (User.ClanID[0] == ClanID[0] && User.ClanID[1] == ClanID[1])
+      {
+        //printf("skipping over %s\n", User.szName);
+        // same, skip over him
+        continue;
+      }
+
+      // otherwise, don't skip him, write him to new file
+      EncryptWrite(&User, sizeof(struct UserInfo), fpNewUList, XOR_ULIST);
+    }
+
+    // close file
+    fclose(fpOldUList);
+    fclose(fpNewUList);
+
+    // rename file
+    unlink("userlist.dat");
+    rename("tmp.$$$", "userlist.dat");
+  }
+/* Function Procedure:
+   If the user is not already in the userlist, open USERLIST.DAT.
+   Append the User to the end of the userlist.
+*/
+  void AddToUList( struct UserInfo *User )
+  {
+    FILE *fpUList;
+
+    // if this clan is in the list, don't bother
+    if (ClanIDInList(User->ClanID))
+      return;
+
+    //printf("Adding %s to file\n", User->szName);
+
+    // open user file
+    fpUList = _fsopen("userlist.dat", "ab", SH_DENYWR);
+    if (!fpUList)
+        return;
+
+    // append to file
+    EncryptWrite(User, sizeof(struct UserInfo), fpUList, XOR_ULIST);
+
+    // close file
+    fclose(fpUList);
+  }
+/* Function Procedure:
+   Cycle the BBS list, send the specified user to all active nodes with the
+   packet type: PT_ADDUSER
+*/
+  void UpdateNodesOnNewUser ( struct UserInfo *User )
+  {
+    // run ONLY by main bbs
+    // create packet for all BBSes saying "Here's a new user, add him to your
+    // userlist"
+    FILE *fp;
+    _INT16 CurBBS;
+
+    // for each BBS in the list, send him a packet
+    // must skip BBS #1 since that's this BBS (main BBS)
+    for (CurBBS = 1; CurBBS < MAX_IBBSNODES; CurBBS++)
+    {
+      if (IBBS.Data->Nodes[CurBBS].Active == FALSE)
+        continue;
+
+      IBBS_SendPacket (PT_ADDUSER, sizeof(struct UserInfo), User, CurBBS+1);
+    }
+	(void)fp;
+  }
+
+/* Function Procedure:
+   If user is not on this board add them.
+   If this BBS is not the main BBS, send the packet to the LC with type of PT_NEWUSER
+   If this is the main BBS, call UpdateNodesOnNewUser, which tells all the BBSes about
+   the user.
+*/
+  void IBBS_LeagueNewUser ( struct UserInfo *User )
+  {
+    struct Packet Packet;
+    FILE *fp;
+
+    // add this user to THIS bbs's user list now
+    AddToUList(User);
+
+    // if this is a node only
+    if (IBBS.Data->BBSID != 1)
+    {
+      IBBS_SendPacket ( PT_NEWUSER, sizeof(struct UserInfo), User, 1);
+    }
+    else
+    {
+      // if this is the main BBS, we DO NOT need to process him as the other
+      // boards do since WE have the full list of players in the league already
+      // assuming he got this far, his name was not yet on the list
+      // and assuming WE got this far, then we already added him to our user
+      // list, so we don't need to do that again, so all we need to do is send
+      // a packet to all our other boards in the league saying "add this dude
+      // to your user list"
+
+      UpdateNodesOnNewUser(User);
+    }
+	(void)fp;
+	(void)Packet;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Check USERLIST.DAT for either ClanName or UserName that matches szName
+   If found, return TRUE else FALSE
+*/
+  BOOL IBBS_InList( char *szName, BOOL ClanName )
+  {
+    // this and the other functions are ONLY used in InterBBS games.
+    // they are NOT used in local games since they are redundant
+
+    // returns TRUE if user (either clan name or username) is already in
+    // the list
+
+    // if you have a user who's data isn't in this BBS's .PC file, run this
+    // and if it returns TRUE, it must mean the user is already playing on
+    // another BBS
+
+    // use this for new users who choose clan name, if already in use, tell
+    // him after return TRUE
+
+    FILE *fpUList;
+    BOOL Found = FALSE;
+    struct UserInfo User;
+
+    fpUList = _fsopen("userlist.dat", "rb", SH_DENYWR);
+    if (!fpUList)
+    {
+      // no user list found, assume not in list then
+      return FALSE;
+    }
+
+    // scan through file until end
+    for (;;)
+    {
+      if (EncryptRead(&User, sizeof(struct UserInfo), fpUList, XOR_ULIST) == 0)
+        break;
+
+      // see if this user's name is same as one we're looking for
+      if (ClanName)
+      {
+        if (stricmp(User.szName, szName) == 0)
+        {
+          Found = TRUE;
+          break;
+        }
+      }
+      else
+      {
+        // compare with player's name
+        if (stricmp(User.szMasterName, szName) == 0)
+        {
+          Found = TRUE;
+          break;
+        }
+      }
+    }
+
+    fclose(fpUList);
+
+    return Found;
+  }
+
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Create a packet that contains the ClanID and the BBSID for the data.
+   Packet type will be PT_COMEBACK it is sent to the specified bbs id, it is
+   sent from this bbs.  The packet is from an Active BBS, specifying today's
+   date and this game's id.
+*/
+  void IBBS_SendComeBack( _INT16 BBSIdTo, struct clan *Clan )
+  {
+    // write packet
+    struct Packet Packet;
+    FILE *fp;
+
+    /* create packet header */
+    Packet.Active = TRUE;
+    Packet.BBSIDFrom = IBBS.Data->BBSID;
+    Packet.BBSIDTo = BBSIdTo;
+    Packet.PacketType = PT_COMEBACK;
+    strcpy(Packet.szDate, System.szTodaysDate);
+    Packet.PacketLength = sizeof(_INT16)*3;
+    strcpy(Packet.GameID, Game.Data->GameID);
+
+    fp = _fsopen("tmp.$$$", "wb", SH_DENYWR);
+    if (!fp) return;
+
+    /* write packet */
+    EncryptWrite(&Packet, sizeof(struct Packet), fp, XOR_PACKET);
+
+    // write info
+    EncryptWrite(Clan->ClanID, 2*sizeof(_INT16), fp, XOR_PACKET);
+    EncryptWrite(&IBBS.Data->BBSID, sizeof(_INT16), fp, XOR_PACKET);
+
+    fclose(fp);
+
+    // send packet to BBS
+    IBBS_SendPacketFile(Packet.BBSIDTo, "tmp.$$$");
+    unlink("tmp.$$$");
+  }
+
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Check the AttackPacket Type:
+   If EO_VILLAGE:
+      szAttackerName = "This village"
+      Increase Footmen by Attacking army's Footmen
+      Increase Axemen by Attacking army's Axemen
+      Increase Knights by Attacking army's Knights
+   If EO_CLAN:
+      szAttackerName = "Your clan"
+      If Clan found in database, increase Footmen, Axemen, and Knights of clan.
+   Write message to attacker that their army has lost but returned.
+*/
+  void ReturnLostAttack ( struct AttackPacket *AttackPacket )
+  {
+    struct clan *TmpClan;
+    char *szMessage, szAttackerName[20];
+    _INT16 WhichBBS, iTemp, Junk[2];
+
+    switch (AttackPacket->AttackingEmpire.OwnerType)
+    {
+      case EO_VILLAGE :
+        strcpy(szAttackerName, "This village");
+        Village.Data->Empire.Army.Footmen += AttackPacket->AttackingArmy.Footmen;
+        Village.Data->Empire.Army.Axemen  += AttackPacket->AttackingArmy.Axemen;
+        Village.Data->Empire.Army.Knights += AttackPacket->AttackingArmy.Knights;
+        break;
+      case EO_CLAN :
+        strcpy(szAttackerName, "Your clan");
+        TmpClan = malloc(sizeof(struct clan));
+        CheckMem(TmpClan);
+        if (GetClan(AttackPacket->AttackOriginatorID, TmpClan))
+        {
+          TmpClan->Empire.Army.Footmen += AttackPacket->AttackingArmy.Footmen;
+          TmpClan->Empire.Army.Axemen  += AttackPacket->AttackingArmy.Axemen;
+          TmpClan->Empire.Army.Knights += AttackPacket->AttackingArmy.Knights;
+        }
+        Clan_Update(TmpClan);
+        FreeClan(TmpClan);
+        break;
+    }
+
+    // write message to AttackOriginator telling him the attack was lost
+    szMessage = MakeStr(300);
+
+
+    // figure out which village it was
+    WhichBBS = AttackPacket->BBSToID-1;
+
+    sprintf(szMessage, "%s's attack on the village of %s was lost but returned.\nYou had sent the following: %ld footmen, %ld axemen, %ld knights.",
+        szAttackerName, IBBS.Data->Nodes[WhichBBS].Info.pszVillageName,
+        AttackPacket->AttackingArmy.Footmen, AttackPacket->AttackingArmy.Axemen,
+        AttackPacket->AttackingArmy.Knights);
+    Junk[0] = Junk[1] = -1;
+    GenericMessage(szMessage, AttackPacket->AttackOriginatorID, Junk, "", FALSE);
+    free(szMessage);
+	(void)iTemp;
+  }
+
+/* Function Procedure:
+   Read packets in the BACKUP.DAT file (if any).
+   If the packet is marked as Active:
+     If date of the packet is older than the days lost to the game process
+     If Type == PT_CLANMOVE:
+       Re-Add clan to game.
+     If Type == PT_ATTACK:
+       Return Lost troops to player due to backup-restore.
+   If packet is newer than the days lost, resave it to the backup file.
+   If packet is not marked as active, ignore it.
+*/
+   
+  void IBBS_BackupMaint( void )
+  {
+    /* read in old BACKUP.DAT, write only those which are Active */
+    /* if packet which is older than 7 days is found, deal with it */
+
+    FILE *fpOld;
+    FILE *fpNew;
+    struct Packet Packet;
+    char *cpBuffer;
+    _INT16 iTemp;
+    struct clan *TmpClan;
+    struct AttackPacket AttackPacket;
+
+    fpOld = _fsopen("backup.dat", "rb", SH_DENYWR);
+    if (!fpOld)
+    {
+      // DisplayStr("> No BACKUP.DAT to process.\n");
+      return;
+    }
+
+    fpNew = _fsopen("backup.new", "wb", SH_DENYWR);
+    if (!fpNew)
+    {
+      DisplayStr("> Error writing BACKUP.DAT\n");
+      return;
+    }
+
+    for (;;)
+    {
+      if (EncryptRead(&Packet, sizeof(struct Packet), fpOld, XOR_PACKET) == 0)
+        break;
+
+      if (Packet.Active)
+      {
+        if (DaysBetween(Packet.szDate, System.szTodaysDate) > Game.Data->LostDays)
+        {
+          // see if it's also a travel packet type
+          // if so do this
+          if (Packet.PacketType == PT_CLANMOVE)
+          {
+            // player travel was screwed up, so restore him to .PC
+            // file
+
+            TmpClan = malloc(sizeof(struct clan));
+            CheckMem(TmpClan);
+            EncryptRead(TmpClan, sizeof(struct clan), fpOld, XOR_PACKET);
+
+            for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+              TmpClan->Member[iTemp] = NULL;
+
+            // read members
+            for (iTemp = 0; iTemp < 6; iTemp++)
+            {
+              TmpClan->Member[iTemp] = malloc(sizeof(struct pc));
+              CheckMem(TmpClan->Member[iTemp]);
+              EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fpOld, XOR_PACKET);
+            }
+
+            IBBS_AddToGame(TmpClan, TRUE);
+
+            // tell other board to comeback in case of problems
+            // --> NO!!  SendComeBack(TmpClan->DestinationBBS, TmpClan);
+
+            FreeClan(TmpClan);
+            continue;
+          }
+          else if (Packet.PacketType == PT_ATTACK)
+          {
+            // an empire attack
+
+            // get attackpacket
+            EncryptRead(&AttackPacket, sizeof(struct AttackPacket), fpOld, XOR_PACKET);
+
+            // find clan who was doing the attacking
+            // write him a message telling of the lost troops
+            ReturnLostAttack(&AttackPacket);
+
+            // update village's, alliance's OR clan's empire stats
+            continue;
+          }
+        }
+
+        //printf("Packet type is %d\n", Packet.PacketType);
+
+        /* write it to file */
+        EncryptWrite(&Packet, sizeof(struct Packet), fpNew, XOR_PACKET);
+
+        /* write buffer if any */
+        if (Packet.PacketLength)
+        {
+          //printf("length found\n");
+          cpBuffer = malloc(Packet.PacketLength);
+          CheckMem(cpBuffer);
+          EncryptRead(cpBuffer, Packet.PacketLength, fpOld, XOR_PACKET);
+          EncryptWrite(cpBuffer, Packet.PacketLength, fpNew, XOR_PACKET);
+          free(cpBuffer);
+        }
+      }
+      else
+      {
+        if (Packet.PacketLength)
+          fseek(fpOld, Packet.PacketLength, SEEK_CUR);
+      }
+    }
+
+    /* done */
+
+    fclose(fpNew);
+    fclose(fpOld);
+
+    unlink("backup.dat");
+    rename("backup.new", "backup.dat");
+  }
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Read LEAVING.DAT, find the clan's ID in the file.
+   If found mark it as inactive and resave LEAVING.DAT.
+   Reset the clan's WorldStatus to WS_STAYING and the DestinationBBS as -1
+*/
+
+  void AbortTrip ( void )
+  {
+    struct LeavingData LeavingData;
+    FILE *fpLeavingDat;
+    _INT16 CurEntry = -1;
+
+    /* open LEAVING.DAT */
+    fpLeavingDat = _fsopen("leaving.dat", "r+b", SH_DENYRW);
+    if (!fpLeavingDat)
+    {
+      return;
+    }
+
+    /* find that guy's entry which is active, make it inactive, write it to file */
+
+    for (;;)
+    {
+      CurEntry++;
+      if (EncryptRead(&LeavingData, sizeof(LeavingData), fpLeavingDat, XOR_TRAVEL) == 0)
+      {
+        //rputs("|04Couldn't find data in LEAVING.DAT file\n");
+        break;
+      }
+
+      if (LeavingData.Active == FALSE)    /* skip if inactive */
+        continue;
+
+      /* see if that's the one */
+      if (LeavingData.ClanID[0] == PClan->ClanID[0] &&
+        LeavingData.ClanID[1] == PClan->ClanID[1])
+      {
+        /* found it! */
+        fseek(fpLeavingDat, (long)CurEntry * sizeof(struct LeavingData), SEEK_SET);
+
+        LeavingData.Active = FALSE;
+
+        EncryptWrite(&LeavingData, sizeof(LeavingData), fpLeavingDat, XOR_TRAVEL);
+        break;
+      }
+    }
+    fclose(fpLeavingDat);
+
+    /* set this guy's trip stuff to none */
+    PClan->WorldStatus = WS_STAYING;
+    PClan->DestinationBBS = -1;
+
+    rputs("|04Trip aborted.\n");
+  }
+
+
+/* Function Procedure:
+   If the clan is set to leave (WorldStatus == WS_LEAVING) display the destination.
+   Ask if user wants to abort trip.
+   If no trip scheduled, tell user
+*/
+  void IBBS_CurrentTravelInfo ( void )
+  {
+    char szString[90];
+
+    /* see if travelling already */
+    if (PClan->WorldStatus == WS_LEAVING)
+    {
+      sprintf(szString, "|0SYou are set to leave for %s.\n",
+        IBBS.Data->Nodes[ PClan->DestinationBBS-1 ].Info.pszVillageName);
+      rputs(szString);
+
+      if (YesNo("|0SDo you wish to abort the trip?") == YES)
+      {
+        AbortTrip();
+      }
+    }
+    else
+      rputs("|0BNo trip is currently scheduled\n%P");
+  }
+
+// ------------------------------------------------------------------------- //
+/* Function Procedure:
+   Set clan's worldstatus to WS_GONE.
+   Add News entry for clan leaving.
+   Fix the Leaving stats appropriately (Followers/Footmen/Axemen/Knights)
+   Reduce the clan's current stats by the leaving stats (Followers/Footmen/Axemen/Knights)
+   Update the clan's entry with these new values
+   Set the clan to their leaving values (transfer all vault gold to the leaving group)
+*/
+  void IBBS_UpdateLeavingClan( struct clan *Clan, struct LeavingData LeavingData )
+  {
+    char szString[128];
+    long Gold;
+
+    /* update news */
+    sprintf(szString, ST_NEWSCLANEXIT, Clan->szName);
+    News_AddNews(szString);
+
+    Clan->WorldStatus = WS_GONE;
+
+    // fix up the stats for that clan's troops
+    if (LeavingData.Followers > Clan->Empire.Army.Followers)
+      LeavingData.Followers = Clan->Empire.Army.Followers;
+    if (LeavingData.Footmen > Clan->Empire.Army.Footmen)
+      LeavingData.Footmen = Clan->Empire.Army.Footmen;
+    if (LeavingData.Axemen > Clan->Empire.Army.Axemen)
+      LeavingData.Axemen = Clan->Empire.Army.Axemen;
+    if (LeavingData.Knights > Clan->Empire.Army.Knights)
+      LeavingData.Knights = Clan->Empire.Army.Knights;
+
+    // reduce the stats on THIS bbs before writing to this BBS's data file
+    Clan->Empire.Army.Followers -= LeavingData.Followers;
+    Clan->Empire.Army.Footmen -= LeavingData.Footmen;
+    Clan->Empire.Army.Axemen -= LeavingData.Axemen;
+    Clan->Empire.Army.Knights -= LeavingData.Knights;
+
+    Gold = Clan->Empire.VaultGold;
+    Clan->Empire.VaultGold = 0;
+
+    Clan_Update(Clan);
+
+    // set the stats for the traveling clan now
+    Clan->Empire.VaultGold = Gold;
+    Clan->Empire.Army.Followers  = LeavingData.Followers;
+    Clan->Empire.Army.Footmen = LeavingData.Footmen;
+    Clan->Empire.Army.Axemen = LeavingData.Axemen;
+    Clan->Empire.Army.Knights = LeavingData.Knights;
+  }
+
+
+  void IBBS_TravelMaint ( void )
+  {
+    struct LeavingData LeavingData;
+    struct Packet Packet;
+    FILE *fpLeavingDat, *fpOutboundDat, *fpOld;
+    struct clan *TmpClan;
+    struct pc *TmpPC;
+    _INT16 iTemp;
+
+    // DisplayStr("IBBS_TravelMaint()\n");
+
+    fpLeavingDat = _fsopen("leaving.dat", "rb", SH_DENYWR);
+    if (!fpLeavingDat)
+    {
+      return;
+    }
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      TmpClan->Member[iTemp] = NULL;
+
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+    for (;;)
+    {
+      /* reading leavingdata structure */
+      if (EncryptRead(&LeavingData, sizeof(LeavingData), fpLeavingDat, XOR_TRAVEL) == 0)
+      {
+        /* no more to read */
+        break;
+      }
+
+      if (LeavingData.Active == FALSE)  /* skip inactive ones */
+        continue;
+
+      /* get Clan struct from .PC file */
+      if (GetClan(LeavingData.ClanID, TmpClan) == FALSE)
+      {
+        continue;
+      }
+
+      // if already left OR he's deleted, skip
+      if (TmpClan->WorldStatus == WS_GONE)
+      {
+        FreeClan(TmpClan);
+        TmpClan = malloc(sizeof(struct clan));
+        CheckMem(TmpClan);
+        for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+          TmpClan->Member[iTemp] = NULL;
+        continue;
+      }
+
+      IBBS_UpdateLeavingClan(TmpClan, LeavingData);
+
+      TmpClan->WorldStatus = WS_STAYING;
+
+      /* write packet file */
+      fpOutboundDat = _fsopen(ST_OUTBOUNDFILE, "wb", SH_DENYWR);
+      if (!fpOutboundDat)
+      {
+        DisplayStr("|04Error writing temporary outbound.tmp file\n");
+        fclose(fpLeavingDat);
+
+        FreeClan(TmpClan);
+        free(TmpPC);
+        return;
+      }
+
+      fpOld = _fsopen("backup.dat", "ab", SH_DENYRW);
+      if (!fpOld)
+      {
+        DisplayStr("|04Can't open BACKUP.DAT!!\n");
+        FreeClan(TmpClan);
+        free(TmpPC);
+        fclose(fpLeavingDat);
+        return;
+      }
+
+      /* BACKUP.DAT is checked daily.  When DataOk messages are sent from
+         BBSes, entries in BACKUP.DAT are set to "inactive" and are skipped
+         -- on next maintenance, inactive data in BACKUP.DAT is purged.
+         * if backup.dat is found which is a week old (meaning no DataOk
+           was received for a week), this BBS processes the user in as if
+           he were travelling here.  In the news, it'll say "Blah was lost
+           but returned to Blah"  --
+           FIXME:  then send packet saying "he aborted the trip, so make him
+           "comeback"
+      */
+
+      /* create packet header */
+      Packet.Active = TRUE;
+      Packet.BBSIDFrom = IBBS.Data->BBSID;
+      Packet.BBSIDTo = LeavingData.DestID;
+      Packet.PacketType = PT_CLANMOVE;
+      strcpy(Packet.szDate, System.szTodaysDate);
+      Packet.PacketLength = sizeof(struct clan) + 6*sizeof(struct pc);
+      strcpy(Packet.GameID, Game.Data->GameID);
+
+      /* write packet */
+      EncryptWrite(&Packet, sizeof(struct Packet), fpOutboundDat, XOR_PACKET);
+      EncryptWrite(&Packet, sizeof(struct Packet), fpOld, XOR_PACKET);
+
+      EncryptWrite(TmpClan, sizeof(struct clan), fpOutboundDat, XOR_PACKET);
+      EncryptWrite(TmpClan, sizeof(struct clan), fpOld, XOR_PACKET);
+
+      /* write members to file */
+      TmpPC->szName[0] = 0;
+      TmpPC->Status = Dead;
+      for (iTemp = 0; iTemp < 6; iTemp++)
+      {
+        if (TmpClan->Member[iTemp])
+        {
+          EncryptWrite(TmpClan->Member[iTemp], sizeof(struct pc), fpOutboundDat, XOR_PACKET);
+          EncryptWrite(TmpClan->Member[iTemp], sizeof(struct pc), fpOld, XOR_PACKET);
+
+          free(TmpClan->Member[iTemp]);
+          TmpClan->Member[iTemp] = NULL;
+        }
+        else
+        {
+          EncryptWrite(TmpPC, sizeof(struct pc), fpOutboundDat, XOR_PACKET);
+          EncryptWrite(TmpPC, sizeof(struct pc), fpOld, XOR_PACKET);
+        }
+      }
+
+      fclose(fpOld);
+      fclose(fpOutboundDat);
+
+      /* send this packet to the destination BBS */
+      IBBS_SendPacketFile(LeavingData.DestID, ST_OUTBOUNDFILE);
+      unlink(ST_OUTBOUNDFILE);
+
+      // need to free up members used...
+      FreeClan(TmpClan);
+      TmpClan = malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+      for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+        TmpClan->Member[iTemp] = NULL;
+    }
+    fclose(fpLeavingDat);
+    unlink("leaving.dat");
+
+    free(TmpPC);
+    FreeClan(TmpClan);
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  void GetTroopsTraveling( struct LeavingData *LeavingData )
+  {
+    char szString[128], cInput;
+
+    rputs("|0CNow, you must choose the troops that will travel with the clan.\nThe rest will stay behind in this village.\n\n");
+
+    for (;;)
+    {
+      rputs(" |0BTroops Traveling\n");
+      rputs(ST_LONGLINE);
+
+      // show troops currently going
+      sprintf(szString, " |0A(|0BA|0A) |0CFollowers        |14%ld\n", LeavingData->Followers);
+      rputs(szString);
+      sprintf(szString, " |0A(|0BB|0A) |0CFootmen          |14%ld\n", LeavingData->Footmen);
+      rputs(szString);
+      sprintf(szString, " |0A(|0BC|0A) |0CAxemen           |14%ld\n", LeavingData->Axemen);
+      rputs(szString);
+      sprintf(szString, " |0A(|0BD|0A) |0CKnights          |14%ld\n", LeavingData->Knights);
+      rputs(szString);
+      rputs(" |0A(|0B0|0A) |0CDone\n");
+      rputs(ST_LONGLINE);
+      rputs(" ");
+      rputs(ST_ENTEROPTION);
+      rputs("Done");
+
+      cInput = od_get_answer("ABCD0\r\n");
+
+      rputs("\b\b\b\b    \b\b\b\b|15");
+
+      if (cInput == '0' || cInput == '\r' || cInput == '\n')
+        break;
+
+      switch(cInput)
+      {
+        case 'A' :
+          rputs("Followers\n\n");
+          LeavingData->Followers = GetLong("|0SHow many followers?",
+            LeavingData->Followers, PClan->Empire.Army.Followers);
+          break;
+        case 'B' :
+          rputs("Footmen\n\n");
+          LeavingData->Footmen = GetLong("|0SHow many footmen?",
+            LeavingData->Footmen, PClan->Empire.Army.Footmen);
+          break;
+        case 'C' :
+          rputs("Axemen\n\n");
+          LeavingData->Axemen = GetLong("|0SHow many Axemen?",
+            LeavingData->Axemen , PClan->Empire.Army.Axemen);
+          break;
+        case 'D' :
+          rputs("Knights\n\n");
+          LeavingData->Knights = GetLong("|0SHow many Knights?",
+            LeavingData->Knights, PClan->Empire.Army.Knights);
+          break;
+      }
+      rputs("\n");
+    }
+    rputs("Done\n\n");
+  }
+
+  BOOL IBBS_TravelToBBS(_INT16 DestID)
+  {
+    char szString[128];
+    struct LeavingData LeavingData;
+    FILE *fpLeavingDat;
+
+    /* see if it's this BBS */
+    if (IBBS.Data->BBSID == DestID)
+    {
+      rputs("You're already here!\n");
+      return FALSE;
+    }
+
+    /* if no recon yet */
+    if (IBBS.Data->Nodes[DestID-1].Recon.LastReceived == 0 ||
+      (DaysSince1970(System.szTodaysDate) - IBBS.Data->Nodes[DestID-1].Recon.LastReceived) >= 10)
+    {
+      // if no recon yet don't allow travel
+      // if days since last recon is >= 10 days, don't allow travel
+
+      rputs("|12The path to that BBS is currently hazy.  Try again later.\n\n");
+      return FALSE;
+    }
+
+    /* see if travelling already */
+    if (PClan->WorldStatus == WS_LEAVING)
+    {
+      sprintf(szString, "|0SYou are already set to leave for %s!\n",
+        IBBS.Data->Nodes[ PClan->DestinationBBS-1 ].Info.pszVillageName);
+      rputs(szString);
+
+      if (YesNo("|0SDo you wish to abort the trip?") == YES)
+      {
+        AbortTrip();
+      }
+      else
+        return FALSE;
+    }
+
+    Help("Traveling", ST_VILLHLP);
+
+    sprintf(szString, "|0SAre you sure you wish to travel to %s?",
+    IBBS.Data->Nodes[ DestID-1 ].Info.pszVillageName);
+
+    if (YesNo(szString) == YES)
+    {
+      /* append LEAVING.DAT file */
+      LeavingData.DestID = DestID;
+      LeavingData.Active = TRUE;
+      LeavingData.ClanID[0] = PClan->ClanID[0];
+      LeavingData.ClanID[1] = PClan->ClanID[1];
+
+      // ask user how many guys to bring along
+      LeavingData.Followers = 0;
+      LeavingData.Footmen = 0;
+      LeavingData.Axemen = 0;
+      LeavingData.Knights = 0;
+      LeavingData.Catapults = 0;
+      GetTroopsTraveling(&LeavingData);
+
+      fpLeavingDat = _fsopen("leaving.dat", "ab", SH_DENYRW);
+      if (!fpLeavingDat)
+      {
+        //rputs("|04Couldn't open LEAVING.DAT file\n");
+        return FALSE;
+      }
+      EncryptWrite(&LeavingData, sizeof(LeavingData), fpLeavingDat, XOR_TRAVEL);
+      fclose(fpLeavingDat);
+
+      PClan->WorldStatus = WS_LEAVING;
+      PClan->DestinationBBS = DestID;
+
+      if (YesNo("|0SDo you wish to exit the game now?") == YES)
+      {
+        System_Close();
+      }
+    }
+    else
+    {
+      rputs("|04Trip aborted.\n");
+      return FALSE;
+    }
+
+    rputs("|14Trip set!\n");
+    return TRUE;
+  }
+
+  void IBBS_SeeVillages ( BOOL Travel )
+  {
+    /* view other villages and their info */
+    /* allow user to choose village as he would a help file */
+    /* display info on that village using villinfo.txt file */
+    /* display last stats for that village -- ruler, tax rate, etc. */
+    /* if user enters blank line, quit */
+
+    _INT16 iTemp, NumBBSes, WhichBBS;
+    char *pszBBSNames[MAX_IBBSNODES], szString[128], BBSIndex[MAX_IBBSNODES];
+    __BOOL ShowInitially;
+
+    NumBBSes = 0;
+    for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+    {
+      pszBBSNames[iTemp] = NULL;
+
+      if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+        continue;
+
+      pszBBSNames [ NumBBSes ] = IBBS.Data->Nodes[iTemp].Info.pszVillageName;
+      BBSIndex[NumBBSes] = iTemp;
+      NumBBSes++;
+    }
+
+    ShowInitially = TRUE;
+
+    for (;;)
+    {
+      // choose which BBS
+      GetStringChoice (pszBBSNames, NumBBSes, "|0SChoose which village.\n|0E> |0F",
+        &WhichBBS, ShowInitially, DT_WIDE, TRUE);
+
+      ShowInitially = FALSE;
+
+      if (WhichBBS == -1)
+        return;
+
+      rputs("\n");
+      Help(IBBS.Data->Nodes[0+(BBSIndex[WhichBBS])].Info.pszVillageName, "world.ndx");
+      rputs("\n");
+
+      if (Travel)
+      {
+        /* travel stuff here */
+        sprintf(szString, "|0STravel to %s?", pszBBSNames[(BBSIndex[WhichBBS]+0)]);
+        if (NoYes(szString) == YES)
+        {
+          /* travel stuff here */
+          if (IBBS_TravelToBBS(BBSIndex[WhichBBS]+1))
+            return;
+        }
+      }
+    }
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  void IBBS_AddLCLog ( char *szString )
+  {
+    FILE *fpLCLogFile;
+
+    /* open news file */
+
+    /* add to it */
+
+    fpLCLogFile = _fsopen("lc.log", "at", SH_DENYWR);
+
+    fputs(szString, fpLCLogFile);
+
+    fclose(fpLCLogFile);
+  }
+
+// ------------------------------------------------------------------------- //
+
+	void IBBS_Destroy ( void )
+	{
+		_INT16 CurBBS;
+
+		if (!IBBS.Initialized)
+			return;
+
+		for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+			{
+        if (IBBS.Data->Nodes[CurBBS].Info.pszBBSName)
+          free(IBBS.Data->Nodes[CurBBS].Info.pszBBSName);
+        if (IBBS.Data->Nodes[CurBBS].Info.pszVillageName)
+          free(IBBS.Data->Nodes[CurBBS].Info.pszVillageName);
+        if (IBBS.Data->Nodes[CurBBS].Info.pszAddress)
+          free(IBBS.Data->Nodes[CurBBS].Info.pszAddress);
+			}
+		}
+
+		free(IBBS.Data);
+
+		IBBS.Initialized = FALSE;
+	}
+
+// ------------------------------------------------------------------------- //
+
+	void IBBS_LoginStats ( void )
+		/*
+		 * Shows IBBS stats for local login.
+		 */
+	{
+		char szString[128];
+
+		sprintf(szString, "|02� |07This BBS is in the InterBBS league %s %s (GameID = %s)\n",
+		Game.Data->LeagueID, Game.Data->szWorldName, Game.Data->GameID);
+		zputs(szString);
+	}
+
+// ------------------------------------------------------------------------- //
+
+  void IBBS_Create ( void )
+	{
+		_INT16 CurBBS;
+
+		for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+      {
+        IBBS.Data->Nodes[CurBBS].Reset.Received = FALSE;
+        IBBS.Data->Nodes[CurBBS].Reset.LastSent = 0;
+
+        IBBS.Data->Nodes[CurBBS].Recon.LastReceived = 0;
+        IBBS.Data->Nodes[CurBBS].Recon.LastSent = 0;
+        IBBS.Data->Nodes[CurBBS].Recon.PacketIndex = 'a';
+
+        IBBS.Data->Nodes[CurBBS].Attack.ReceiveIndex = 0;
+        IBBS.Data->Nodes[CurBBS].Attack.SendIndex = 0;
+      }
+		}
+	}
+
+	void IBBS_Read ( void )
+	{
+		FILE *fp;
+		_INT16 CurBBS;
+
+		fp = _fsopen("ibbs.dat", "rb", SH_DENYWR);
+		if (!fp)
+		{
+      IBBS_Create();
+			return;
+		}
+
+    for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+      {
+        EncryptRead(&IBBS.Data->Nodes[CurBBS].Recon, sizeof(struct ibbs_node_recon),
+          fp, XOR_IBBS);
+        EncryptRead(&IBBS.Data->Nodes[CurBBS].Attack, sizeof(struct ibbs_node_attack),
+          fp, XOR_IBBS);
+      }
+      else
+      {
+        fseek(fp, sizeof(struct ibbs_node_attack) + sizeof(struct ibbs_node_recon), SEEK_CUR);
+      }
+		}
+
+    // now read in reset data
+    for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+      {
+        if (!EncryptRead(&IBBS.Data->Nodes[CurBBS].Reset, sizeof(struct ibbs_node_reset),
+          fp, XOR_IBBS))
+        {
+          IBBS.Data->Nodes[CurBBS].Reset.Received = FALSE;
+          IBBS.Data->Nodes[CurBBS].Reset.LastSent = 0;
+        }
+      }
+      else
+      {
+        fseek(fp, sizeof(struct ibbs_node_reset), SEEK_CUR);
+      }
+    }
+
+		fclose(fp);
+	}
+
+	void IBBS_Write ( void )
+	{
+		FILE *fp;
+		_INT16 CurBBS;
+    struct ibbs_node_attack DummyAttack;
+    struct ibbs_node_recon DummyRecon;
+    struct ibbs_node_reset DummyReset;
+
+		fp = _fsopen("ibbs.dat", "wb", SH_DENYRW);
+		if (!fp)
+		{
+			return;
+		}
+
+    DummyReset.Received = FALSE;
+    DummyReset.LastSent = 0;
+
+    DummyRecon.LastReceived = 0;
+    DummyRecon.LastSent = 0;
+    DummyRecon.PacketIndex = 'a';
+
+    DummyAttack.ReceiveIndex = 0;
+    DummyAttack.SendIndex = 0;
+
+		for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+      {
+        EncryptWrite(&IBBS.Data->Nodes[CurBBS].Recon, sizeof(struct ibbs_node_recon),
+          fp, XOR_IBBS);
+        EncryptWrite(&IBBS.Data->Nodes[CurBBS].Attack, sizeof(struct ibbs_node_attack),
+          fp, XOR_IBBS);
+      }
+      else
+      {
+        EncryptWrite(&DummyRecon, sizeof(struct ibbs_node_recon),
+          fp, XOR_IBBS);
+        EncryptWrite(&DummyAttack, sizeof(struct ibbs_node_attack),
+          fp, XOR_IBBS);
+      }
+		}
+
+    // now write reset data
+    for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+      {
+        EncryptWrite(&IBBS.Data->Nodes[CurBBS].Reset, sizeof(struct ibbs_node_reset),
+          fp, XOR_IBBS);
+      }
+      else
+      {
+        EncryptWrite(&DummyReset, sizeof(struct ibbs_node_reset),
+          fp, XOR_IBBS);
+      }
+    }
+
+		fclose(fp);
+	}
+
+// ------------------------------------------------------------------------- //
+
+	_INT16 FoundPoint = FALSE;
+	_INT16 Level = 0;
+	_INT16 StartingPoint;
+	struct  PACKED Point {
+    char BackLink;
+    char ForwardLinks[MAX_IBBSNODES];
+  } *Points[MAX_IBBSNODES];
+
+
+  void FindPoint ( _INT16 Destination, _INT16 Source, _INT16 BasePoint )
+	{
+    _INT16 CurLink;
+
+		Level++;
+
+		/* see if we're there */
+		if (Source == Destination)
+		{
+			if (StartingPoint == -1)
+				StartingPoint = Source;
+
+			//printf("Found %d.  Starting point was %d\n", Source+1, StartingPoint+1);
+			FoundPoint = TRUE;
+			Level--;
+			return;
+		}
+
+		/* try forward links from Source */
+    for (CurLink = 0; CurLink < MAX_IBBSNODES; CurLink++)
+		{
+			if (Points[Source]->ForwardLinks[CurLink] != -1)
+			{
+				/* if link found is same as basepoint, don't go through it */
+				if (Points[Source]->ForwardLinks[CurLink] == BasePoint)
+					continue;
+
+				if (Level == 1)
+				{
+					StartingPoint = Points[Source]->ForwardLinks[CurLink];
+					//printf("Trying %d\n", StartingPoint);
+				}
+
+				//printf("Trying [%d][%d]\n", Source, CurLink);
+
+				/* found a link, try it */
+				FindPoint (Destination, Points[Source]->ForwardLinks[CurLink], Source);
+
+				if (FoundPoint)
+				{
+					Level--;
+					return;
+				}
+			}
+			else break; 		/* no more links */
+		}
+
+		/* tried all those points, now try backlinking */
+		if (Points[Source]->BackLink != -1)
+		{
+			/* if backlink just returns you, return */
+			if (Points[Source]->BackLink == BasePoint)
+			{
+				Level--;
+				return;
+			}
+
+			if (Level == 1)
+				StartingPoint = Points[Source]->BackLink;
+
+			/* found a link, try it */
+			FindPoint (Destination, Points[Source]->BackLink, Source);
+		}
+
+		Level--;
+	}
+
+
+	void IBBS_LoadNDX ( void )
+		/*
+		 * Loads up world.ndx file
+		 */
+	{
+		FILE *fpWorld;
+    char szLine[400], *pcCurrentPos, szString[400];
+    char szToken[MAX_TOKEN_CHARS + 1], *pcAt;
+		unsigned _INT16 uCount;
+		_INT16 iKeyWord;
+		_INT16 CurBBS = 0, NumBBSesRead = -1;
+		_INT16 iTemp, OrigWorlds, CurSlot;
+		char TypeOfStat;
+		BOOL UseHost = FALSE;           // set if using host method of routing
+    BOOL InDescription = FALSE;
+
+		/* make all bbs NULL pointers */
+		for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+			IBBS.Data->Nodes[iTemp].Active = FALSE;
+
+		/* read in .NDX file */
+		fpWorld = _fsopen("world.ndx", "r", SH_DENYWR);
+		if (!fpWorld)
+		{
+			// DisplayStr("|12Could not find world.ndx file.  If you are not in an InterBBS league,\nturn off the InterBBS option in the CONFIG.EXE program.\n\n");
+			IBBS_Destroy();
+			System_Error(ST_NOWORLDNDX);
+		}
+
+		for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+			Points[iTemp] = NULL;
+
+		for (;;)
+		{
+      /* read in a line */
+      if (fgets(szLine, 400, fpWorld) == NULL) break;
+
+			/* Ignore all of line after comments or CR/LF char */
+			pcCurrentPos=(char *)szLine;
+      ParseLine(pcCurrentPos);
+
+			/* If no token was found, proceed to process the next line */
+			if(!*pcCurrentPos) continue;
+
+			GetToken(pcCurrentPos, szToken);
+
+			if (szToken[0] == '$')
+				break;
+
+			if (szToken[0] == '^')
+			{
+				InDescription = !InDescription;
+				continue;
+			}
+
+			if (InDescription)
+				continue;
+
+			/* Loop through list of keywords */
+			for(iKeyWord = 0; iKeyWord < MAX_NDX_WORDS; ++iKeyWord)
+			{
+				/* If keyword matches */
+				if(stricmp(szToken, papszNdxKeyWords[iKeyWord]) == 0)
+				{
+					/* Process token */
+					switch (iKeyWord)
+					{
+						case 5 :	/* num of BBS in list */
+							NumBBSesRead++;
+
+							/* see if out of items memory yet */
+							CurBBS = atoi(pcCurrentPos) - 1;
+              if (CurBBS < 0 || CurBBS >= MAX_IBBSNODES)
+                System_Error("BBSId out of bounds!\n");
+
+							if (Points[CurBBS] == NULL)
+							{
+                Points[CurBBS] = malloc(sizeof(struct Point));
+								CheckMem(Points[CurBBS]);
+
+								/* nullify all links since initialized it */
+								for (CurSlot = 0; CurSlot < MAX_IBBSNODES; CurSlot++)
+									Points[CurBBS]->ForwardLinks[CurSlot] = -1;
+
+								Points[CurBBS]->BackLink = -1;
+							}
+							
+							/* activate this BBS */
+
+              IBBS.Data->Nodes[CurBBS].Active = TRUE;
+              IBBS.Data->Nodes[CurBBS].Info.pszBBSName = NULL;
+              IBBS.Data->Nodes[CurBBS].Info.pszVillageName = NULL;
+              IBBS.Data->Nodes[CurBBS].Info.pszAddress = NULL;
+              IBBS.Data->Nodes[CurBBS].Info.RouteThrough = CurBBS+1;
+              IBBS.Data->Nodes[CurBBS].Info.MailType = MT_NORMAL;
+
+              IBBS.Data->Nodes[CurBBS].Attack.SendIndex = 0;
+              IBBS.Data->Nodes[CurBBS].Attack.ReceiveIndex = 0;
+							break;
+						case 1 :	/* village name */
+              IBBS.Data->Nodes[CurBBS].Info.pszVillageName = malloc(strlen(pcCurrentPos) + 1);
+              CheckMem(IBBS.Data->Nodes[CurBBS].Info.pszVillageName);
+              strcpy(IBBS.Data->Nodes[CurBBS].Info.pszVillageName, pcCurrentPos);
+							break;
+						case 2 :	/* Address */
+              IBBS.Data->Nodes[CurBBS].Info.pszAddress = malloc(strlen(pcCurrentPos) + 1);
+              CheckMem(IBBS.Data->Nodes[CurBBS].Info.pszAddress);
+              strcpy(IBBS.Data->Nodes[CurBBS].Info.pszAddress, pcCurrentPos);
+							break;
+						case 0 :	/* BBS name */
+              IBBS.Data->Nodes[CurBBS].Info.pszBBSName = malloc(strlen(pcCurrentPos) + 1);
+              CheckMem(IBBS.Data->Nodes[CurBBS].Info.pszBBSName);
+              strcpy(IBBS.Data->Nodes[CurBBS].Info.pszBBSName, pcCurrentPos);
+							break;
+						case 6 :	/* Status */
+							//printf("status: currently unused\n");
+							break;
+						case 7 :	/* worldname */
+							strcpy(Game.Data->szWorldName, pcCurrentPos);
+							break;
+						case 8 :	/* league ID */
+							pcCurrentPos[2] = 0;	/* truncate it to two chars */
+							strcpy(Game.Data->LeagueID, pcCurrentPos);
+							break;
+						case 9 :		/* Host */
+							/* get tokens till no more */
+              UseHost = TRUE;
+
+							for (;;)
+							{
+								GetToken(pcCurrentPos, szString);
+
+								if (szString[0] == 0)
+									break;
+
+								iTemp = atoi(szString);
+
+                // REP: delete later
+                //printf("Linking %d through %d\n", iTemp, CurBBS+1);
+                //getch();
+
+								/* Node "iTemp" is a node of this host */
+
+								if (Points[iTemp-1] == NULL)
+								{
+                  //printf("Initializing node %d\n", iTemp);
+									Points[iTemp-1] = (struct Point *) malloc(sizeof(struct Point));
+									CheckMem(Points[iTemp-1]);
+
+									/* nullify all links since initialized it */
+									for (CurSlot = 0; CurSlot < MAX_IBBSNODES; CurSlot++)
+										Points[iTemp-1]->ForwardLinks[CurSlot] = -1;
+
+									Points[iTemp-1]->BackLink = -1;
+								}
+
+
+								Points[ iTemp-1 ]->BackLink = CurBBS;
+
+								/* find open slot for this forward link */
+								for (CurSlot = 0; CurSlot < MAX_IBBSNODES; CurSlot++)
+									if (Points[CurBBS]->ForwardLinks[CurSlot] == -1)
+										break;
+
+								/* set up forwardlink */
+								Points[CurBBS]->ForwardLinks[CurSlot] = iTemp-1;
+
+							}
+							break;
+            case 10 : /* NoMSG */
+              NoMSG[CurBBS] = TRUE;
+              break;
+          }
+					break;
+				}
+			}
+		}
+
+		// If keyword "Host" was found in the world.ndx file, Hosting method
+		// is used, so figure out routing
+		if (UseHost)
+			for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+			{
+        if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+					continue;
+
+        //printf("searching for %d\n", iTemp+1);
+				FoundPoint = FALSE;
+				StartingPoint = -1;
+				FindPoint(iTemp, IBBS.Data->BBSID-1, IBBS.Data->BBSID-1);
+
+        IBBS.Data->Nodes[iTemp].Info.RouteThrough = StartingPoint+1;
+        //printf("%d routed through %d\n", iTemp+1, IBBS.Data->Nodes[iTemp].Info.RouteThrough);
+			}
+
+    /* get rid of Point memory */
+		for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+			if (Points[iTemp])
+      {
+        //printf("Removing point %d from memory\n", iTemp+1);
+				free(Points[iTemp]);
+      }
+
+    NumBBSesRead++;
+
+    fclose(fpWorld);
+	(void)pcAt;
+	(void)OrigWorlds;
+	(void)TypeOfStat;
+	(void)uCount;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void IBBS_ProcessRouteConfig ( void )
+	{
+		FILE *fpRouteConfigFile;
+		char szRouteConfigName[40], szRouteConfigLine[255];
+		char *pcCurrentPos;
+		unsigned _INT16 uCount;
+		char szToken[MAX_TOKEN_CHARS + 1], szFirstToken[20], szSecondToken[20];
+		_INT16 iKeyWord, iTemp;
+
+		fpRouteConfigFile = _fsopen("route.cfg", "rt", SH_DENYWR);
+		if (!fpRouteConfigFile)
+		{
+			return;
+		}
+
+		for (;;)
+		{
+			/* read in a line */
+			if (fgets(szRouteConfigLine, 255, fpRouteConfigFile) == NULL) break;
+
+			/* Ignore all of line after comments or CR/LF char */
+			pcCurrentPos=(char *)szRouteConfigLine;
+			ParseLine(pcCurrentPos);
+
+			/* If no token was found, proceed to process the next line */
+			if(!*pcCurrentPos) continue;
+
+			GetToken(pcCurrentPos, szToken);
+
+			if (szToken[0] == '$')
+				break;
+
+			/* Loop through list of keywords */
+			for(iKeyWord = 0; iKeyWord < MAX_RT_WORDS; ++iKeyWord)
+			{
+				/* If keyword matches */
+				if(stricmp(szToken, papszRouteKeyWords[iKeyWord]) == 0)
+				{
+					/* Process config token */
+					switch (iKeyWord)
+					{
+						case 0 :	/* route */
+							GetToken(pcCurrentPos, szFirstToken);
+							GetToken(pcCurrentPos, szSecondToken);
+
+							//printf("Token1 = [%s]\nToken2 = [%s]\n", szFirstToken, szSecondToken);
+							if (stricmp(szFirstToken, "ALL") == 0)
+							{
+								//printf("all mail being routed through %d\n", atoi(szSecondToken));
+								/* route all through somewhere else */
+								for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+								{
+									if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+										continue;
+
+                  IBBS.Data->Nodes[iTemp].Info.RouteThrough = atoi(szSecondToken);
+								}
+							}
+							else
+							{
+								IBBS.Data->Nodes[ atoi(szFirstToken)-1 ].Info.RouteThrough = atoi(szSecondToken);
+								//printf("Mail to %d being routed through %d\n", atoi(szFirstToken), atoi(szSecondToken));
+							}
+							break;
+						case 1 :	/* crash */
+							GetToken(pcCurrentPos, szFirstToken);
+
+							//printf("Token1 = %s\n", szFirstToken);
+							if (stricmp(szFirstToken, "ALL") == 0)
+							{
+								//printf("all mail being crashed\n");
+								for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+								{
+									if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+										continue;
+
+                  IBBS.Data->Nodes[iTemp].Info.MailType = MT_CRASH;
+								}
+							}
+							else
+							{
+								IBBS.Data->Nodes[ atoi(szFirstToken)-1 ].Info.MailType = MT_CRASH;
+								//printf("Mail to %d being crashed\n", atoi(szFirstToken));
+							}
+							break;
+						case 2 :	/* hold */
+							GetToken(pcCurrentPos, szFirstToken);
+
+							//printf("Token1 = %s\n", szFirstToken);
+							if (stricmp(szFirstToken, "ALL") == 0)
+							{
+								//printf("all mail being held\n");
+								for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+								{
+									if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+										continue;
+
+									IBBS.Data->Nodes[iTemp].Info.MailType = MT_HOLD;
+								}
+							}
+							else
+							{
+								IBBS.Data->Nodes[ atoi(szFirstToken)-1 ].Info.MailType = MT_HOLD;
+								//printf("Mail to %d being held\n", atoi(szFirstToken));
+							}
+							break;
+						case 3 :	/* normal */
+							GetToken(pcCurrentPos, szFirstToken);
+
+							//printf("Token1 = %s\n", szFirstToken);
+							if (stricmp(szFirstToken, "ALL") == 0)
+							{
+								//printf("all mail set to normal\n");
+								for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+								{
+									if (IBBS.Data->Nodes[iTemp].Active == FALSE)
+										continue;
+
+                  IBBS.Data->Nodes[iTemp].Info.MailType = MT_NORMAL;
+								}
+							}
+							else
+							{
+								IBBS.Data->Nodes[ atoi(szFirstToken)-1 ].Info.MailType = MT_NORMAL;
+								//printf("Mail to %d set to normal\n", atoi(szFirstToken));
+							}
+							break;
+					}
+				}
+			}
+		}
+
+		fclose(fpRouteConfigFile);
+		(void)szRouteConfigName;
+		(void)uCount;
+	}
+
+// ------------------------------------------------------------------------- //
+
+  void IBBS_SendPacketFile ( _INT16 DestID, char *pszSendFile )
+	{
+		char szFullFileName[500], szPacketName[13];	/* 12345678.123 */
+		char PacketIndex[MAX_IBBSNODES], LastCounter, szString[580];
+		FILE *fp;
+		tIBInfo InterBBSInfo;
+    tIBResult Result;
+
+    if (IBBS.Initialized == FALSE)
+    {
+      System_Error("IBBS not initialized for call.\n");
+    }
+
+
+    if (DestID <= 0 || DestID > MAX_IBBSNODES ||
+      IBBS.Data->Nodes[DestID-1].Active == FALSE)
+    {
+      DisplayStr("IBBS_SendPacketFile() aborted:  Invalid ID\n");
+      return;
+    }
+
+
+    IBBS.Data->Nodes[DestID-1].Recon.LastSent = DaysSince1970(System.szTodaysDate);
+
+//		sprintf(szString, "|03Sending Packet:  %s to %d\n", pszSendFile, DestinationId);
+//		DisplayStr(szString);
+
+
+		/* set up interbbsinfo */
+    strncpy(InterBBSInfo.szThisNodeAddress, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszAddress, NODE_ADDRESS_CHARS);
+		InterBBSInfo.szThisNodeAddress[NODE_ADDRESS_CHARS] = '\0';
+
+		sprintf(szString, "The Clans League %s", Game.Data->LeagueID);
+		strncpy(InterBBSInfo.szProgName, szString, PROG_NAME_CHARS);
+		InterBBSInfo.szProgName[PROG_NAME_CHARS] = '\0';
+
+		strncpy(InterBBSInfo.szNetmailDir, Config->szNetmailDir, PATH_CHARS);
+		InterBBSInfo.szNetmailDir[PATH_CHARS] = '\0';
+
+		InterBBSInfo.bHold = FALSE;
+		InterBBSInfo.bCrash = FALSE;
+
+    if (IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Info.MailType == MT_CRASH)
+			InterBBSInfo.bCrash = TRUE;
+    else if (IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Info.MailType == MT_HOLD)
+			InterBBSInfo.bHold = TRUE;
+
+		InterBBSInfo.bEraseOnSend = TRUE;
+		InterBBSInfo.bEraseOnReceive = TRUE;
+		InterBBSInfo.nTotalSystems = 0;
+		InterBBSInfo.paOtherSystem = NULL;
+
+		/* change this later to the outbound directory of BBS */
+		// strcpy(szFullFileName, "C:\\PROG\\THECLANS\\OUTBOUND\\");
+		// FIXME: ?!	Use outbound directory or don't care?
+
+		if (System.LocalIBBS)
+			strcpy(szFullFileName, Config->szInboundDir);
+		else
+		{
+      strcpy(szFullFileName, System.szMainDir);
+      strcat(szFullFileName, "outbound/");
+		}
+
+		/* format:	CLxxxyyy.idc */
+		/* xxx = from BBS #
+			 yyy = to BBS #
+			 id = league ID
+			 c = counter for that node */
+
+		/* init the lastcounter */
+    if (IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Recon.PacketIndex == 'a')
+			LastCounter = 'z';
+		else
+      LastCounter = IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Recon.PacketIndex - 1;
+
+		sprintf(szPacketName,"cl%03d%03d.%-2s", IBBS.Data->BBSID, 
+				IBBS.Data->Nodes[DestID-1].Info.RouteThrough, Game.Data->LeagueID);
+
+		strcat(szFullFileName, szPacketName);
+
+
+/*
+    sprintf(szString, "filename: %s\n", szPacketName);
+		DisplayStr(szString);
+
+    sprintf(szString, "trying to sendfile is called %s\n", szFullFileName);
+    DisplayStr(szString);
+*/
+
+
+		/* see if can open that file */
+    fp = _fsopen(szFullFileName, "rb", SH_DENYWR);
+		if (fp)
+		{
+			/* if so, add onto it */
+			//DisplayStr("Appending to packet.\n");
+			fclose(fp);
+
+			file_append(pszSendFile, szFullFileName);
+
+      // DisplayStr("|15Appended|03\n");
+		}
+		else
+		{
+			// couldn't open file
+
+      LastCounter = IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Recon.PacketIndex;
+
+			if (System.LocalIBBS)
+				strcpy(szFullFileName, Config->szInboundDir);
+			else
+      {
+        strcpy(szFullFileName, System.szMainDir);
+        strcat(szFullFileName, "outbound/");
+      }
+
+			szPacketName[11] = LastCounter;
+			szPacketName[12] = 0;
+			strcat(szFullFileName, szPacketName);
+
+			/* else, make a new packet */
+			// DisplayStr("Making new packet.\n");
+
+			/* increment for next time */
+            IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Recon.PacketIndex++;
+            if (IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Recon.PacketIndex == 'z' + 1)
+                IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Recon.PacketIndex = 'a';
+
+			/* copy file to outbound dir */
+			//printf("Copying %s to %s\n", pszSendFile, szFullFileName);
+			file_copy(pszSendFile, szFullFileName);
+
+	//	sprintf(szString, "Sendfile is called %s\n", szFullFileName);
+	//	DisplayStr(szString);
+
+			/* send that file! */
+//		sprintf(szString, "Packet for BBS #%d being sent through %s\n", DestinationId, BBS[ BBS[DestinationId-1].RouteThrough-1 ].Info.pszAddress);
+//		DisplayStr(szString);
+
+			//sprintf("Filenameis %s\n", szFullFileName);
+      if (!NoMSG[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ])
+        Result = IBSendFileAttach(&InterBBSInfo, IBBS.Data->Nodes[ IBBS.Data->Nodes[DestID-1].Info.RouteThrough-1 ].Info.pszAddress, szFullFileName);
+	}
+	(void)PacketIndex;
+}
+
+
+// ------------------------------------------------------------------------- //
+	void IBBS_SendSpy( struct empire *Empire, _INT16 DestID )
+	{
+		struct SpyAttemptPacket Spy;
+		struct Packet Packet;
+		FILE *fp;
+
+		switch(Empire->OwnerType)
+		{
+			case EO_VILLAGE :
+				sprintf(Spy.szSpierName, "the village of %s", Village.Data->szName);
+				break;
+			case EO_CLAN :
+				sprintf(Spy.szSpierName, "the clan of %s from %s", Empire->szName, Village.Data->szName);
+				break;
+		}
+
+		Spy.IntelligenceLevel = Empire->Buildings[B_AGENCY];
+
+		Spy.BBSFromID = IBBS.Data->BBSID;
+		Spy.BBSToID 	= DestID;
+
+		// for now
+		Spy.ClanID[0] = -1;
+		Spy.ClanID[1] = -1;
+		Spy.MasterID[0] = PClan->ClanID[0];
+		Spy.MasterID[1] = PClan->ClanID[1];
+		Spy.TargetType = EO_VILLAGE;
+
+		/* create packet header */
+		Packet.Active = TRUE;
+		Packet.BBSIDTo = DestID;
+		Packet.BBSIDFrom = IBBS.Data->BBSID;
+		Packet.PacketType = PT_SPY;
+    strcpy(Packet.GameID, Game.Data->GameID);
+		strcpy(Packet.szDate, System.szTodaysDate);
+		Packet.PacketLength = sizeof(struct SpyAttemptPacket);
+
+    fp = _fsopen(ST_OUTBOUNDFILE, "wb", SH_DENYWR);
+		if (!fp)	return;
+
+		// write packet header
+		EncryptWrite(&Packet, sizeof(struct Packet), fp, XOR_PACKET);
+
+		EncryptWrite(&Spy, sizeof(struct SpyAttemptPacket), fp, XOR_PACKET);
+
+		fclose(fp);
+
+		// send packet to BBS
+		IBBS_SendPacketFile(Packet.BBSIDTo, ST_OUTBOUNDFILE);
+		unlink(ST_OUTBOUNDFILE);
+
+		rputs("|0BYour spy has been sent!\n");
+	}
+
+// ------------------------------------------------------------------------- //
+
+  void IBBS_SendAttackPacket(struct empire *AttackingEmpire, struct Army *AttackingArmy,
+		_INT16 Goal, _INT16 ExtentOfAttack, _INT16 TargetType, _INT16 ClanID[2], _INT16 DestID)
+	{
+		struct AttackPacket AttackPacket;
+
+
+		// write packet data
+		AttackPacket.BBSFromID = IBBS.Data->BBSID;
+		AttackPacket.BBSToID = DestID;
+		AttackPacket.AttackingEmpire = *AttackingEmpire;
+		AttackPacket.AttackingArmy = *AttackingArmy;
+		AttackPacket.Goal = Goal;
+		AttackPacket.ExtentOfAttack = ExtentOfAttack;
+		AttackPacket.TargetType = TargetType;
+		AttackPacket.ClanID[0] = ClanID[0];
+		AttackPacket.ClanID[1] = ClanID[1];
+
+		AttackPacket.AttackOriginatorID[0] = PClan->ClanID[0];
+		AttackPacket.AttackOriginatorID[1] = PClan->ClanID[1];
+
+        AttackPacket.AttackIndex = IBBS.Data->Nodes[DestID-1].Attack.SendIndex+1;
+        IBBS.Data->Nodes[DestID-1].Attack.SendIndex++;
+
+    IBBS_SendPacket ( PT_ATTACK, sizeof(struct AttackPacket), &AttackPacket,
+                          DestID);
+	}
+
+
+// ------------------------------------------------------------------------- //
+
+	void IBBS_ShowLeagueAscii ( void )
+	{
+		// shows ascii definied in world.ndx file
+
+		FILE *fp;
+		char szString[255], szToken[255];
+
+		fp = _fsopen("world.ndx", "r", SH_DENYWR);
+		if (!fp)
+		{
+			return;
+		}
+
+		for (;;)
+		{
+			if (fgets(szString, 255, fp) == 0)
+				break;
+
+			strcpy(szToken, szString);
+			szToken[5] = 0;
+
+			if (stricmp(szToken, "Ascii") == 0)
+			{
+				// point out to screen
+				if (szString[6])
+					rputs(&szString[6]);
+				else
+					rputs("\n");
+			}
+		}
+
+		fclose(fp);
+
+		// sprintf(szString, "|02You are entering the village of |10%s |02in the world of |14%s|02.\n",
+		sprintf(szString, ST_MAIN2,
+            IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszVillageName, Game.Data->szWorldName);
+		rputs(szString);
+	}
+
+// ------------------------------------------------------------------------- //
+
+  void IBBS_SendPacket ( _INT16 PacketType, long PacketLength, void *PacketData,
+                           _INT16 DestID )
+	{
+		struct Packet Packet;
+        FILE *fpOutboundDat, *fpBackupDat;
+
+    if (DestID <= 0 || DestID > MAX_IBBSNODES ||
+      IBBS.Data->Nodes[ DestID - 1].Active == FALSE)
+    {
+      DisplayStr("IBBS_SendPacket() aborted:  Invalid ID\n");
+      return;
+    }
+
+		Packet.Active = TRUE;
+
+    strcpy(Packet.GameID, Game.Data->GameID);
+		strcpy(Packet.szDate, System.szTodaysDate);
+		Packet.BBSIDFrom = IBBS.Data->BBSID;
+		Packet.BBSIDTo = DestID;
+
+		Packet.PacketType = PacketType;
+		Packet.PacketLength = PacketLength;
+
+    fpOutboundDat = _fsopen(ST_OUTBOUNDFILE, "wb", SH_DENYWR);
+		if (!fpOutboundDat)
+		{
+			DisplayStr("|04Error writing temporary outbound.tmp file\n");
+			return;
+		}
+
+		/* write packet */
+		EncryptWrite(&Packet, sizeof(struct Packet), fpOutboundDat, XOR_PACKET);
+
+		if (PacketLength)
+    EncryptWrite(PacketData, PacketLength, fpOutboundDat, XOR_PACKET);
+
+		fclose(fpOutboundDat);
+
+    // printf("Sending packet to %d\n", DestID);
+
+    IBBS_SendPacketFile(DestID, ST_OUTBOUNDFILE);
+		unlink(ST_OUTBOUNDFILE);
+
+
+		// write to backup.dat
+    if (PacketType == PT_ATTACK)
+    {
+      fpBackupDat = _fsopen("backup.dat", "ab", SH_DENYWR);
+      if (!fpBackupDat)  return;
+
+      // write to backup packet
+      EncryptWrite(&Packet, sizeof(struct Packet), fpBackupDat, XOR_PACKET);
+
+      if (PacketLength)
+        EncryptWrite(PacketData, PacketLength, fpOutboundDat, XOR_PACKET);
+
+      fclose(fpBackupDat);
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+	void IBBS_SendRecon ( _INT16 DestID )
+	{
+    if (IBBS.Data->Nodes[ DestID - 1].Active)
+      IBBS_SendPacket( PT_RECON, 0, 0, DestID );
+	}
+
+	void IBBS_SendReset ( _INT16 DestID )
+	{
+    if (IBBS.Data->Nodes[ DestID - 1].Active)
+      IBBS_SendPacket( PT_RESET, sizeof (struct game_data), Game.Data, DestID );
+	}
+// ------------------------------------------------------------------------- //
+
+  void IBBS_UpdateRecon ( void )
+	{
+		_INT16 CurBBS;
+
+		// go through all Nodes,
+		// if Node is active AND last recon sent is 0, send recon and update
+		// lastreconsent
+
+		for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active && (CurBBS+1) != IBBS.Data->BBSID)
+			{
+        if (IBBS.Data->Nodes[CurBBS].Recon.LastSent == 0 &&
+          IBBS.Data->Nodes[CurBBS].Recon.LastReceived == 0)
+				{
+          IBBS_SendRecon(CurBBS+1);
+          IBBS.Data->Nodes[CurBBS].Recon.LastSent = DaysSince1970(System.szTodaysDate);
+
+					// REP: add new BBS to news?
+          if (IBBS.Data->BBSID == 1)
+            IBBS_SendUserList(CurBBS+1);
+				}
+				else if ( ((DaysSince1970(System.szTodaysDate) -
+          IBBS.Data->Nodes[CurBBS].Recon.LastReceived) >= RECONDAYS) &&
+					( (DaysSince1970(System.szTodaysDate) -
+          IBBS.Data->Nodes[CurBBS].Recon.LastSent) != 0) )
+				{
+					// send a recon there
+					IBBS_SendRecon(CurBBS+1);
+          IBBS.Data->Nodes[CurBBS].Recon.LastSent = DaysSince1970(System.szTodaysDate);
+				}
+			}
+		}
+	}
+
+	void IBBS_UpdateReset ( void )
+	{
+		_INT16 CurBBS;
+
+		// go through all Nodes,
+		// if Node hasn't yet received a reset AND a reset hasn't been sent yet
+		// today, send one today
+
+		// can ONLY be run by LC!!!
+		for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active && (CurBBS+1) != IBBS.Data->BBSID)
+			{
+        if (IBBS.Data->Nodes[CurBBS].Reset.Received == FALSE &&
+            IBBS.Data->Nodes[CurBBS].Reset.LastSent < DaysSince1970(System.szTodaysDate) )
+				{
+          //printf("Sending reset to BBS #%d\n", CurBBS+1);
+					IBBS_SendReset(CurBBS+1);
+          IBBS.Data->Nodes[CurBBS].Reset.LastSent = DaysSince1970(System.szTodaysDate);
+				}
+			}
+		}
+	}
+
+// ------------------------------------------------------------------------- //
+	void IBBS_LeagueInfo ( void )
+	{
+		char szString[128];
+    _INT16 CurBBS, NumBBSes;
+
+		rputs("\n\n|14League Info|06\n\n");
+
+		sprintf(szString, "League Id        |07%s|06\n", Game.Data->LeagueID);
+		rputs(szString);
+		sprintf(szString, "World Name       |07%s|06\n", Game.Data->szWorldName);
+		rputs(szString);
+    sprintf(szString, "GameID           |07%s|06\n", Game.Data->GameID);
+		rputs(szString);
+
+		if (Game.Data->GameState == 0)
+		{
+			rputs("A game is currently in progress.\n");
+			sprintf(szString, "Days in progress |07%ld|06\n", DaysBetween(Game.Data->szDateGameStart, System.szTodaysDate));
+			rputs(szString);
+/*
+			sprintf(szString, "Elimination mode is |14%s|06\n",
+				World.EliminationMode ? "ON" : "OFF");
+			rputs(szString);
+*/
+		}
+		else if (Game.Data->GameState == 2)
+		{
+			rputs("The game is waiting for the main BBS's OK.\n");
+		}
+		else if (Game.Data->GameState == 1)
+		{
+      sprintf(szString, "The game will begin on |07%s|06\n",
+        Game.Data->szDateGameStart);
+      rputs(szString);
+		}
+		rputs("\n");
+
+		// list other boards in league
+		rputs("|07Id BBS Name             Village Name         Address    Recon\n");
+		rputs("|08-- -------------------- -------------------- ---------- -------\n");
+    for (CurBBS = 0, NumBBSes = 1; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+      if (IBBS.Data->Nodes[CurBBS].Active)
+			{
+				if (CurBBS+1 != IBBS.Data->BBSID)
+				{
+					sprintf(szString, "|06%-2d |14%-20s |06%-20s |07%-10s (%2ld/%2ld)\n",
+                        CurBBS+1, IBBS.Data->Nodes[CurBBS].Info.pszBBSName,
+                        IBBS.Data->Nodes[CurBBS].Info.pszVillageName, IBBS.Data->Nodes[CurBBS].Info.pszAddress,
+                        DaysSince1970(System.szTodaysDate) - IBBS.Data->Nodes[CurBBS].Recon.LastReceived,
+                        DaysSince1970(System.szTodaysDate) - IBBS.Data->Nodes[CurBBS].Recon.LastSent);
+				}
+				else
+				{
+					sprintf(szString, "|06%-2d |14%-20s |06%-20s |07%-10s ( N/A )\n",
+                        CurBBS+1, IBBS.Data->Nodes[CurBBS].Info.pszBBSName,
+                        IBBS.Data->Nodes[CurBBS].Info.pszVillageName, IBBS.Data->Nodes[CurBBS].Info.pszAddress);
+				}
+
+				rputs(szString);
+
+        if ( NumBBSes%15 == 0 )
+          door_pause();
+        NumBBSes++;
+			}
+		}
+    if ( !(NumBBSes%15==0))
+      door_pause();
+	}
+
+// ------------------------------------------------------------------------- //
+
+	void KillAlliances( void )
+	{
+		struct Alliance *Alliances[MAX_ALLIANCES];
+		char szFileName[13];
+		_INT16 iTemp;
+
+		GetAlliances(Alliances);
+
+		// delete files
+		// free up mem used by alliances
+		for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		if (Alliances[iTemp])
+		{
+			sprintf(szFileName, "hall%02d.txt", Alliances[iTemp]->ID);
+			unlink(szFileName);
+
+			free(Alliances[iTemp]);
+			Alliances[iTemp] = NULL;
+		}
+
+		// free up mem used by alliances
+		for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		if (Alliances[iTemp])
+			free(Alliances[iTemp]);
+
+		// called to destroy ALLY.DAT and remove those pesky HALLxxyy.TXT files
+		unlink("ally.dat");
+	}
+
+  void Reset ( void )
+  {
+		// Delete unwanted files here
+		unlink("clans.msj");
+		unlink("clans.pc");
+		unlink("disband.dat");
+		unlink("trades.dat");
+		unlink("public.dat");
+		unlink("pawn.dat");
+		unlink("clans.npx");
+
+		KillAlliances();
+
+		unlink("ally.dat");
+
+		// delete IBBS files
+		unlink("ibbs.dat");
+		unlink("ipscores.dat");
+		unlink("userlist.dat");
+		unlink("backup.dat");
+		unlink("leaving.dat");
+
+    // create a new IBBS.DAT file and then send recons
+    IBBS_Create();
+    IBBS_UpdateRecon();
+
+    // create new village data BASED on old village data
+    Village_Reset();
+
+		// update news
+		unlink("yest.asc");
+		rename("today.asc", "yest.asc");
+		News_CreateTodayNews();
+		News_AddNews("|0A � |0CReset received from LC!\n\n");
+
+	}
+
+  void IBBS_Reset ( struct game_data *GameData )
+		/*
+		 * Run if a reset packet was received.
+		 *
+		 */
+	{
+		// if reset is same as last game's, don't run this
+		if (stricmp(GameData->GameID, Game.Data->GameID) == 0)
+		{
+      DisplayStr("|08* |07dupe reset skipped.\n");
+			return;
+		}
+
+		// otherwise, it's a legit reset request
+		*Game.Data = *GameData;
+
+		strcpy(Game.Data->szTodaysDate, System.szTodaysDate);
+		Game.Data->NextClanID = 0;
+		Game.Data->NextAllianceID = 0;
+		Game.Data->GameState = 1;
+
+		// if today is game's start date
+		if (DaysBetween(Game.Data->szDateGameStart, System.szTodaysDate) >= 0)
+		{
+			// today is the start of new game
+			Game_Start();
+		}
+
+		Reset();
+	}
+
+// ------------------------------------------------------------------------- //
+  // This removes a ClanMOVE packet from backup.dat and only that type!
+  void IBBS_RemoveFromBackup( _INT16 ID[2] )
+  {
+    FILE *fpBackupDat;
+    struct Packet Packet;
+    struct clan *TmpClan;
+    long OldFileOffset; /* records start of packet so we can seek back to it */
+    _INT16 ClanID[2];
+
+    /* find leaving packet in Backup.dat and set as inactive */
+
+    fpBackupDat = _fsopen("backup.dat", "r+b", SH_DENYRW);
+    if (!fpBackupDat)
+    {
+      /* no need for dataOk?!  Report as error for now */
+      DisplayStr("|12Error with backup.dat in RemoveFromBackup()\n");
+      return;
+    }
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    /* seek through file, looking for ID[] which is same as this guy */
+    for (;;)
+    {
+      /* save this file position */
+      OldFileOffset = ftell(fpBackupDat);
+
+      /* read packet */
+      if (EncryptRead(&Packet, sizeof(struct Packet), fpBackupDat, XOR_PACKET) == 0)
+        break;
+
+      /* if packet has ID of this dude, mark it as inactive */
+      if (Packet.PacketType == PT_CLANMOVE && Packet.Active)
+      {
+        if (EncryptRead(TmpClan, sizeof(struct clan), fpBackupDat, XOR_PACKET) == 0)
+          break;
+
+        if (TmpClan->ClanID[0] == ID[0] && TmpClan->ClanID[1] == ID[1])
+          Packet.Active = FALSE;
+      }
+      /* if packet doesn't have same ID OR is not clanmove type, skip */
+      else
+      {
+        if (Packet.PacketLength)
+          fseek(fpBackupDat, Packet.PacketLength, SEEK_CUR);
+        continue;
+      }
+
+      /* fseek back to position */
+      fseek(fpBackupDat, OldFileOffset, SEEK_SET);
+
+      /* write updated packet to file */
+      EncryptWrite(&Packet, sizeof(struct Packet), fpBackupDat, XOR_PACKET);
+
+      if (Packet.PacketLength)
+        fseek(fpBackupDat, Packet.PacketLength, SEEK_CUR);
+    }
+
+    fclose(fpBackupDat);
+
+    free(TmpClan);
+	(void)ClanID;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  void IBBS_AddToGame( struct clan *Clan, BOOL WasLost )
+  {
+    char szString[128];
+    FILE *fpPC;
+    _INT16 iTemp, CurClan;
+    BOOL FoundMatch = FALSE;
+    struct clan *TmpClan;
+
+    /* update news */
+    if (WasLost)
+      sprintf(szString, ">> %s was lost but returns to town\n\n", Clan->szName);
+    else
+      sprintf(szString, ST_NEWSCLANENTER, Clan->szName);
+    News_AddNews(szString);
+
+    Clan->WorldStatus = WS_STAYING;
+    Clan->DestinationBBS = -1;
+
+    fpPC = _fsopen(ST_CLANSPCFILE, "r+b", SH_DENYWR);
+    if (!fpPC)
+    {
+      /* no file yet, append 'em onto end */
+      fpPC = _fsopen(ST_CLANSPCFILE, "ab", SH_DENYRW);
+
+      // fix alliances since they are not the same on each BBS
+      for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+        Clan->Alliances[iTemp] = -1;
+      Clan->PublicMsgIndex = 0;
+      Clan->MadeAlliance = FALSE;
+
+      // make it so no quests known or done
+      for (iTemp = 0; iTemp < MAX_QUESTS/8; iTemp++)
+      {
+        Clan->QuestsDone[iTemp] = 0;
+        Clan->QuestsKnown[iTemp] = 0;
+      }
+
+      EncryptWrite(Clan, sizeof(struct clan), fpPC, XOR_USER);
+
+      /* write members */
+      for (iTemp = 0; iTemp < 6; iTemp++)
+        EncryptWrite(Clan->Member[iTemp], sizeof(struct pc), fpPC, XOR_PC);
+
+      fclose(fpPC);
+
+      /* done */
+      return;
+    }
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    CurClan = 0;
+    for (;;)
+    {
+      /* seek to current clan */
+      fseek(fpPC, (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET);
+
+      /* read in tmp clan */
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPC, XOR_USER) == 0)
+        break;
+
+      /* see if ID matches */
+      if (TmpClan->ClanID[0] == Clan->ClanID[0] &&
+        TmpClan->ClanID[1] == Clan->ClanID[1])
+      {
+        /* found match */
+
+        // fix alliances since they are not the same on each BBS
+        for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+          Clan->Alliances[iTemp] = TmpClan->Alliances[iTemp];
+        Clan->Empire.VaultGold      += TmpClan->Empire.VaultGold;
+        Clan->Empire.Army.Followers += TmpClan->Empire.Army.Followers;
+        Clan->Empire.Army.Footmen   += TmpClan->Empire.Army.Footmen;
+        Clan->Empire.Army.Axemen    += TmpClan->Empire.Army.Axemen;
+        Clan->Empire.Army.Knights   += TmpClan->Empire.Army.Knights;
+        Clan->PublicMsgIndex         = TmpClan->PublicMsgIndex;
+        Clan->MadeAlliance           = TmpClan->MadeAlliance;
+        Clan->Eliminated             = FALSE;
+
+        // make it so no quests known are same
+        for (iTemp = 0; iTemp < MAX_QUESTS/8; iTemp++)
+        {
+          Clan->QuestsDone[iTemp] = TmpClan->QuestsDone[iTemp];
+          Clan->QuestsKnown[iTemp] = TmpClan->QuestsKnown[iTemp];
+        }
+
+        /* seek to that spot and write the merged info to file */
+        fseek(fpPC, (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET);
+
+        EncryptWrite(Clan, sizeof(struct clan), fpPC, XOR_USER);
+
+        /* write members */
+        for (iTemp = 0; iTemp < 6; iTemp++)
+          EncryptWrite(Clan->Member[iTemp], sizeof(struct pc), fpPC, XOR_USER);
+
+        FoundMatch = TRUE;
+        break;
+      }
+      CurClan++;
+    }
+    free(TmpClan);
+    fclose(fpPC);
+
+    /* when found, write data to file, write it ALL for now.  later only *some*
+       will be written */
+
+    /* if not there, close file, open for ab and then append on end */
+    if (FoundMatch == FALSE)
+    {
+      // fix alliances since they are not the same on each BBS
+      for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+        Clan->Alliances[iTemp] = -1;
+      Clan->PublicMsgIndex = 0;
+      Clan->MadeAlliance = FALSE;
+
+      fpPC = _fsopen(ST_CLANSPCFILE, "ab", SH_DENYRW);
+      EncryptWrite(Clan, sizeof(struct clan), fpPC, XOR_USER);
+
+      /* write members */
+      for (iTemp = 0; iTemp < 6; iTemp++)
+        EncryptWrite(Clan->Member[iTemp], sizeof(struct pc), fpPC, XOR_PC);
+
+      fclose(fpPC);
+    }
+
+    /* done */
+  }
+
+  void ComeBack( _INT16 ClanID[2], _INT16 BBSID )
+  {
+    struct LeavingData LeavingData;
+    FILE *fpLeavingDat;
+    struct clan *TmpClan;
+
+    // alloc mem
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    // get Clan from file
+    if (GetClan(ClanID, TmpClan) == FALSE)
+    {
+      FreeClan(TmpClan);
+      return; // not even here!
+    }
+
+    // if that clan ain't here, return
+    if (TmpClan->WorldStatus != WS_STAYING)
+    {
+      FreeClan(TmpClan);
+      return;
+    }
+
+    /* append leaving.dat file */
+    LeavingData.DestID = BBSID;
+    LeavingData.Active = TRUE;
+    LeavingData.ClanID[0] = TmpClan->ClanID[0];
+    LeavingData.ClanID[1] = TmpClan->ClanID[1];
+
+    // send all troops back home
+    LeavingData.Followers = TmpClan->Empire.Army.Followers;
+    LeavingData.Footmen =   TmpClan->Empire.Army.Footmen;
+    LeavingData.Axemen  =   TmpClan->Empire.Army.Axemen;
+    LeavingData.Knights =   TmpClan->Empire.Army.Knights;
+
+    fpLeavingDat = _fsopen("leaving.dat", "ab", SH_DENYRW);
+    if (!fpLeavingDat)
+    {
+      FreeClan(TmpClan);
+      return;
+    }
+    EncryptWrite(&LeavingData, sizeof(LeavingData), fpLeavingDat, XOR_TRAVEL);
+    fclose(fpLeavingDat);
+
+    TmpClan->WorldStatus = WS_LEAVING;
+    TmpClan->DestinationBBS = BBSID;
+
+    Clan_Update(TmpClan);
+    FreeClan(TmpClan);
+  }
+
+
+  _INT16 IBBS_ProcessPacket ( char *szFileName )
+	{
+    struct SpyResultPacket SpyResult;
+    struct SpyAttemptPacket Spy;
+    FILE *fp, *fpNewFile, *fpScores, *fpWorldNDX, *fpUserList;
+		struct Packet Packet;
+    struct clan *TmpClan;
+		_INT16 iTemp, OwnerType, NumScores;
+    char *pcBuffer, szString[128], GameID[16], GameDate[16], szName[25],
+				ScoreDate[11];
+    _INT16 ClanID[2], BBSID;
+		struct game_data GameData;
+    struct Message Message;
+    struct UserScore **UserScores;
+    struct UserInfo User;
+    struct AttackPacket *AttackPacket;
+    struct AttackResult *AttackResult;
+
+		/* open it */
+    fp = _fsopen(szFileName, "rb", SH_DENYWR);
+		if (!fp)
+		{
+			sprintf(szString, "Can't read in %s\n", szFileName);
+			DisplayStr(szString);
+			return 0;
+		}
+
+		// show processing it
+    sprintf(szString, "|07> |15Processing |14%s\n", szFileName);
+		DisplayStr(szString);
+
+		/* read it in until end of file */
+		for (;;)
+		{
+			if (EncryptRead(&Packet, sizeof(struct Packet), fp, XOR_PACKET) == 0)
+				break;
+
+      // if packet is old, ignore it
+      if (DaysBetween(Packet.szDate, System.szTodaysDate) > MAX_PACKETAGE)
+      {
+        fseek(fp, Packet.PacketLength, SEEK_CUR);
+        continue;
+      }
+
+			// if gameId is of the current game, update recon stuff
+      if (stricmp(Packet.GameID, Game.Data->GameID) == 0)
+			{
+        IBBS.Data->Nodes[ Packet.BBSIDFrom - 1 ].Recon.LastReceived =
+					DaysSince1970(Game.Data->szTodaysDate);
+			}
+      else
+      {
+        // GameIDs differ AND this isn't a reset packet, so we must ignore
+        // this packet completely
+        if (Packet.PacketType != PT_RESET)
+        {
+          fseek(fp, Packet.PacketLength, SEEK_CUR);
+          continue;
+        }
+      }
+
+			/* see if this packet is for you.  if not, reroute it to where it
+				belongs */
+
+      if (Packet.BBSIDTo != IBBS.Data->BBSID)
+			{
+				/* get packet info and write it to file */
+				if (Packet.PacketLength)
+				{
+					pcBuffer = malloc(Packet.PacketLength);
+					CheckMem(pcBuffer);
+					EncryptRead(pcBuffer, Packet.PacketLength, fp, XOR_PACKET);
+				}
+				else
+					pcBuffer = NULL;
+
+
+        fpNewFile = _fsopen(ST_OUTBOUNDFILE, "wb", SH_DENYWR);
+				if (!fpNewFile)
+				{
+					if (pcBuffer) free(pcBuffer);
+
+					fclose(fp);
+					DisplayStr("Can't write outbound.tmp\n");
+					return 0;
+				}
+				EncryptWrite(&Packet, sizeof(struct Packet), fpNewFile, XOR_PACKET);
+        if (Packet.PacketLength)
+          EncryptWrite(pcBuffer, Packet.PacketLength, fpNewFile, XOR_PACKET);
+
+				fclose(fpNewFile);
+
+				if (pcBuffer) 	free(pcBuffer);
+
+        DisplayStr("|08* |07Routing packet\n");
+        IBBS_SendPacketFile(Packet.BBSIDTo, ST_OUTBOUNDFILE);
+				unlink(ST_OUTBOUNDFILE);
+
+				/* move onto next packet in file */
+				continue;
+			}
+      else if (Packet.PacketType == PT_RESET)
+			{
+				/* data ok for specific char */
+        DisplayStr("|08- |07received reset\n");
+
+        EncryptRead(&GameData, sizeof(struct game_data), fp, XOR_PACKET);
+
+        IBBS_Reset(&GameData);
+
+        // send back a gotreset
+        IBBS_SendPacket(PT_GOTRESET, 0, 0, Packet.BBSIDFrom);
+			}
+      else if (Packet.PacketType == PT_GOTRESET)
+      {
+        sprintf(szString, "%s - Received GotReset from %s\n\n",
+          System.szTodaysDate, IBBS.Data->Nodes[ Packet.BBSIDFrom - 1 ].Info.pszBBSName);
+        IBBS_AddLCLog(szString);
+
+        DisplayStr(szString);
+
+        IBBS.Data->Nodes[ Packet.BBSIDFrom - 1].Reset.Received = TRUE;
+      }
+      else if (Packet.PacketType == PT_RECON)
+			{
+        // send back a GOTRECON
+        DisplayStr("|08* |07sending gotrecon\n");
+        IBBS_SendPacket(PT_GOTRECON, 0, 0, Packet.BBSIDFrom);
+			}
+      else if (Packet.PacketType == PT_GOTRECON)
+			{
+        // do nothing
+        DisplayStr("|08- |07got gotrecon\n");
+			}
+      else if (Packet.PacketType == PT_MSJ)
+			{
+        DisplayStr("|08- |07msj found\n");
+
+        // read in message from file
+        EncryptRead(&Message, sizeof(struct Message), fp, XOR_PACKET);
+
+        // allocate mem for text
+        Message.Data.MsgTxt = malloc(Message.Data.Length);
+        CheckMem(Message.Data.MsgTxt);
+
+        // load message text
+        EncryptRead(Message.Data.MsgTxt, Message.Data.Length, fp, XOR_PACKET);
+
+        // write message
+        PostMsj(&Message);
+
+        // deallocate mem
+        free(Message.Data.MsgTxt);
+			}
+      else if (Packet.PacketType == PT_SCOREDATA)
+      {
+        DisplayStr("|08- |07score data\n");
+
+        EncryptRead(&NumScores, sizeof(_INT16), fp, XOR_PACKET);
+
+        // read the scores in
+        UserScores = malloc(sizeof(struct UserScore *) * MAX_USERS);
+        CheckMem(UserScores);
+        for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+          UserScores[iTemp] = NULL;
+
+        for (iTemp = 0; iTemp < NumScores; iTemp++)
+        {
+          UserScores[iTemp] = malloc(sizeof(struct UserScore));
+          CheckMem(UserScores[iTemp]);
+          EncryptRead(UserScores[iTemp], sizeof(struct UserScore), fp, XOR_PACKET);
+        }
+
+        // process it
+        ProcessScoreData(UserScores);
+
+        // free up mem used
+        for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+        {
+          if (UserScores[iTemp])
+            free(UserScores[iTemp]);
+        }
+        free(UserScores);
+      }
+      else if (Packet.PacketType == PT_SCORELIST)
+      {
+        DisplayStr("|08- |07score list\n");
+
+        EncryptRead(&NumScores, sizeof(_INT16), fp, XOR_PACKET);
+
+        // read in date
+        EncryptRead(ScoreDate, 11, fp, XOR_PACKET);
+
+        // read the scores in
+        UserScores = malloc(sizeof(struct UserScore *) * MAX_USERS);
+        CheckMem(UserScores);
+        for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+          UserScores[iTemp] = NULL;
+
+        for (iTemp = 0; iTemp < NumScores; iTemp++)
+        {
+          UserScores[iTemp] = malloc(sizeof(struct UserScore));
+          CheckMem(UserScores[iTemp]);
+          EncryptRead(UserScores[iTemp], sizeof(struct UserScore), fp, XOR_PACKET);
+        }
+
+        // write it all to the IPSCORES.DAT file
+        fpScores = _fsopen("ipscores.dat", "wb", SH_DENYWR);
+        if (fpScores)
+        {
+          EncryptWrite(ScoreDate, 11, fpScores, XOR_IPS);
+
+          for (iTemp = 0; iTemp < NumScores; iTemp++)
+          {
+            EncryptWrite(UserScores[iTemp], sizeof(struct UserScore), fpScores, XOR_IPS);
+          }
+
+          fclose(fpScores);
+        }
+
+        // free up mem used
+        for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+        {
+          if (UserScores[iTemp])
+            free(UserScores[iTemp]);
+        }
+        free(UserScores);
+      }
+      else if (Packet.PacketType == PT_CLANMOVE)
+      {
+        TmpClan = malloc(sizeof (struct clan));
+        CheckMem(TmpClan);
+        EncryptRead(TmpClan, sizeof(struct clan), fp, XOR_PACKET);
+
+        for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+          TmpClan->Member[iTemp] = NULL;
+
+        // only do if in a game already
+        if (Game.Data->GameState == 0)
+        {
+          sprintf(szString, "|08- |07%s found.  Destination: |09%d\n", TmpClan->szName, Packet.BBSIDTo);
+          DisplayStr(szString);
+        }
+
+        /* read in each PC */
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          TmpClan->Member[iTemp] = malloc( sizeof(struct pc) );
+          CheckMem(TmpClan->Member[iTemp]);
+          EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fp, XOR_PACKET);
+        }
+
+        /* update .PC file with this guys stats */
+        // only do if in a game already
+        if (Game.Data->GameState == 0)
+        {
+          IBBS_AddToGame(TmpClan, FALSE);
+          IBBS_SendPacket(PT_DATAOK, sizeof(_INT16)*2, TmpClan->ClanID, Packet.BBSIDFrom);
+        }
+
+        FreeClan(TmpClan);
+      }
+      else if (Packet.PacketType == PT_DATAOK)
+      {
+        if (Game.Data->GameState != 0)
+          continue;
+
+        /* data ok for specific char */
+        DisplayStr("|08- |07Received DataOk\n");
+
+        EncryptRead(ClanID, sizeof(_INT16)*2, fp, XOR_PACKET);
+
+        IBBS_RemoveFromBackup(ClanID);
+      }
+      else if (Packet.PacketType == PT_COMEBACK)
+      {
+        // user is returning to the board specified FROM this board
+        DisplayStr("|08- |07comeback found\n");
+
+        // read in clanID + BBSId of destination
+        EncryptRead(ClanID, 2*sizeof(_INT16), fp, XOR_PACKET);
+        EncryptRead(&BBSID, sizeof(_INT16), fp, XOR_PACKET);
+
+        ComeBack(ClanID, BBSID);
+      }
+      else if (Packet.PacketType == PT_NEWUSER)
+      {
+        DisplayStr("|08- |07newuser found\n");
+        // new user has logged into a BBS in the league, we will
+        // now see if he is a dupe user or a valid one
+
+        // read in user from file
+        EncryptRead(&User, sizeof(struct UserInfo), fp, XOR_PACKET);
+
+        // see if user is already in list
+        if (IBBS_InList(User.szMasterName, FALSE))
+        {
+          // if so, return packet saying "Delete that guy!"
+          IBBS_SendDelUser(Packet.BBSIDFrom, &User);
+        }
+        else
+        {
+          // if not already in list, send packet to everybody
+          // in league saying
+          //   "here is a new user, add him"
+          // add the user to your own user list too
+
+          UpdateNodesOnNewUser(&User);
+
+          AddToUList(&User);
+        }
+      }
+      else if (Packet.PacketType == PT_ADDUSER)
+      {
+        // new user update from main BBS
+        DisplayStr("|08- |07adduser found\n");
+
+        // read in user from file
+        EncryptRead(&User, sizeof(struct UserInfo), fp, XOR_PACKET);
+
+        // add to THIS bbs's list
+        AddToUList(&User);
+      }
+      else if (Packet.PacketType == PT_DELUSER)
+      {
+        DisplayStr("|08- |07deluser found\n");
+
+        // he is a dupe user
+        // got word from head BBS to delete a certain user, do it then :)
+        EncryptRead(&User, sizeof(struct UserInfo), fp, XOR_PACKET);
+
+        sprintf(szString, "deleting %s\n", User.szName);
+        DisplayStr(szString);
+
+        DeleteClan ( User.ClanID, User.szName, FALSE );
+      }
+      else if (Packet.PacketType == PT_SUBUSER)
+      {
+        // user is being deleted from all boards
+        DisplayStr("|08- |07subuser found\n");
+
+        // read in user from file
+        EncryptRead(&User, sizeof(struct UserInfo), fp, XOR_PACKET);
+
+        sprintf(szString, "deleting %s\n", User.szName);
+        DisplayStr(szString);
+
+        // remove him from clan data AND userlist (done in DeleteClan)
+        DeleteClan(User.ClanID, User.szName, FALSE);
+      }
+      else if (Packet.PacketType == PT_ATTACK)
+      {
+        DisplayStr("|08- |07attack found\n");
+
+        // read attack packet
+        AttackPacket = malloc(sizeof(struct AttackPacket));
+        CheckMem(AttackPacket);
+        EncryptRead(AttackPacket, sizeof(struct AttackPacket), fp, XOR_PACKET);
+
+        // process attack packet
+        ProcessAttackPacket(AttackPacket);
+        free(AttackPacket);
+      }
+      else if (Packet.PacketType == PT_ATTACKRESULT)
+      {
+        DisplayStr("|08- |07attackresult found\n");
+
+        // read attack packet
+        AttackResult = malloc(sizeof(struct AttackResult));
+        CheckMem(AttackResult);
+        EncryptRead(AttackResult, sizeof(struct AttackResult), fp, XOR_PACKET);
+
+        // process attack packet
+        ProcessResultPacket(AttackResult);
+        free(AttackResult);
+      }
+      else if (Packet.PacketType == PT_SPY)
+      {
+        DisplayStr("|08- |07spy\n");
+
+        EncryptRead(&Spy, sizeof(struct SpyAttemptPacket), fp, XOR_PACKET);
+
+        // process attack packet
+        IBBS_ProcessSpy(&Spy);
+      }
+      else if (Packet.PacketType == PT_SPYRESULT)
+      {
+        DisplayStr("|08- |07spy result\n");
+
+        EncryptRead(&SpyResult, sizeof(struct SpyResultPacket), fp, XOR_PACKET);
+
+        // process attack packet
+        IBBS_ProcessSpyResult(&SpyResult);
+      }
+      else if (Packet.PacketType == PT_NEWNDX)
+      {
+        DisplayStr("|08- |07ndx found\n");
+
+        // allocate mem for world.ndx file
+        pcBuffer = malloc(Packet.PacketLength);
+        CheckMem(pcBuffer);
+
+        // load world.ndx
+        EncryptRead(pcBuffer, Packet.PacketLength, fp, XOR_PACKET);
+
+        // write to file
+        fpWorldNDX = _fsopen("world.ndx", "wb", SH_DENYRW);
+        if (fpWorldNDX)
+        {
+          fwrite(pcBuffer, Packet.PacketLength, 1, fpWorldNDX);
+          fclose(fpWorldNDX);
+        }
+
+        // deallocate mem
+        free(pcBuffer);
+      }
+      else if (Packet.PacketType == PT_ULIST)
+      {
+        DisplayStr("|08- |07userlist found\n");
+
+        // allocate mem for world.ndx file
+        pcBuffer = malloc(Packet.PacketLength);
+        CheckMem(pcBuffer);
+
+        // load file in
+        EncryptRead(pcBuffer, Packet.PacketLength, fp, XOR_PACKET);
+
+        // write to file
+        fpUserList = _fsopen("userlist.dat", "wb", SH_DENYRW);
+        if (fpUserList)
+        {
+          fwrite(pcBuffer, Packet.PacketLength, 1, fpUserList);
+          fclose(fpUserList);
+        }
+
+        // deallocate mem
+        free(pcBuffer);
+      }
+			else
+			{
+        DisplayStr("|04x |12Unknown packet type!  ABORTING!!\n");
+				fclose(fp);
+				return 0;
+			}
+		}
+
+		fclose(fp);
+
+		(void)szName;
+		(void)OwnerType;
+		(void)GameDate;
+		(void)GameID;
+		/* if unsuccessfully dealt with, return 0 */
+		return 1;
+	}
+
+
+// ------------------------------------------------------------------------- //
+
+	// returns TRUE (I think) if no more files
+	BOOL GetNextFile(char *szWildcard, char *szFileName)
+	{
+		struct ffblk ffblk;
+		unsigned _INT16 date = 65534, time = 65534;
+		BOOL Done, NoMoreFiles = TRUE;
+
+		Done = findfirst(szWildcard, &ffblk, 0); 
+
+
+		// go through a file, record date, timestamps
+
+		while (!Done)
+		{
+			//printf("trying out %s\n", ffblk.ff_name);
+			// is date of file less than last file read in?
+			if (ffblk.ff_fdate <= date)
+			{
+				// if same date, and this file's time is greater than
+				// other time, this ain't the file we want.
+				if ( (ffblk.ff_fdate == date && ffblk.ff_ftime < time) ||
+					(ffblk.ff_fdate < date))
+				{
+					//printf("found file %s\n", ffblk.ff_name);
+					date = ffblk.ff_fdate;
+					time = ffblk.ff_ftime;
+					strcpy(szFileName, ffblk.ff_name);
+					NoMoreFiles = FALSE;
+				}
+			}
+			Done = findnext(&ffblk);
+		}
+
+		return NoMoreFiles;
+	}
+
+	void IBBS_PacketIn ( void )
+	{
+		tIBInfo InterBBSInfo;
+/*		struct ffblk ffblk;*/
+		char szFileName[500], szPacketName[500], szString[580], szFileName2[500];
+		BOOL Done;
+		FILE *fp;
+
+		if (Game.Data->InterBBS == FALSE)
+		{
+			DisplayStr("|12* This game is not set up for InterBBS!\n");
+			return;
+		}
+    DisplayStr("|09* IBBS_PacketIn()\n");
+
+		/* set up interbbsinfo */
+        strncpy(InterBBSInfo.szThisNodeAddress, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszAddress, NODE_ADDRESS_CHARS);
+		InterBBSInfo.szThisNodeAddress[NODE_ADDRESS_CHARS] = '\0';
+
+		sprintf(szString, "The Clans League %s", Game.Data->LeagueID);
+		strncpy(InterBBSInfo.szProgName, szString, PROG_NAME_CHARS);
+		InterBBSInfo.szProgName[PROG_NAME_CHARS] = '\0';
+
+		strncpy(InterBBSInfo.szNetmailDir, Config->szNetmailDir, PATH_CHARS);
+		InterBBSInfo.szNetmailDir[PATH_CHARS] = '\0';
+
+		InterBBSInfo.bHold = FALSE;
+		InterBBSInfo.bCrash = FALSE;
+		InterBBSInfo.bEraseOnSend = TRUE;
+		InterBBSInfo.bEraseOnReceive = TRUE;
+		InterBBSInfo.nTotalSystems = 0;
+		InterBBSInfo.paOtherSystem = NULL;
+
+		// process files with this wildcard spec ONLY:	CLxxx*.IDy
+		//
+		// xxx is THIS BBS's Id.
+
+		// create filename to search for
+		#ifdef __unix__
+		strcpy(szPacketName, Config->szInboundDir);
+		sprintf(szFileName,"[Cc][Ll]???%03d.%-2s?",IBBS.Data->BBSID,Game.Data->LeagueID);
+		#else
+		sprintf(szFileName,"CL???%03d.%-2s?",IBBS.Data->BBSID,Game.Data->LeagueID);
+		#endif
+		// now copy over to the full filename
+		strcat(szPacketName, szFileName);
+
+    // printf("Filespec to search is %s\n", szPacketName);
+
+		if (System.LocalIBBS)
+		{
+			// set true if IBGetFile was a success
+			Done = IBGetFile(&InterBBSInfo, szFileName) != eSuccess;
+		}
+		else
+		{
+			//Done = findfirst(szPacketName, &ffblk, 0);
+			Done = GetNextFile(szPacketName, szFileName2);
+		}
+
+		/* keep calling till no more messages to read */
+		while (!Done)
+		{
+			/* process file */
+
+			if (System.LocalIBBS == FALSE)
+			{
+				strcpy(szFileName, Config->szInboundDir);
+				//strcat(szFileName, ffblk.ff_name);
+				strcat(szFileName, szFileName2);
+			}
+			// for LocalInterBBS, we assume szFilename already contains the
+			// filename
+
+            if (IBBS_ProcessPacket(szFileName) == 0)
+			{
+				sprintf(szString, "Error dealing with packet %s\n", szFileName);
+				DisplayStr(szString);
+			}
+			else
+			{
+				/* delete it */
+				unlink(szFileName);
+			}
+
+			if (System.LocalIBBS)
+			{
+				// set true if IBGetFile was a success
+				Done = IBGetFile(&InterBBSInfo, szFileName) != eSuccess;
+			}
+			else
+				// Done = findnext(&ffblk);
+				Done = GetNextFile(szPacketName, szFileName2);
+		}
+
+    DisplayStr("\n");
+
+		// look for new nodelist
+		// look for world.ndx first
+		// if not found, go for WORLD.ID
+		if (System.LocalIBBS == FALSE)
+		{
+			// try world.ID
+			#ifdef __unix__
+			sprintf(szFileName2, "[Ww][Oo][Rr][Ll][Dd].%-2s", Game.Data->LeagueID);
+			#else
+			sprintf(szFileName2, "WORLD.%-2s", Game.Data->LeagueID);
+			#endif
+
+			strcpy(szFileName, Config->szInboundDir);
+			strcat(szFileName, szFileName2);
+
+			while(!GetNextFile(szFileName,szFileName2))  {
+				fp = _fsopen(szFileName, "r", SH_DENYWR);
+				if (fp)
+				{
+					DisplayStr("|08- |07new world.ndx found.\n");
+					// found it
+					fclose(fp);
+					file_copy(szFileName2, "world.ndx");
+					unlink(szFileName2);
+				}
+			}
+		}
+	}
+
+// ------------------------------------------------------------------------- //
+
+
+  void IBBS_Init ( void )
+		/*
+		 * IBBS data is initialized.	MUST be called before any other IBBS_*
+		 * functions are called.
+		 */
+	{
+    if (Verbose)
+    {
+      DisplayStr("> IBBS_Init()\n");
+      delay(500);
+    }
+
+#ifdef PRELAB
+		printf("IBBS Initializing. -- %lu\n", farcoreleft());
+#endif
+
+    IBBS.Data = malloc(sizeof(struct ibbs_data));
+    CheckMem(IBBS.Data);
+    IBBS.Initialized = TRUE;
+
+    IBBS.Data->BBSID = Config->BBSID;
+
+    IBBS_LoadNDX();
+    IBBS_ProcessRouteConfig();
+
+    IBBS_Read();
+	}
+
+// ------------------------------------------------------------------------- //
+
+	void IBBS_Close ( void )
+		/*
+		 * Closes down IBBS.
+		 */
+	{
+		if (!IBBS.Initialized) return;
+
+#ifdef PRELAB
+		printf("IBBS Closing. -- %lu\n", farcoreleft());
+#endif
+
+    IBBS_Write();
+    IBBS_Destroy();
+	}
+
+// ------------------------------------------------------------------------- //
+
+	void IBBS_Maint ( void )
+	{
+		_INT16 CurBBS;
+
+		if (Game.Data->InterBBS == FALSE)
+			return;
+
+		DisplayStr("* IBBS_Maint()\n");
+
+		IBBS_PacketIn();
+
+		for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+		{
+			if (IBBS.Data->Nodes[CurBBS].Active)
+			{
+				if (IBBS.Data->Nodes[CurBBS].Recon.PacketIndex < 'z')
+					IBBS.Data->Nodes[CurBBS].Recon.PacketIndex++;
+				else
+					IBBS.Data->Nodes[CurBBS].Recon.PacketIndex = 'a';
+			}
+		}
+
+		// scores for the league
+		if (IBBS.Data->BBSID != 1)
+			CreateScoreData(TRUE);
+
+		CreateScoreData(FALSE);
+
+		if (IBBS.Data->BBSID == 1)
+			SendScoreList();
+
+		if (IBBS.Data->BBSID == 1)
+		{
+			/* send userlist to every BBS */
+			if ((DaysSince1970(System.szTodaysDate) % 4) == 0)
+			{
+				for (CurBBS = 1; CurBBS < MAX_IBBSNODES; CurBBS++)
+				{
+					if (IBBS.Data->Nodes[CurBBS].Active)
+					{
+						IBBS_SendUserList(CurBBS+1);
+					}
+				}
+			}
+		}
+
+		IBBS_TravelMaint();
+		IBBS_BackupMaint();
+	}
+
+#ifdef _WIN32
+#if defined(_UNICODE) || defined(UNICODE)
+# error "findfirst/findnext clones will not compile under UNICODE"
+#endif
+
+	int findfirst (const char *pathname, struct ffblk *ffblk, int attribute)
+	{
+		WIN32_FIND_DATA w32_finddata;
+
+		if (!ffblk)
+		{
+			errno = ENOENT;
+			return -1;
+		}
+
+		ffblk->ff_findhandle = FindFirstFile (pathname, &w32_finddata);
+		if (ffblk->ff_findhandle == INVALID_HANDLE_VALUE)
+		{
+			errno = ENOENT;
+			return -1;
+		}
+
+		ffblk->ff_findattribute = attribute;
+		convert_attribute (&ffblk->ff_attrib, w32_finddata.dwFileAttributes);
+		/* Search for matching attribute */
+		return (search_and_construct_ffblk(&w32_finddata, ffblk, TRUE));
+	}
+	
+	int findnext (struct ffblk *ffblk)
+	{
+		WIN32_FIND_DATA w32_finddata;
+
+		if (!ffblk)
+		{
+			errno = ENOENT;
+			return -1;
+		}
+
+		return (search_and_construct_ffblk(&w32_finddata, ffblk, FALSE));
+	}
+
+	int search_and_construct_ffblk(WIN32_FIND_DATA *w32_finddata, struct ffblk *ffblk, BOOL bhave_file)
+	{
+		SYSTEMTIME system_time;
+
+		if ((bhave_file == TRUE && !(ffblk->ff_attrib & ffblk->ff_findattribute)) ||
+			(bhave_file == FALSE))
+		{
+			do {
+				/* Check for FA_NORMAL and FA_ARCH  */
+				/* Make sure these IFs only run AFTER a file has been found for FindNextFile */
+				if (bhave_file)
+				{
+					if (ffblk->ff_attrib == FA_NORMAL && ffblk->ff_findattribute == FA_NORMAL)
+						break;
+					if (ffblk->ff_attrib == FA_ARCH && ffblk->ff_findattribute == FA_NORMAL)
+						break;
+				}
+				else
+					bhave_file = TRUE;
+				if (!FindNextFile (ffblk->ff_findhandle, w32_finddata))
+				{
+					FindClose(ffblk->ff_findhandle);
+					errno = ENOENT;
+					return -1;
+				}
+				else
+					convert_attribute(&ffblk->ff_attrib, w32_finddata->dwFileAttributes);
+			} while (!(ffblk->ff_attrib & ffblk->ff_findattribute));
+		}
+
+		if (strlen(w32_finddata->cAlternateFileName))
+			strncpy(ffblk->ff_name, w32_finddata->cAlternateFileName, 13);
+		else
+			strncpy(ffblk->ff_name, w32_finddata->cFileName, 13);
+
+		FileTimeToSystemTime(&w32_finddata->ftLastWriteTime, &system_time);
+
+		ffblk->ff_fsize = (long)w32_finddata->nFileSizeLow;
+		/* Packed Date Format:
+		   Year [7 bits/0xFE00]
+		   Month [4 bits/0x01E0]
+		   Day [5 bits/0x001F]
+		   Packed Time Format:
+		   Hours [5 bits/0xF800]
+		   Minutes [6 bits/0x07E0]
+		   Seconds/2 [5 bits/0x001F]
+		*/
+		ffblk->ff_fdate  = ((system_time.wYear - 1980) & 0x7F) << 9;
+		ffblk->ff_fdate |= ((system_time.wMonth - 1) & 0x0F) << 5;
+		ffblk->ff_fdate |= ((system_time.wDay) & 0x1F);
+		ffblk->ff_ftime  = ((system_time.wHour) & 0x1F) << 11;
+		ffblk->ff_ftime |= ((system_time.wMinute) & 0x2F) << 5;
+		ffblk->ff_ftime |= ((system_time.wSecond / 2) & 0x1F);
+		return 0;
+	}
+
+	void convert_attribute(char *attrib_out, DWORD attrib_in)
+	{
+		*attrib_out = FA_NORMAL;
+		if (attrib_in & FILE_ATTRIBUTE_READONLY)
+			*attrib_out |= FA_RDONLY;
+		if (attrib_in & FILE_ATTRIBUTE_HIDDEN)
+			*attrib_out |= FA_HIDDEN;
+		if (attrib_in & FILE_ATTRIBUTE_SYSTEM)
+			*attrib_out |= FA_SYSTEM;
+		if (attrib_in & FILE_ATTRIBUTE_DIRECTORY)
+			*attrib_out |= FA_DIREC;
+		if (attrib_in & FILE_ATTRIBUTE_ARCHIVE)
+			*attrib_out |= FA_ARCH;
+	}
+#endif
diff --git a/src/doors/clans-src/ibbs.h b/src/doors/clans-src/ibbs.h
new file mode 100644
index 0000000000000000000000000000000000000000..6dbe978950899e8e00dd31587430d673836912ef
--- /dev/null
+++ b/src/doors/clans-src/ibbs.h
@@ -0,0 +1,59 @@
+
+  void IBBS_Init ( void );
+    /*
+     * IBBS data is initialized.  MUST be called before any other IBBS_*
+     * functions are called.
+     */
+
+  void IBBS_Close ( void );
+    /*
+     * Closes down IBBS.
+     */
+
+  void IBBS_LoginStats ( void );
+    /*
+     * Shows IBBS stats for local login.
+     */
+
+  void IBBS_Maint ( void );
+
+  void IBBS_SendAttackPacket(struct empire *AttackingEmpire, struct Army *AttackingArmy,
+    _INT16 Goal, _INT16 ExtentOfAttack, _INT16 TargetType, _INT16 ClanID[2], _INT16 DestID);
+
+  void IBBS_SendSpy( struct empire *Empire, _INT16 DestID );
+
+  void IBBS_ShowLeagueAscii ( void );
+  void IBBS_LeagueInfo ( void );
+
+  void IBBS_SendPacket ( _INT16 PacketType, long PacketLength, void *PacketData,
+                          _INT16 DestID );
+
+  void IBBS_UpdateReset ( void );
+
+  void IBBS_UpdateRecon ( void );
+
+  void IBBS_SendPacketFile ( _INT16 DestID, char *pszSendFile );
+
+
+  void IBBS_SeeVillages ( BOOL Travel );
+
+  void IBBS_TravelMaint ( void );
+
+  void IBBS_CurrentTravelInfo ( void );
+  void IBBS_BackupMaint( void );
+
+  void IBBS_SendComeBack( _INT16 BBSIdTo, struct clan *Clan );
+
+  BOOL IBBS_InList( char *szName, BOOL ClanName );
+
+  void RemoveFromUList(_INT16 ClanID[2]);
+
+  void IBBS_DistributeNDX ( void );
+
+  void IBBS_SendReset ( _INT16 DestID );
+  void IBBS_SendRecon ( _INT16 DestID );
+
+  void LeagueKillUser ( struct UserInfo *User );
+
+  void IBBS_PacketIn ( void );
+  void IBBS_LeagueNewUser ( struct UserInfo *User );
diff --git a/src/doors/clans-src/init.h b/src/doors/clans-src/init.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc
--- /dev/null
+++ b/src/doors/clans-src/init.h
@@ -0,0 +1 @@
+
diff --git a/src/doors/clans-src/input.c b/src/doors/clans-src/input.c
new file mode 100644
index 0000000000000000000000000000000000000000..ba9a613f15ab68352ce12f623393eaaee75f6244
--- /dev/null
+++ b/src/doors/clans-src/input.c
@@ -0,0 +1,675 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Input ADT
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+
+#include "structs.h"
+#include <OpenDoor.h>
+#include "language.h"
+#include "mstrings.h"
+#include "myopen.h"
+#include "door.h"
+#include "help.h"
+
+extern struct Language *Language;
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 Similar( char *string, char *word )
+    /*
+     * Returns TRUE if the first N chars of string match the first N chars of
+     * word.  N being the strlen of word.
+     */
+  {
+    _INT16 NumLetters = strlen(word);
+    _INT16 CurLetter;
+
+    for (CurLetter = 0; CurLetter < NumLetters; CurLetter++)
+    {
+      if (string[CurLetter] == 0)
+        break;
+
+      if ( toupper(string[CurLetter]) != toupper(word[CurLetter]))
+        break;
+    }
+
+    if (CurLetter != NumLetters)
+      return FALSE;
+    else
+      return TRUE;
+  }
+
+
+  _INT16 InsideStr(char *SubString, char *FullString, _INT16 AtStart)
+    /*
+     * Returns TRUE if SubString appears within FullString.
+     *
+     * PRE: AtStart is TRUE if you only want to check the start of the string.
+     */
+  {
+    _INT16 NumLetters = strlen(FullString);
+    _INT16 CurLetter = 0;
+
+    if (*SubString == 0)
+      return FALSE;
+
+    if (AtStart == FALSE)
+    {
+      /* if AtStart set, only checks start of string for match */
+      for (CurLetter = 0; CurLetter < NumLetters; CurLetter++)
+      {
+        //od_printf("Comparing letter #%d:  ", CurLetter);
+        if (Similar(&FullString[CurLetter], SubString))
+          return TRUE;
+      }
+    }
+    else
+    {
+      if (Similar(&FullString[CurLetter], SubString))
+        return TRUE;
+    }
+
+    //rputs("Returning FALSE.");
+
+    return FALSE;
+  }
+
+
+  void ListChoices( char **apszChoices, _INT16 NumChoices, _INT16 DisplayType )
+    /*
+     * This lists the choices used by GetStringChoice.
+     *
+     * PRE: DisplayType determines how the choices are listed, wide or long.
+     */
+  {
+    _INT16 iTemp;
+    char szString[128];
+
+    if (DisplayType == DT_WIDE)
+    {
+      rputs(ST_HELPLINE);
+
+      for (iTemp = 0; iTemp < NumChoices; iTemp++)
+      {
+        if (iTemp%3 == 0)
+          rputs(" ");
+
+        sprintf(szString, "%-25s ", apszChoices[iTemp]);
+        rputs(szString);
+
+        if ((iTemp+1)%3 == 0)
+          rputs("\n");
+      }
+
+      if ( iTemp%3 != 0 )
+        rputs("\n");
+
+      /* put footer */
+      rputs(ST_HELPLINE);
+    }
+    else if (DisplayType == DT_LONG)
+    {
+      rputs(ST_LONGLINE);
+      rputs("|07");
+
+      for (iTemp = 0; iTemp < NumChoices; iTemp++)
+      {
+        sprintf(szString, " %-s\n", apszChoices[iTemp]);
+        rputs(szString);
+      }
+
+      /* put footer */
+      rputs(ST_LONGLINE);
+    }
+  }
+
+
+  void GetStringChoice ( char **apszChoices, _INT16 NumChoices, char *szPrompt,
+    _INT16 *UserChoice, BOOL ShowChoicesInitially, _INT16 DisplayType, BOOL AllowBlank )
+    /*
+     * This will choose a string from a listing and return which was chosen in
+     * UserChoice.
+     *
+     * PRE:   apszChoices is an array of the choices (strings)
+     *        NumChoices contains how many total choices (strings) there are
+     *        szPrompt contains the string to prompt user with.
+     *        ShowChoicesInitially = TRUE if you wish to list the choices
+     *          when this is called.
+     *        DisplayType determines how the choices are listed.
+     *        AllowBlank = TRUE if you wish to allow the user to choose nothing
+     *          (i.e. press enter) or = FALSE if you want the user to choose
+     *          one of the options.
+     */
+  {
+    char szUserInput[40], Key, *szString;
+    BOOL ShowedTopic, WantsHelp, BackSpace, Inside;
+    _INT16 iTemp, LastTopicFound = -1, CurChar = 0, TimesInStr = 0, TopicFound = 0;
+
+    /* init stuff */
+    szUserInput[0] = 0;
+
+    ShowedTopic = FALSE;
+    WantsHelp = FALSE;
+
+    /* show all topics */
+
+    szString = MakeStr(128);
+
+    if (ShowChoicesInitially)
+    {
+      /* show all choices */
+      ListChoices(apszChoices, NumChoices, DisplayType);
+    }
+
+    for (;;)
+    {
+      /* enter topic or ? etc... */
+      rputs(szPrompt);
+
+    /* user enters words and stuff */
+		for (;;)
+		{
+      /* enter a char */
+      /* and update szString */
+			od_sleep(0);
+			Key = od_get_key(TRUE);
+
+			if (Key == '?' && CurChar == 0)
+			{
+        rputs(ST_DISPLAYTOPICS);
+				WantsHelp = TRUE;
+				break;
+			}
+
+			/* if user presses [Enters] exit loop */
+			if (Key == '\r' || Key == '\n')
+			{
+				rputs("\n");
+				break;
+			}
+			else if (Key == '\x19')
+			{
+				/* ctrl-Y */
+        if (ShowedTopic && LastTopicFound != -1)
+          for (iTemp = 0; iTemp < (signed)strlen(apszChoices[LastTopicFound]); iTemp++)
+            rputs("\b \b");
+				else
+          for (iTemp = 0; iTemp < (signed)strlen(szUserInput); iTemp++)
+						rputs("\b \b");
+
+        szUserInput[0] = 0;
+				CurChar = 0;
+				ShowedTopic = FALSE;
+
+				continue;
+			}
+
+			/* if backspace */
+			else if (Key == '\b' || Key == 127)
+			{
+        BackSpace = TRUE;
+				if (CurChar != 0)
+				{
+					if (!ShowedTopic)
+						rputs("\b \b");
+
+					CurChar--;
+          szUserInput[CurChar] = 0;
+				}
+			}
+
+			/* if already 29 letters, stop */
+			else if (CurChar == 30)
+				continue;
+			else if (iscntrl(Key))
+				continue;
+
+			/* else, make next letter equal to key */
+			else
+			{
+				BackSpace = FALSE;
+        szUserInput[CurChar++] = Key;
+        szUserInput[CurChar] = 0;
+			}
+
+      /* Display the szString as is IF at least 2 szStrings have the subszString */
+      TimesInStr = 0;
+      for (iTemp = 0; iTemp < NumChoices; iTemp++)
+			{
+        if (stricmp(szUserInput, apszChoices[iTemp]) == 0)
+				{
+          TopicFound = iTemp;
+					TimesInStr = 1;
+					break;
+				}
+
+        Inside = InsideStr(szUserInput, apszChoices[iTemp], FALSE);
+
+				if (Inside)
+				{
+          TopicFound = iTemp;
+					TimesInStr++;
+				}
+
+			}
+
+			if (TimesInStr == 1)
+        rputs(ST_COLOR14);
+			else
+        rputs(ST_COLOR07);
+
+        if (ShowedTopic && TimesInStr == 1 && LastTopicFound == TopicFound)
+        {
+          /* same topic, do nothing */
+        }
+        /* if typing something does nothing, still show topic word, so
+           no change */
+        else if (ShowedTopic && TimesInStr == 1 && LastTopicFound != TopicFound)
+        {
+          /* show new one */
+          for (iTemp = 0; iTemp < (signed)strlen(apszChoices[LastTopicFound]); iTemp++)
+          {
+            rputs("\b \b");
+          }
+          rputs(apszChoices[TopicFound]);
+          ShowedTopic = TRUE;
+        }
+        /* if typing changes from showtopic to user topic, show user topic */
+        else if (ShowedTopic && TimesInStr != 1)
+        {
+          for (iTemp = 0; iTemp < (signed)strlen(apszChoices[LastTopicFound]); iTemp++)
+          {
+            rputs("\b \b");
+          }
+          rputs(szUserInput);
+          ShowedTopic = FALSE;
+        }
+        /* if typing changes from user topic to showtopic, show topic */
+           else if (ShowedTopic == FALSE && TimesInStr == 1)
+        {
+          /* erase old szString */
+          if (!BackSpace)
+            for (iTemp = 0; iTemp < CurChar-1; iTemp++)
+            {
+              rputs("\b \b");
+            }
+          else if (BackSpace)
+            for (iTemp = 0; iTemp < CurChar; iTemp++)
+            {
+              rputs("\b \b");
+            }
+
+          /* show new one */
+          rputs(apszChoices[TopicFound]);
+          ShowedTopic = TRUE;
+        }
+        /* else show char */
+        else if (!BackSpace)
+          od_putch(szUserInput[CurChar-1]);
+
+        LastTopicFound = TopicFound;
+      }
+
+      if (WantsHelp)
+      {
+        ListChoices(apszChoices, NumChoices, DisplayType);
+
+        WantsHelp = FALSE;
+        szUserInput[0] = 0;
+        CurChar = 0;
+        ShowedTopic = FALSE;
+
+        continue;
+      }
+
+      // user quit
+      if (szUserInput[0] == 0 && AllowBlank)
+        break;
+
+      if (TimesInStr == 1)
+      {
+        rputs("\n");
+        *UserChoice = TopicFound;
+        free(szString);
+        return;
+      }
+      else
+        rputs(ST_INVALIDTOPIC);
+
+      szUserInput[0] = 0;
+      CurChar = 0;
+      ShowedTopic = FALSE;
+    }
+
+    free(szString);
+
+    // none found
+    *UserChoice = -1;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void GetStr(char *InputStr, _INT16 MaxChars, BOOL HiBit)
+    /*
+     * This function allows the user to input a string of MaxChars length and
+     * place it in InputStr.
+     *
+     * PRE: InputStr MAY contain a string which contains a value, HiBit
+     *      can be used to toggle whether the user can enter hibit ascii.
+     */
+  {
+    _INT16 CurChar;
+    unsigned char InputCh;
+    char Spaces[85] = "                                                                                     ";
+    char BackSpaces[85] = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+    char TempStr[190];
+
+    Spaces[MaxChars] = 0;
+    BackSpaces[MaxChars] = 0;
+
+    CurChar = strlen(InputStr);
+
+    rputs(Spaces);
+    rputs(BackSpaces);
+    od_disp_str(InputStr);
+
+    for (;;)
+    {
+      od_sleep(0);
+      InputCh = od_get_key( TRUE);
+
+      if (InputCh == '\b' || InputCh == 127)
+      {
+        if (CurChar>0)
+        {
+          CurChar--;
+          rputs("\b \b");
+        }
+      }
+      else if (InputCh == '\r' || InputCh == '\n')
+      {
+        rputs("|16\n");
+        InputStr[CurChar]=0;
+        break;
+      }
+      else if (InputCh== '' || InputCh == '\x1B')  // ctrl-y
+      {
+        InputStr [0] = 0;
+        strcpy(TempStr, BackSpaces);
+        TempStr[ CurChar ] = 0;
+        rputs(TempStr);
+        Spaces[MaxChars] = 0;
+        BackSpaces[MaxChars] = 0;
+        rputs(Spaces);
+        rputs(BackSpaces);
+        CurChar = 0;
+      }
+      else if (InputCh >= '' && HiBit == FALSE)
+        continue;
+      else if (InputCh == 0)
+        continue;
+  //      else if (iscntrl(InputCh) && InputCh < 30 || HiBit == FALSE)
+      else if (iscntrl(InputCh) && InputCh < 30)
+        continue;
+      else if (isalpha(InputCh) && CurChar && InputStr[CurChar-1] == SPECIAL_CODE)
+        continue;
+      else  /* valid character input */
+      {
+        if (CurChar==MaxChars)   continue;
+        InputStr[CurChar++]=InputCh;
+        InputStr[CurChar] = 0;
+        od_putch(InputCh);
+      }
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 GetChoice ( char *DisplayFile, char *Prompt, char *Options[], char *Keys, char DefChar, BOOL ShowTime)
+    /*
+     * This function allows the user to choose an option from the options
+     * listed.  Works much like FE's input system.
+     *
+     * PRE: DisplayFile contains the name of file to display.
+     *      Prompt contains the prompt user will see.
+     *      Options contains the array of options.
+     *      Keys contains the corresponding keys to input to choose options.
+     *      DefChar MUST contain the default character the user will choose if he
+     *        presses Enter.
+     *      ShowTime is set to TRUE if the time is to be displayed in prompt.
+     */
+  {
+    _INT16 cTemp, DefChoice;
+    char KeysAndEnter[50], Choice, Spaces[] = "                      \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+    char TimeStr[40];
+    _INT16 HoursLeft, MinutesLeft;
+
+    HoursLeft = (od_control.user_timelimit - od_control.user_time_used)/60;
+    MinutesLeft = (od_control.user_timelimit - od_control.user_time_used)%60;
+
+    if (MinutesLeft < 0)
+      MinutesLeft = 0;
+
+    sprintf(TimeStr, " |0H[|0I%02d:%02d|0H] ", HoursLeft, MinutesLeft);
+
+    /* figure out default char */
+    for (cTemp = 0; cTemp < (signed)strlen(Keys); cTemp++)
+    {
+      if (DefChar == Keys[cTemp])
+        break;
+    }
+    DefChoice = cTemp;
+
+    /* KeysAndEnter is just Keys[] + "\r" */
+    strcpy(KeysAndEnter, Keys);
+    strcat(KeysAndEnter, "\r\n ");
+
+    cTemp = strlen(KeysAndEnter);
+
+    /* now get input */
+
+    /* Display file */
+    if (DisplayFile[0])
+    {
+      if (strchr(DisplayFile, '.'))
+        Display(DisplayFile);
+      else
+        Help(DisplayFile, ST_MENUSHLP);
+    }
+
+    /* time */
+    if (ShowTime)
+      rputs(TimeStr);
+
+    /* Display prompt, and default option */
+    rputs(Prompt);
+    rputs(Options[DefChoice]);
+
+    /* make sure it's not the special key! */
+    do
+      Choice = od_get_answer(KeysAndEnter);
+    while (Choice == '\xFF');
+
+    if (Choice == '\r' || Choice == DefChar || Choice == ' ' || Choice == '\n')
+    {
+      cTemp = DefChoice;
+    }
+    else
+      for (cTemp = 0; cTemp < (signed)strlen(Keys); cTemp++)
+      {
+        if ( Choice == Keys[cTemp] )
+          break;
+      }
+
+    /* display choice */
+    rputs("\r");
+
+    HoursLeft = (od_control.user_timelimit - od_control.user_time_used)/60;
+    MinutesLeft = (od_control.user_timelimit - od_control.user_time_used)%60;
+    sprintf(TimeStr, " |0H[|0J%02d:%02d|0H] ", HoursLeft, MinutesLeft);
+
+    if (ShowTime)
+      rputs(TimeStr);
+
+    rputs(Prompt);
+    rputs(Spaces);
+    rputs("|15");
+    rputs(Options[cTemp]);
+    rputs("\n\n");
+
+    return (Keys[cTemp]);
+
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  long GetLong( char *Prompt, long DefaultVal, long Maximum )
+    /*
+     * This allows the user to input a long integer.
+     *
+     */
+  {
+    char string[155], NumString[13], InputChar, DefMax[40];
+    _INT16 NumDigits, CurDigit = 0, cTemp;
+    long TenPower;
+
+    /* init screen */
+    rputs(Prompt);
+
+    sprintf(DefMax, " |08(|15%ld|07; %ld|08) |15", DefaultVal, Maximum);
+    rputs(DefMax);
+
+    /* NumDigits contains amount of digits allowed using max. value input */
+
+    TenPower = 10;
+    for (NumDigits = 1; NumDigits < 11; NumDigits++)
+    {
+      if (labs(Maximum) < TenPower )
+        break;
+
+      TenPower *= 10;
+    }
+    if (Maximum < 0L)
+      NumDigits++;
+
+    /* now get input */
+    for (;;)
+    {
+      InputChar = od_get_answer("0123456789><.,\r\n\b\x19\x7f");
+
+      if (isdigit(InputChar))
+      {
+        if (CurDigit < NumDigits)
+        {
+          NumString[CurDigit++] = InputChar;
+          NumString[CurDigit] = 0;
+          od_putch(InputChar);
+        }
+
+      }
+      else if (InputChar == '\b' || InputChar == 127)
+      {
+        if (CurDigit > 0)
+        {
+          CurDigit--;
+          NumString[CurDigit] = 0;
+          rputs("\b \b");
+        }
+      }
+      else if (InputChar == '>' || InputChar == '.')
+      {
+        /* get rid of old value, by showing backspaces */
+        for (cTemp = 0; cTemp < CurDigit; cTemp++)
+          rputs("\b \b");
+
+        sprintf(string, "%-ld", Maximum);
+        string[NumDigits] = 0;
+        rputs(string);
+
+        strcpy(NumString, string);
+        CurDigit = NumDigits;
+      }
+      else if (InputChar == '<' || InputChar == ',' || InputChar == 25)
+      {
+        /* get rid of old value, by showing backspaces */
+        for (cTemp = 0; cTemp < CurDigit; cTemp++)
+          rputs("\b \b");
+
+        CurDigit = 0;
+        string[CurDigit] = 0;
+
+        strcpy(NumString, string);
+      }
+      else if (InputChar == '\r' || InputChar == '\n')
+      {
+        if (CurDigit == 0)
+        {
+          sprintf(string, "%-ld", DefaultVal);
+          string[NumDigits] = 0;
+          rputs(string);
+
+          strcpy(NumString, string);
+          CurDigit = NumDigits;
+
+          rputs("\n");
+          break;
+        }
+        /* see if number too high, if so, make it max */
+        else if (atol(NumString) > Maximum)
+        {
+          /* get rid of old value, by showing backspaces */
+          for (cTemp = 0; cTemp < CurDigit; cTemp++)
+            rputs("\b \b");
+
+          sprintf(string, "%-ld", Maximum);
+          string[NumDigits] = 0;
+          rputs(string);
+
+          strcpy(NumString, string);
+          CurDigit = NumDigits;
+        }
+        else  /* is a valid value */
+        {
+          rputs("\n");
+          break;
+        }
+      }
+    }
+
+    return (atol(NumString));
+  }
+
+
diff --git a/src/doors/clans-src/input.h b/src/doors/clans-src/input.h
new file mode 100644
index 0000000000000000000000000000000000000000..3e7fc445afe8d983e33c577b2f841693fc28ec95
--- /dev/null
+++ b/src/doors/clans-src/input.h
@@ -0,0 +1,45 @@
+  _INT16 GetChoice ( char *DisplayFile, char *Prompt, char *Options[], char *Keys, char DefChar, __BOOL ShowTime);
+    /*
+     * This function allows the user to choose an option from the options
+     * listed.  Works much like FE's input system.
+     *
+     * PRE: DisplayFile contains the name of file to display.
+     *      Prompt contains the prompt user will see.
+     *      Options contains the array of options.
+     *      Keys contains the corresponding keys to input to choose options.
+     *      DefChar MUST contain the default character the user will choose if he
+     *        presses Enter.
+     *      ShowTime is set to TRUE if the time is to be displayed in prompt.
+     */
+
+  void GetStr(char *InputStr, _INT16 MaxChars, __BOOL HiBit);
+    /*
+     * This function allows the user to input a string of MaxChars length and
+     * place it in InputStr.
+     *
+     * PRE: InputStr MAY contain a string which contains a value, HiBit
+     *      can be used to toggle whether the user can enter hibit ascii.
+     */
+
+  long GetLong( char *Prompt, long DefaultVal, long Maximum );
+    /*
+     * This allows the user to input a long integer.
+     *
+     */
+
+  void GetStringChoice ( char **apszChoices, _INT16 NumChoices, char *szPrompt,
+    _INT16 *UserChoice, __BOOL ShowChoicesInitially, _INT16 DisplayType, __BOOL AllowBlank );
+    /*
+     * This will choose a string from a listing and return which was chosen in
+     * UserChoice.
+     *
+     * PRE:   apszChoices is an array of the choices (strings)
+     *        NumChoices contains how many total choices (strings) there are
+     *        szPrompt contains the string to prompt user with.
+     *        ShowChoicesInitially = TRUE if you wish to list the choices
+     *          when this is called.
+     *        DisplayType determines how the choices are listed.
+     *        AllowBlank = TRUE if you wish to allow the user to choose nothing
+     *          (i.e. press enter) or = FALSE if you want the user to choose
+     *          one of the options.
+     */
diff --git a/src/doors/clans-src/interbbs.h b/src/doors/clans-src/interbbs.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a04f8b627af961e03f217513edb387ebc14734f
--- /dev/null
+++ b/src/doors/clans-src/interbbs.h
@@ -0,0 +1,161 @@
+/*
+ * Code taken from the OpenDoors sample IBBS code.
+ */
+
+#ifndef INTERBBS_H
+#define INTERBBS_H
+
+
+/******************************************************************************/
+/*						   Configuration Constants							  */
+/******************************************************************************/
+#define PROG_NAME_CHARS    35
+#define PATH_CHARS         80
+#define FILENAME_CHARS     12
+#define MESSAGE_SUBJECT    "OpenDoors Inter-BBS Door Message"
+#define MESSAGE_PID        "\1PID: ODIBMS 1\r"
+#define MAX_LINE_LENGTH    70
+#define MESSAGE_HEADER     "$"
+#define MESSAGE_FOOTER     "$"
+#define DELIMITER_CHAR     '$'
+#define NODE_ADDRESS_CHARS 23
+#define SYSTEM_NAME_CHARS  40
+#define LOCATION_CHARS     40
+
+/******************************************************************************/
+/*								  Data Types								  */
+/******************************************************************************/
+#ifndef tBool
+typedef _INT16 tBool;
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#if !defined(DWORD_DEFINED) && !defined(DWORD)
+typedef unsigned long DWORD;
+#endif
+
+#if !defined(WORD_DEFINED) && !defined(_MSC_VER)
+#ifndef WORD
+typedef unsigned _INT16 WORD;
+#endif
+#endif
+
+typedef enum
+   {
+   eSuccess,
+   eNoMoreMessages,
+   eGeneralFailure,
+   eBadParameter,
+   eNoMemory,
+   eMissingDir,
+   eFileOpenError
+   } tIBResult;
+
+typedef struct PACKED
+   {
+   char szAddress[NODE_ADDRESS_CHARS + 1];
+   char szSystemName[SYSTEM_NAME_CHARS + 1];
+   char szLocation[LOCATION_CHARS + 1];
+   } PACKED tOtherNode;
+
+typedef struct PACKED
+   {
+   char szThisNodeAddress[NODE_ADDRESS_CHARS + 1];
+   char szProgName[PROG_NAME_CHARS + 1];
+   char szNetmailDir[PATH_CHARS + 1];
+   tBool bCrash;
+   tBool bHold;
+   tBool bEraseOnSend;
+   tBool bEraseOnReceive;
+   _INT16 nTotalSystems;
+   tOtherNode *paOtherSystem;
+   }  PACKED tIBInfo;
+
+
+/******************************************************************************/
+/*                         InterBBS API Functions                             */
+/******************************************************************************/
+tIBResult IBSend(tIBInfo *pInfo, char *pszDestNode, void *pBuffer,
+                 _INT16 nBufferSize);
+tIBResult IBSendAll(tIBInfo *pInfo, void *pBuffer, _INT16 nBufferSize);
+tIBResult IBGet(tIBInfo *pInfo, void *pBuffer, _INT16 nMaxBufferSize);
+tIBResult IBReadConfig(tIBInfo *pInfo, char *pszConfigFile);
+
+
+/******************************************************************************/
+/*							 Private Declarations							  */
+/******************************************************************************/
+typedef struct PACKED
+   {
+   char szFromUserName[36];
+   char szToUserName[36];
+   char szSubject[72];
+   char szDateTime[20]; 		/* "DD Mon YY  HH:MM:SS" */
+   WORD wTimesRead;
+   WORD wDestNode;
+   WORD wOrigNode;
+   WORD wCost;					/* Lowest unit of originator's currency */
+   WORD wOrigNet;
+   WORD wDestNet;
+   WORD wDestZone;
+   WORD wOrigZone;
+   WORD wDestPoint;
+   WORD wOrigPoint;
+   WORD wReplyTo;
+   WORD wAttribute;
+   WORD wNextReply;
+   }  PACKED tMessageHeader;
+
+#define ATTRIB_PRIVATE		0x0001
+#define ATTRIB_CRASH		0x0002
+#define ATTRIB_RECEIVED 	0x0004
+#define ATTRIB_SENT 		0x0008
+#define ATTRIB_FILE_ATTACH	0x0010
+#define ATTRIB_IN_TRANSIT	0x0020
+#define ATTRIB_ORPHAN		0x0040
+#define ATTRIB_KILL_SENT	0x0080
+#define ATTRIB_LOCAL		0x0100
+#define ATTRIB_HOLD 		0x0200
+#define ATTRIB_FILE_REQUEST 0x0800
+#define ATTRIB_RECEIPT_REQ	0x1000
+#define ATTRIB_IS_RECEIPT	0x2000
+#define ATTRIB_AUDIT_REQ	0x4000
+#define ATTRIB_FILE_UPDATE	0x8000
+
+typedef struct PACKED
+   {
+   WORD wZone;
+   WORD wNet;
+   WORD wNode;
+   WORD wPoint;
+   } PACKED tFidoNode;
+
+
+tBool DirExists(const char *pszDirName);
+void MakeFilename(const char *pszPath, const char *pszFilename, char *pszOut);
+tIBResult ValidateInfoStruct(tIBInfo *pInfo);
+tBool CreateMessage(char *pszMessageDir, tMessageHeader *pHeader,
+					char *pszText);
+DWORD GetFirstUnusedMsgNum(char *pszMessageDir);
+void GetMessageFilename(char *pszMessageDir, DWORD lwMessageNum,
+						char *pszOut);
+tBool WriteMessage(char *pszMessageDir, DWORD lwMessageNum,
+				   tMessageHeader *pHeader, char *pszText);
+tBool ReadMessage(char *pszMessageDir, DWORD lwMessageNum,
+				  tMessageHeader *pHeader, char **ppszText);
+DWORD GetNextMSGID(void);
+_INT16 GetMaximumEncodedLength(_INT16 nUnEncodedLength);
+void EncodeBuffer(char *pszDest, const void *pBuffer, _INT16 nBufferSize);
+void DecodeBuffer(const char *pszSource, void *pDestBuffer, _INT16 nBufferSize);
+void ConvertAddressToString(char *pszDest, const tFidoNode *pNode);
+void ConvertStringToAddress(tFidoNode *pNode, const char *pszSource);
+tBool ProcessConfigFile(char *pszFileName, _INT16 nKeyWords, char **papszKeyWord,
+                  void (*pfCallBack)(int, char *, void *), void *pCallBackData);
+void ProcessConfigLine(_INT16 nKeyword, char *pszParameter, void *pCallbackData);
+tIBResult IBSendFileAttach(tIBInfo *pInfo, char *pszDestNode, char *pszFileName);
+#endif
diff --git a/src/doors/clans-src/items.c b/src/doors/clans-src/items.c
new file mode 100644
index 0000000000000000000000000000000000000000..75ff87e74021100002fcf3d54729d93fcde8aa4c
--- /dev/null
+++ b/src/doors/clans-src/items.c
@@ -0,0 +1,990 @@
+
+/*
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "myopen.h"
+#include "items.h"
+#include "spells.h"
+#include "door.h"
+#include <OpenDoor.h>
+#include "help.h"
+#include "input.h"
+
+#define MT_POLYMETRAL	1
+#define MT_LACONIA		2
+
+
+struct {
+  BOOL Initialized;
+  _INT16 NumItems;
+
+  struct item_data *Data[MAX_ITEMS];
+} Items = { FALSE, 0 };
+
+extern struct IniFile IniFile;
+extern struct Language *Language;
+extern struct game Game;
+extern struct clan *PClan;
+extern struct village Village;
+extern struct Spell *Spells[MAX_SPELLS];
+
+
+
+// ------------------------------------------------------------------------- //
+  void Items_FindTreasureChest ( void )
+  {
+    char *RandomTable, szString[128], szItemName[25];
+    _INT16 CurItem, CurLevel, RandIndex, ChosenItem;
+
+    Items_Init();
+
+    RandomTable = malloc(Items.NumItems*10);
+    CheckMem(RandomTable);
+
+    // generate random table
+    for (CurItem = 0, RandIndex = 0; CurItem < Items.NumItems; CurItem++)
+    {
+      for (CurLevel = 0; CurLevel < Items.Data[CurItem]->RandLevel; CurLevel++)
+      {
+        RandomTable[ RandIndex++ ] = CurItem;
+      }
+    }
+
+    // choose one of those items
+    ChosenItem = RandomTable[ RANDOM(RandIndex) ];
+
+    // give him that item
+    // sprintf(szString, "|07You find |15%s|07. |0STake it?", Items[ ChosenItem ]->szName);
+    sprintf(szString, ST_TREASURE0, Items.Data[ ChosenItem ]->szName);
+
+    strcpy(szItemName, Items.Data[ ChosenItem ]->szName);
+    free(RandomTable);
+    Items_Close();
+
+    if (YesNo(szString) == YES)
+    {
+      // give item reloads items!
+      Items_GiveItem(szItemName);
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+  void ReadBook ( void )
+  {
+    _INT16 DefaultItemIndex, iTemp, ItemIndex, WhichMember;
+    char cKey, szString[128];
+
+    // which book?
+
+    // see if anything to read
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+    {
+      if (PClan->Items[iTemp].Available)
+        break;
+    }
+    if (iTemp == MAX_ITEMS_HELD)
+    {
+      rputs(ST_ISTATS2);
+      return;
+    }
+
+    /* find first item in inventory which is a book */
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+    {
+      if (PClan->Items[iTemp].Available &&
+        PClan->Items[iTemp].cType == I_BOOK)
+        break;
+    }
+    if (iTemp == MAX_ITEMS_HELD)
+    {
+      rputs("|04No books found.\n");
+      return;
+    }
+    else
+      DefaultItemIndex = iTemp+1;
+
+    ItemIndex = (_INT16) GetLong(ST_ISTATS3, DefaultItemIndex, MAX_ITEMS_HELD);
+    if (ItemIndex == 0)
+      return;
+    ItemIndex--;
+
+    /* if that item is non-existant, tell him */
+    if (PClan->Items[ItemIndex].Available == FALSE ||
+      PClan->Items[ItemIndex].cType != I_BOOK)
+    {
+      rputs(ST_INVALIDITEM);
+      return;
+    }
+    ShowItemStats(&PClan->Items[ItemIndex], PClan);
+
+    // choose who will read it
+    rputs("\n");
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp] && iTemp < Game.Data->MaxPermanentMembers)
+      {
+        sprintf(szString, "|0A(|0B%c|0A) |0C%s\n",
+          iTemp + 'A', PClan->Member[iTemp]->szName);
+        rputs(szString);
+      }
+    }
+    rputs("|0SWho will read it? |04[Enter=abort] |0F");
+
+    for (;;)
+    {
+      cKey = toupper(od_get_key(TRUE));
+
+      if (cKey == '\r' || cKey == '\n')
+      {
+        rputs(ST_ABORTED);
+        return;
+      }
+
+      WhichMember = cKey - 'A';
+
+      if (WhichMember >= 0 && WhichMember < Game.Data->MaxPermanentMembers)
+      {
+        if (PClan->Member[ WhichMember ])
+        {
+          rputs(PClan->Member[ WhichMember ]->szName);
+          rputs("\n");
+          break;
+        }
+      }
+    }
+
+    // see what can read
+    if (ItemPenalty(PClan->Member[ WhichMember], &PClan->Items[ItemIndex]))
+    {
+      sprintf(szString, "%s cannot read that book!\n",
+        PClan->Member[ WhichMember]->szName);
+      rputs(szString);
+      return;
+    }
+
+    // find next spell index open AND see if spell already known
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+    {
+      if (PClan->Member[ WhichMember]->SpellsKnown[iTemp]-1 ==
+        PClan->Items[ItemIndex].SpellNum &&
+        PClan->Items[ItemIndex].SpellNum != -1)
+      {
+        // already know this spell
+        rputs("|0CThat character already knows that spell.\n");
+        return;
+      }
+
+      if (PClan->Member[ WhichMember]->SpellsKnown[iTemp] == 0)
+        break;
+    }
+
+    if (iTemp == MAX_SPELLS)
+    {
+      rputs("|07That characters knows already too many spells.\n");
+      return;
+    }
+
+    // list who can read it
+
+    // make him read it NOW
+    sprintf(szString, "|0B%s |0Creads the book...\n",
+      PClan->Member[ WhichMember ]->szName);
+    rputs(szString);
+
+    if (PClan->Items[ ItemIndex ].SpellNum != -1)
+    {
+      sprintf(szString, "|0C%s learns the |0B%s |0Cspell.\n",
+        PClan->Member[ WhichMember ]->szName,
+        Spells[ PClan->Items[ ItemIndex ].SpellNum ]->szName);
+      rputs(szString);
+
+      // learn it
+      PClan->Member[ WhichMember ]->SpellsKnown[iTemp] =
+        PClan->Items[ ItemIndex ].SpellNum + 1;
+    }
+
+    // if HPadd
+    if (PClan->Items[ ItemIndex ].HPAdd)
+    {
+      sprintf(szString, "|0C%s gains |0B%d HP\n",
+        PClan->Member[ WhichMember ]->szName,
+        PClan->Items[ ItemIndex ].HPAdd);
+      rputs(szString);
+
+      PClan->Member[ WhichMember ]->MaxHP +=
+        PClan->Items[ ItemIndex ].HPAdd;
+
+      PClan->Member[ WhichMember ]->HP =
+        PClan->Member[ WhichMember ]->MaxHP;
+    }
+
+    // if SPadd
+    if (PClan->Items[ ItemIndex ].SPAdd)
+    {
+      sprintf(szString, "|0C%s gains |0B%d SP\n",
+        PClan->Member[ WhichMember ]->szName,
+        PClan->Items[ ItemIndex ].SPAdd);
+      rputs(szString);
+
+      PClan->Member[ WhichMember ]->MaxSP +=
+        PClan->Items[ ItemIndex ].SPAdd;
+
+      PClan->Member[ WhichMember ]->SP =
+        PClan->Member[ WhichMember ]->MaxSP;
+    }
+
+    // get rid of item
+    PClan->Items[ ItemIndex ].Available = FALSE;
+
+  }
+
+
+// ------------------------------------------------------------------------- //
+  __BOOL ItemPenalty ( struct pc *PC, struct item_data *Item )
+    /*
+     * This function will check to see if PC has the required attributes to
+     * use the item.  If he does, FALSE is returned, otherwise, TRUE.
+     */
+  {
+    _INT16 iTemp;
+    BOOL Penalty = FALSE;
+
+    for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+      if (PC->Attributes[iTemp] < Item->ReqAttributes[iTemp]
+        && Item->ReqAttributes[iTemp])
+        Penalty = TRUE;
+
+    return Penalty;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void ItemUseableBy ( struct item_data *Item )
+    /*
+     * This function outputs who in PClan may use the item.
+     *
+     */
+  {
+    _INT16 CurMember/*, iTemp*/;
+    char szString[128];
+    struct pc *PC;
+    BOOL ShownOne;
+
+    rputs("\n|0CThe following members may use this item:\n|0B");
+
+    // go through each member
+    ShownOne = FALSE;    // haven't shown at least one member yet
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (PClan->Member[CurMember] == NULL)
+        continue;
+
+      // if he meets the requirements, display him
+      PC = PClan->Member[CurMember];
+
+      if (ItemPenalty(PC, Item) == FALSE)
+      {
+        if (ShownOne)
+          rputs(", ");
+
+        sprintf(szString, "%s", PC->szName);
+        rputs(szString);
+
+        ShownOne = TRUE;
+      }
+    }
+    if (ShownOne)
+      rputs("\n");
+    else
+      rputs("No one\n");
+  }
+
+
+  void ShowItemStats ( struct item_data *Item, struct clan *Clan )
+    /*
+     * This function displays the stats for the item AND who is using it
+     * within Clan AND who can use it within PClan.
+     */
+  {
+    char *szAttributeNames[NUM_ATTRIBUTES];
+    _INT16 iTemp/*, AttributesShown*/;
+    char szString[128]/*, szFullString[128]*/;
+    _INT16 CurBonus, CurReq, CurLine;
+    char *szAttr[NUM_ATTRIBUTES] = {
+      "AGI",
+      "DEX",
+      "STR",
+      "WIS",
+      "ARM",
+      "CHR"};
+    char szLine[128];
+    char *szIcon[6];
+
+    switch (Item->cType)
+    {
+      case I_WEAPON :
+        LoadStrings(1210, 6, szIcon);
+        break;
+      case I_ARMOR :
+        LoadStrings(1216, 6, szIcon);
+        break;
+      case I_SHIELD :
+        LoadStrings(1222, 6, szIcon);
+        break;
+      case I_SCROLL :
+        LoadStrings(1228, 6, szIcon);
+        break;
+      case I_BOOK :
+        LoadStrings(1234, 6, szIcon);
+        break;
+      case I_OTHER :
+        LoadStrings(1240, 6, szIcon);
+        break;
+    }
+
+    CurBonus = 0;
+    CurReq = 0;
+
+    LoadStrings(10, 6, szAttributeNames);
+
+    // show first lines here
+    rputs("\n");
+    sprintf(szString, "|0B %s\n", Item->szName);
+    rputs(szIcon[0]);
+    rputs(szString);
+    rputs(szIcon[1]);
+    rputs("|0A哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪腬n");
+    rputs(szIcon[2]);
+
+    if (Item->cType != I_SCROLL && Item->cType != I_BOOK &&
+        Item->cType != I_OTHER)
+    {
+      rputs("|15 Modifiers        |12Requirements\n");
+
+      for (CurLine = 0; CurLine < 3; CurLine++)
+      {
+        strcpy(szLine, " ");
+
+        for (iTemp = 0; iTemp < 2; iTemp++)
+        {
+          // find stat modified
+          for (;CurBonus < NUM_ATTRIBUTES; CurBonus++)
+          {
+            if (Item->Attributes[CurBonus])
+              break;  // found one
+          }
+
+          if (CurBonus != NUM_ATTRIBUTES)
+          {
+            if (Item->Attributes[CurBonus] < 0)
+              sprintf(szString, "|04%2d %s ",
+                Item->Attributes[CurBonus], szAttr[CurBonus]);
+            else if (Item->Attributes[CurBonus] > 0)
+              sprintf(szString, "|0C%2d %s ",
+                Item->Attributes[CurBonus], szAttr[CurBonus]);
+
+            CurBonus++;
+          }
+          else strcpy(szString, "       ");
+
+          strcat(szLine, szString);
+        }
+
+        strcat(szLine, "   ");
+
+        for (iTemp = 0; iTemp < 2; iTemp++)
+        {
+          // find next requirement
+          for (;CurReq < NUM_ATTRIBUTES; CurReq++)
+          {
+            if (Item->ReqAttributes[CurReq])
+              break;  // found one
+          }
+
+          if (CurReq != NUM_ATTRIBUTES)
+          {
+            sprintf(szString, "|0C%2d %s ", Item->ReqAttributes[CurReq], szAttr[CurReq]);
+            CurReq++;
+          }
+          else szString[0] = 0;
+
+          strcat(szLine, szString);
+        }
+
+        // display line now
+        rputs(szIcon[CurLine+3]); // icon first
+        rputs(szLine);
+        rputs("\n");
+      }
+    }
+    else if (Item->cType == I_SCROLL)
+    {
+      sprintf(szString, " |0B%d Use(s) Left\n", Item->Energy);
+      rputs(szString);
+
+      for (CurLine = 3; CurLine < 6; CurLine++)
+      {
+        rputs(szIcon[CurLine]);
+        rputs("\n");
+      }
+    }
+    else if (Item->cType == I_BOOK || Item->cType == I_OTHER)
+    {
+      if (Item->cType == I_BOOK)
+        rputs(" |0CHave a wizard examine this.\n");
+      else
+        rputs("\n");
+
+      for (CurLine = 3; CurLine < 6; CurLine++)
+      {
+        // display icon only
+        rputs(szIcon[CurLine]);
+        rputs("\n");
+      }
+    }
+
+    // show who's using it right now
+    if (Item->UsedBy && Clan)
+    {
+      sprintf(szString, "\n|0CUsed by:  |0B%s\n", Clan->Member[Item->UsedBy - 1]->szName);
+      rputs(szString);
+    }
+
+    // show who can use this without penalty
+    ItemUseableBy(Item);
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void Items_Read ( void )
+  {
+    _INT16 iTemp, NumItems, CurFile, CurItem;
+    struct FileHeader ItemFile;
+
+    for (CurItem = 0; CurItem < MAX_ITEMS; CurItem++)
+      Items.Data[CurItem] = NULL;
+
+
+    // for each file, read in the data
+    for (CurItem = 0, CurFile = 0; CurFile < MAX_ITEMFILES; CurFile++)
+    {
+      if (IniFile.pszItems[CurFile] == NULL)
+        break;
+
+      MyOpen(IniFile.pszItems[CurFile], "rb", &ItemFile);
+      if (ItemFile.fp == NULL) continue;
+
+      // get num items in file
+      fread(&NumItems, sizeof(_INT16), 1, ItemFile.fp);
+
+      // read each item in file
+      for (iTemp = 0; iTemp < NumItems; iTemp++)
+      {
+        Items.Data[CurItem] = malloc(sizeof(struct item_data));
+        CheckMem(Items.Data[CurItem]);
+
+        fread(Items.Data[CurItem], sizeof(struct item_data), 1, ItemFile.fp);
+
+        CurItem++;
+        if (CurItem == MAX_ITEMS) break;
+      }
+      fclose(ItemFile.fp);
+
+      if (CurItem == MAX_ITEMS) break;
+    }
+
+    Items.NumItems = CurItem;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Items_Destroy ( void )
+  {
+    _INT16 CurItem;
+
+    for (CurItem = 0; CurItem < MAX_ITEMS; CurItem++)
+      if (Items.Data[CurItem])
+      {
+        free(Items.Data[CurItem]);
+        Items.Data[CurItem] = NULL;
+      }
+
+    Items.NumItems = 0;
+  }
+
+// ------------------------------------------------------------------------- //
+  void Items_GiveItem ( char *szItemName )
+    /*
+     * This function will give the item with the name specified to
+     * PClan.
+     */
+  {
+    _INT16 iTemp, EmptySlot/*, ItemIndex*/;
+
+    // see if he has room to carry it
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+    {
+      if (PClan->Items[iTemp].Available == FALSE)
+        break;
+    }
+    if (iTemp == MAX_ITEMS_HELD)
+    {
+      /* no more room in inventory */
+      rputs(ST_ITEMNOMOREROOM);
+      return;
+    }
+    else
+      EmptySlot = iTemp;
+
+    // load items
+    Items_Init();
+
+    // see which item we're referring to
+    for (iTemp = 0; iTemp < MAX_ITEMS; iTemp++)
+      if (stricmp(Items.Data[iTemp]->szName, szItemName) == 0)
+        break;
+
+    if (iTemp == MAX_ITEMS)
+    {
+      rputs("Item not found in file!\n");
+      Items_Close();
+      return;
+    }
+
+    PClan->Items[EmptySlot] = *Items.Data[iTemp];
+    PClan->Items[EmptySlot].UsedBy = 0;
+    PClan->Items[EmptySlot].Available = TRUE;
+
+    Items_Close();
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+
+  void Items_Init ( void )
+    /*
+     * Loads item data into memory.
+     */
+  {
+    // items already loaded
+    if (Items.Initialized) return;
+
+    Items.Initialized = TRUE;
+
+    Items_Read();
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Items_Close ( void )
+    /*
+     * Unloads items.
+     */
+  {
+    if (!Items.Initialized) return;
+
+    Items_Destroy();
+    Items.Initialized = FALSE;
+  }
+
+
+  /* read scroll */
+  void Items_ReadScroll (struct pc *PC, struct clan *TargetClan, _INT16 Target, _INT16 ScrollNum)
+  {
+    char szString[128];
+
+    // use up scroll
+    sprintf(szString, "� |14%s |07reads |12%s\n",
+      PC->szName, PC->MyClan->Items[ ScrollNum ].szName);
+    rputs(szString);
+
+    // reduce energy
+    PC->MyClan->Items[ ScrollNum ].Energy--;
+
+    // if depleted
+    if (PC->MyClan->Items[ ScrollNum ].Energy == 0)
+    {
+      sprintf(szString, "� |07%s vanishes\n", PC->MyClan->Items[ ScrollNum ].szName);
+      rputs(szString);
+      PC->MyClan->Items[ ScrollNum ].Available = FALSE;
+    }
+
+    Spells_CastSpell(PC, TargetClan, Target, PC->MyClan->Items[ScrollNum].SpellNum);
+  }
+
+  void Item_BuyItem( _INT16 ItemType )
+  {
+    _INT16 ItemIndex[MAX_ITEMS];
+    _INT16 iTemp, TotalItems;
+    char szString[255];
+    char szKeys[MAX_ITEMS + 5], Choice;
+    long ItemCosts[MAX_ITEMS], /*NewCost,*/ ItemGst[MAX_ITEMS];
+    char MaterialChoice = 0;
+    _INT16 EmptySlot;
+    struct item_data Item;
+
+    Items_Init();
+
+    /* so we have szKeys[] = "?Q\r ABCDEFGHI..." */
+    szKeys[0] = '?';
+    szKeys[1] = 'Q';
+    szKeys[2] = '\r';
+    szKeys[3] = '\n';
+    szKeys[4] = ' ';
+    for (iTemp = 0; iTemp < MAX_ITEMS; iTemp++)
+      szKeys[iTemp + 5] = 'A' + iTemp;
+    szKeys[iTemp+5] = 0;
+
+    /* generate index of items which are the item type */
+    for (iTemp = 0, TotalItems = 0; iTemp < MAX_ITEMS; iTemp++)
+    {
+      // make sure item is even allowed to be bought from here
+      // FIXME: use WizardLevel for books+scrolls?
+      if (Items.Data[iTemp] &&
+        Items.Data[iTemp]->cType == ItemType && Items.Data[iTemp]->Special == FALSE
+        &&
+        ((Items.Data[iTemp]->MarketLevel <= Village.Data->MarketLevel &&
+         (ItemType == I_WEAPON || ItemType == I_ARMOR || ItemType == I_SHIELD))
+         ||
+         (Items.Data[iTemp]->MarketLevel <= Village.Data->WizardLevel &&
+         (ItemType == I_SCROLL || ItemType == I_BOOK))  )
+
+        && (Items.Data[iTemp]->VillageType == Village.Data->VillageType ||
+          Items.Data[iTemp]->VillageType == V_ALL)  )
+      {
+        /* found item type */
+        ItemIndex[TotalItems] = iTemp;
+
+        // cost fluctuation... FIXME: in future, have different ones for
+        // spells+books??
+        ItemCosts[TotalItems] = Items.Data[  ItemIndex[TotalItems] ]->lCost
+          + ((long)Village.Data->CostFluctuation*Items.Data[ItemIndex[TotalItems] ]->lCost)/100L;
+
+        ItemGst[TotalItems] = ((ItemCosts[TotalItems] * Village.Data->GST)/100L);
+
+        /* add gst */
+        ItemCosts[TotalItems] += ItemGst[TotalItems];
+        TotalItems++;
+      }
+    }
+    szKeys[TotalItems+5] = 0;
+
+
+    /* get input */
+
+    for (;;)
+    {
+      /* header stuff */
+      if (ItemType == I_WEAPON)
+        rputs(ST_WEAPONSAVAILABLE);
+      else if (ItemType == I_ARMOR)
+        rputs(ST_ARMORAVAILABLE);
+      else if (ItemType == I_SHIELD)
+        rputs(ST_SHIELDSAVAILABLE);
+
+      rputs(ST_LONGLINE);
+      rputs(ST_ITEMHEADER);
+      /* list which ones to buy */
+      for (iTemp = 0; iTemp < TotalItems; iTemp++)
+      {
+        sprintf(szString, ST_ITEMLINE, 'A' + iTemp,
+          PClan->Empire.VaultGold >= Items.Data[ ItemIndex[iTemp] ]->lCost ? "|0C" : "|08",
+          Items.Data[ ItemIndex[iTemp] ]->szName, ItemCosts[iTemp]);
+        rputs(szString);
+      }
+      sprintf(szString, ST_ITEMOPTIONS, PClan->Empire.VaultGold);
+      rputs(szString);
+      rputs(ST_LONGLINE);
+      rputs(ST_ITEMPROMPT);
+
+      Choice = od_get_answer(szKeys);
+
+      rputs("\b\b\b\b\b     \b\b\b\b\b|15");
+
+      if (Choice == '?')
+      {
+        rputs(ST_ITEMHELPTITLE);
+        if (ItemType == I_SCROLL || ItemType == I_BOOK)
+          rputs("|07 The old wizard keeps to himself and tells you nothing about the items.\n%P\n\n");
+        else
+          GeneralHelp(ST_ITEMHLP);
+      }
+      else if (Choice == 'Q' || Choice == '\r' || Choice == ' ' || Choice == '\n')
+      {
+        rputs(ST_ITEMABORTED);
+        Items_Close();
+        return;
+      }
+      else
+      {
+        rputs(Items.Data[ ItemIndex[Choice - 'A'] ]->szName);
+        rputs("\n\n");
+
+        /* give info on item */
+        if (Items.Data[ ItemIndex[Choice - 'A'] ]->cType != I_BOOK &&
+          Items.Data[ ItemIndex[Choice - 'A'] ]->cType != I_SCROLL &&
+          Items.Data[ ItemIndex[Choice - 'A'] ]->cType != I_OTHER)
+          Help(Items.Data[ ItemIndex[Choice - 'A'] ]->szName, ST_ITEMHLP);
+
+        sprintf(szString, ST_ITEMCOSTIS, ItemCosts[ Choice - 'A'], PClan->Empire.VaultGold);
+        rputs(szString);
+
+        /* ask if he still wants to buy it */
+        if (YesNo(ST_ITEMBUYTHIS) == YES)
+        {
+          rputs("\n");
+
+          /* bought.  see if user has room for item and can afford */
+          /* if can't, kick him out */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available == FALSE)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            /* no more room in inventory */
+            rputs(ST_ITEMNOMOREROOM);
+            Items_Close();
+            return;
+          }
+          else
+            EmptySlot = iTemp;
+
+          /* see if can afford it */
+          if (PClan->Empire.VaultGold < ItemCosts[Choice - 'A'])
+          {
+            rputs(ST_ITEMNOAFFORD);
+            continue;
+          }
+
+          /* choose type of material */
+          if (Items.Data[ ItemIndex[Choice - 'A'] ]->DiffMaterials)
+          {
+            for (;;)
+            {
+              /* show two types */
+              rputs(ST_ITEMMATERIALS);
+              /* prompt for one */
+              rputs(ST_ITEMCHOOSEONE);
+
+              /* if chooses more expensive type, tell him that it costs x% more */
+              MaterialChoice = od_get_answer("AB\r ");
+
+              if (MaterialChoice == 'A' || MaterialChoice == '\r' || MaterialChoice == ' ')
+              {
+                rputs("\b\b\b\b\b\b\b\b\b\b|15Polymetral\n");
+                Help("Polymetral", ST_ITEMHLP);
+
+                /* ask if he wants to use this */
+                if (YesNo("\n|0SUse this material?") == YES)
+                {
+                  /* see if he can afford it */
+                  //NewCost = (ItemCosts[Choice - 'A'] * (RANDOM(Village.Data->MarketLevel*10) + 90 + RANDOM(10)))/100L;
+
+                  if (PClan->Empire.VaultGold < ItemCosts[Choice - 'A'])
+                  {
+                    rputs("|12You cannot afford this!\n");
+                    if (NoYes("|0SUse Laconia instead?") == NO)
+                    {
+                      Items_Close();
+                      return;
+                    }
+
+                    /* so use other material */
+                    MaterialChoice = MT_LACONIA;
+                    break;
+                  }
+                  else
+                  {
+                    /* can afford it, use it! */
+                    MaterialChoice = MT_POLYMETRAL;
+                    break;
+                  }
+                }
+              }
+              else
+              {
+                rputs("\b\b\b\b\b\b\b\b\b\b|15Laconia   \n");
+                Help("Laconia", ST_ITEMHLP);
+
+                /* ask if he wants to use this */
+                if (YesNo("\n|0SUse this material?") == YES)
+                {
+                  /* see if he can afford it under this type of */
+                  //NewCost = ItemCosts[Choice - 'A'];
+
+                  if (PClan->Empire.VaultGold < ItemCosts[Choice - 'A'])
+                  {
+                    rputs("|12You cannot afford this!\n");
+                    if (NoYes("|0SUse PolyMetral instead?") == NO)
+                    {
+                      Items_Close();
+                      return;
+                    }
+
+                    /* so use other material */
+                    MaterialChoice = MT_POLYMETRAL;
+                    break;
+                  }
+                  else
+                  {
+                    /* can afford it, use it! */
+                    MaterialChoice = MT_LACONIA;
+                    break;
+                  }
+                }
+              }
+            }
+          }
+
+          /* take user's money */
+          PClan->Empire.VaultGold -= ItemCosts[Choice - 'A'];
+
+          /* give GST to vault */
+          Village.Data->Empire.VaultGold += ItemGst[Choice - 'A'];
+
+          /* make stats here -------- */
+          strcpy(Item.szName, Items.Data[ ItemIndex[Choice - 'A'] ]->szName);
+          Item = *Items.Data[ ItemIndex[Choice - 'A'] ];
+
+          Item.UsedBy = 0;
+          Item.Available = TRUE;
+          Item.cType = ItemType;
+
+          /* set stats */
+          for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+          {
+            if (ItemType == I_WEAPON || ItemType == I_ARMOR || ItemType == I_SHIELD)
+            {
+              if (Item.Attributes[iTemp])
+                Item.Attributes[iTemp] =
+                Items.Data[ ItemIndex[Choice - 'A'] ]->Attributes[iTemp] + RANDOM(Village.Data->MarketLevel/3 + 1) + Village.Data->MarketLevel/2;
+            }
+            else // scroll or book
+            {
+              if (Item.Attributes[iTemp])
+                Item.Attributes[iTemp] =
+                  Items.Data[ ItemIndex[Choice - 'A'] ]->Attributes[iTemp] + RANDOM(Village.Data->WizardLevel/3 + 1) + Village.Data->WizardLevel/2;
+            }
+
+            Item.ReqAttributes[iTemp] =
+              Items.Data[ ItemIndex[Choice - 'A'] ]->ReqAttributes[iTemp];
+          }
+
+          /* if using a material, change stats accordingly */
+          if (MaterialChoice == MT_POLYMETRAL)
+          {
+            /* make it lighter by decreasing req attributes */
+            if (Item.ReqAttributes[ATTR_STRENGTH])
+              Item.ReqAttributes[ATTR_STRENGTH] -= (RANDOM(3) + 1);
+            if (Item.Attributes[ATTR_STRENGTH])
+              Item.Attributes[ATTR_AGILITY] += RANDOM(2);
+            if (Item.Attributes[ATTR_DEXTERITY])
+              Item.Attributes[ATTR_DEXTERITY] += RANDOM(2);
+
+            /* make it have less energy -- it'll have between 0 and 20% less energy */
+            Item.Energy = (Item.Energy*(RANDOM(20)+80))/100;
+          }
+          else if (MaterialChoice == MT_LACONIA)
+          {
+            /* make it stronger by giving higher strength */
+            if (Item.ReqAttributes[ATTR_STRENGTH])
+              Item.ReqAttributes[ATTR_STRENGTH] += (RANDOM(3) + 1);
+
+            /* and increase strength attribute */
+            if (Item.Attributes[ATTR_STRENGTH])
+              Item.Attributes[ATTR_STRENGTH] += (RANDOM(2) + 1);
+
+            /* make it have longer lifespan but higher strength reqattrib */
+            Item.Energy = (Item.Energy*(RANDOM(40)+90))/100;
+          }
+
+          // make it super item (+)
+          if (RANDOM(50) == 0 && ItemType != I_SCROLL && ItemType != I_BOOK)
+          {
+            // all stats go up by 25%
+            for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+            {
+              Item.Attributes[iTemp] += (Item.Attributes[iTemp]/4);
+            }
+
+            // cost doubles
+            Item.lCost = 2*ItemCosts[Choice - 'A'];
+
+            rputs("Blacksmith creates a super item!!\n");
+            strcat(Item.szName, "+");
+          }
+          else    // regular cost
+            Item.lCost = ItemCosts[Choice - 'A'];
+
+
+          // add onto it due to Quality Level
+          if (Village.Data->MarketQuality)
+            for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+            {
+              Item.Attributes[iTemp] += ((Item.Attributes[iTemp]*(RANDOM(20) + (Village.Data->MarketQuality*50)/4))/100);
+
+              if (Item.ReqAttributes[iTemp])
+                Item.ReqAttributes[iTemp] -= ((Item.ReqAttributes[iTemp]*(RANDOM(10) + (Village.Data->MarketQuality*30)/4))/100);
+            }
+
+          /* ------------------------ */
+
+          /* show stats */
+          ShowItemStats(&Item, NULL);
+
+          /* ask if user wants to buy still.  if so, give it to user, take rest of money */
+          if (YesNo("|0SBuy it?") == YES)
+          {
+            /* add to items list */
+            rputs("\n|0BYou take the item.\n");
+
+            PClan->Items[EmptySlot] = Item;
+          }
+          else
+          {
+            // rputs("\n|0BYou are refunded half the cost.\n");
+            PClan->Empire.VaultGold += ((Item.lCost*75)/100);
+
+            /* get GST back from gov't */
+            Village.Data->Empire.VaultGold -= (ItemGst[Choice - 'A']/2);
+          }
+          continue;
+        }
+        rputs("\n");
+      }
+    }
+  }
diff --git a/src/doors/clans-src/items.h b/src/doors/clans-src/items.h
new file mode 100644
index 0000000000000000000000000000000000000000..c719e5f303c2c25956cab586c25d70d931390e27
--- /dev/null
+++ b/src/doors/clans-src/items.h
@@ -0,0 +1,33 @@
+
+  void Items_Init ( void );
+    /*
+     * Loads item data into memory.
+     */
+
+  void Items_Close ( void );
+    /*
+     * Unloads items.
+     */
+
+
+  __BOOL ItemPenalty ( struct pc *PC, struct item_data *Item );
+    /*
+     * This function will check to see if PC has the required attributes to
+     * use the item.  If he does, FALSE is returned, otherwise, TRUE.
+     */
+
+  void Items_GiveItem ( char *szItemName );
+    /*
+     * This function will give the item with the name specified to
+     * PClan.
+     */
+
+  void Items_ReadScroll (struct pc *PC, struct clan *TargetClan, _INT16 Target, _INT16 ScrollNum);
+
+  void Item_BuyItem( _INT16 ItemType );
+
+  void ShowItemStats ( struct item_data *Item, struct clan *Clan );
+
+  void Items_FindTreasureChest ( void );
+
+  void ReadBook ( void );
diff --git a/src/doors/clans-src/k_clansi.h b/src/doors/clans-src/k_clansi.h
new file mode 100644
index 0000000000000000000000000000000000000000..c76f42ed569c7bbe1df3b0a1214d43d5af9014e0
--- /dev/null
+++ b/src/doors/clans-src/k_clansi.h
@@ -0,0 +1,11 @@
+#define MAX_INI_WORDS       6
+
+char *papszIniKeyWords[MAX_INI_WORDS] =
+{
+    "NpcFile",
+    "Language",
+    "Items",
+    "Races",
+    "Classes",
+    "Spells"
+};
diff --git a/src/doors/clans-src/k_comman.h b/src/doors/clans-src/k_comman.h
new file mode 100644
index 0000000000000000000000000000000000000000..d6e4cb3f065227abe2559de5121f5f20eac4d46e
--- /dev/null
+++ b/src/doors/clans-src/k_comman.h
@@ -0,0 +1,21 @@
+#define MAX_COMLINE_WORDS    16
+
+char *papszComLineKeyWords[MAX_COMLINE_WORDS] =
+{
+    "L",
+    "Local",
+    "M",
+    "?",
+    "Help",
+    "T",
+    "N",
+    "LIBBS",
+    "Users",
+    "NewNDX",
+    "I",
+    "Recon",
+    "SendReset",
+    "Reset",
+    "Verbose",
+	"D"
+};
diff --git a/src/doors/clans-src/k_config.h b/src/doors/clans-src/k_config.h
new file mode 100644
index 0000000000000000000000000000000000000000..634ed9802339b0352707628b45d373867ca702b7
--- /dev/null
+++ b/src/doors/clans-src/k_config.h
@@ -0,0 +1,21 @@
+#define MAX_CONFIG_WORDS          16
+
+char *papszConfigKeyWords[MAX_CONFIG_WORDS] =
+{
+    "SysopName",
+    "BBSName",
+    "UseLog",
+    "ScoreANSI",
+    "ScoreASCII",
+    "Node",
+    "DropDirectory",
+    "UseFOSSIL",
+    "SerialPortAddr",
+    "SerialPortIRQ",
+    "BBSId",
+    "NetmailDir",
+    "InboundDir",
+    "MailerType",
+    "InterBBS",
+    "bangshangalang��"
+};
diff --git a/src/doors/clans-src/k_ibbs.h b/src/doors/clans-src/k_ibbs.h
new file mode 100644
index 0000000000000000000000000000000000000000..270af2529954712d2e0cd1461005cfd528498857
--- /dev/null
+++ b/src/doors/clans-src/k_ibbs.h
@@ -0,0 +1,27 @@
+#define MAX_NDX_WORDS   11
+
+char *papszNdxKeyWords[MAX_NDX_WORDS] =
+{
+    "BBSName",
+    "VillageName",
+    "Address",
+    "ConnectType",
+    "MailType",
+    "BBSId",
+    "Status",
+    "WorldName",
+    "LeagueId",
+    "Host",
+    "NoMSG"
+};
+
+#define MAX_RT_WORDS    4
+
+char *papszRouteKeyWords[MAX_RT_WORDS] =
+{
+    "ROUTE",
+    "CRASH",
+    "HOLD",
+    "NORMAL"
+};
+
diff --git a/src/doors/clans-src/k_quests.h b/src/doors/clans-src/k_quests.h
new file mode 100644
index 0000000000000000000000000000000000000000..c8e3effbd300ae040e83b9c321be409dc1628195
--- /dev/null
+++ b/src/doors/clans-src/k_quests.h
@@ -0,0 +1,9 @@
+#define MAX_QUEST_WORDS     4
+
+char *papszQuestKeyWords[MAX_QUEST_WORDS] =
+{
+    "Name",
+    "Index",
+    "File",
+    "Known"
+};
diff --git a/src/doors/clans-src/langcomp.c b/src/doors/clans-src/langcomp.c
new file mode 100644
index 0000000000000000000000000000000000000000..c6288203d18e03655f9fe55aae38512b5d6f695c
--- /dev/null
+++ b/src/doors/clans-src/langcomp.c
@@ -0,0 +1,256 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+// Compiles the language file
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "defines.h"
+#include <string.h>
+
+void Convert ( char *Dest, char *From );
+
+struct PACKED LanguageHeader
+{
+    char Signature[30];         // "The Clans Language File v1.0"
+
+    unsigned _INT16 StrOffsets[2000];  // offsets for up to 500 strings
+    unsigned _INT16 NumBytes;          // how big is the bigstring!?
+
+    char *BigString;        // All 500 strings jumbled together into
+                                // one
+} PACKED Language;
+
+int main ( int argc, char *argv[])
+{
+    FILE *fFrom, *fTo;
+    _INT16 iTemp, CurString;
+    char TempString[800], String[800], FromFile[30], ToFile[30];
+
+    printf("The Clans Language File Compiler v.1.0 (c) copyright 1997 Allen Ussher\n\n");
+
+    if (argc != 2)
+    {
+        printf("Format:  Langcomp <Language>\n");
+        exit(0);
+    }
+
+    strcpy(FromFile, argv[1]);
+
+    for (iTemp = strlen(FromFile); iTemp>0; iTemp--)
+        if (FromFile[iTemp] == '.')
+            break;
+
+    if (iTemp == 0)
+    {
+        strcpy(ToFile, FromFile);
+        strcat(ToFile, ".xl");
+        strcat(FromFile, ".txt");
+    }
+    else
+    {
+        FromFile[iTemp] = 0;
+        strcpy(ToFile, FromFile);
+        strcat(ToFile, ".xl");
+        FromFile[iTemp] = '.';
+    }
+
+    fFrom = fopen(FromFile, "r");
+    if (!fFrom)
+    {
+        printf("Error opening %s\n", FromFile);
+        exit(0);
+    }
+
+    // initialize the big string
+    strcpy(Language.Signature, "The Clans Language File v1.0\x1A");
+    for (iTemp = 0;  iTemp < 2000; iTemp++)
+        Language.StrOffsets[iTemp] = 0;
+    Language.NumBytes = 0;
+
+    Language.BigString = malloc(64000);
+    if (!Language.BigString)
+    {
+        printf("Couldn't allocate enough memory to run!");
+        fclose(fFrom);
+        exit(0);
+    }
+
+    // just to ensure it works out, make the first string in BigString = ""
+    Language.BigString[0] = 0;
+    Language.NumBytes = 1;
+
+    // read through line by line
+    for (;;)
+    {
+        if (!fgets(TempString, 800, fFrom)) break;
+
+        if (TempString[0] == '#')   continue;       // skip if comment line
+        if (TempString[0] == ' ')   continue;       // skip if comment line
+
+        // break down string
+        // get rid of \n and \r
+		while (TempString[ strlen(TempString) - 1] == '\n' || TempString[ strlen(TempString) - 1] == '\r')
+			TempString[ strlen(TempString) - 1] = 0;
+
+        // convert @@ at end to \n
+        if (TempString[ strlen(TempString) - 2] == '@' &&
+            TempString[ strlen(TempString) - 1] == '@')
+        {
+            TempString[ strlen(TempString) - 2] = 0;
+            strcat(TempString, "\n");
+        }
+
+        CurString = atoi(TempString);
+        if (CurString == 0) continue;
+
+        // convert string's special language codes
+        Convert(String, &TempString[5]);
+        // strcpy(String, &TempString[5]);
+
+        Language.StrOffsets[CurString] = Language.NumBytes;
+        strcpy( &Language.BigString[ Language.NumBytes ], String);
+        Language.NumBytes += (strlen(String)+1); // must also include zero byte
+        //Language.BigString[ Language.NumBytes ] = 0;
+        //Language.NumBytes++;
+
+        //sprintf(String, "%04d %s", CurString, &Language.BigString[ Language.StrOffsets[CurString] ]);
+        //String[50] = 0;
+        //strcat(String, "\r");
+        //puts(String);
+    }
+
+    fclose(fFrom);
+
+    // now write it to the file
+    fTo = fopen(ToFile, "wb");
+    if (!fTo)
+    {
+        printf("Error opening %s\n", ToFile);
+        free(Language.BigString);
+        exit(0);
+    }
+
+    fwrite(&Language, sizeof(Language), 1, fTo);
+    fwrite(Language.BigString, Language.NumBytes, 1, fTo);
+
+    fclose(fTo);
+
+    free(Language.BigString);
+
+    printf("Done!\n\n%u bytes were used.  (max 64000).\n", Language.NumBytes);
+	return(0);
+}
+
+/* IMPORTANT!!!!   Format of the compiled language (*.XL)
+
+
+    struct
+    {
+        char Signature[30];         // "X-Engine Language File v1.0"
+
+        long StrOffsets[2000];       // offsets for up to 500 strings
+
+        char far *BigString;        // All 500 strings jumbled together into
+                                    // one
+    } LanguageHeader;
+*/
+
+void Convert ( char *Dest, char *From )
+{
+    _INT16 dCurChar = 0, fCurChar = 0;
+
+    Dest[dCurChar] = 0;    // make it 0 length
+
+    while (From[fCurChar])
+    {
+        if (From[fCurChar] == '^')
+        {
+            if (From[fCurChar+1] == 'M')
+            {
+                Dest[dCurChar] = '\n';
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == '[')
+            {
+                Dest[dCurChar] = 27;
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == '-')
+            {
+                Dest[dCurChar] = 0;
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == 'H')
+            {
+                Dest[dCurChar] = '\b';
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == 'N')
+            {
+                Dest[dCurChar] = '\r';
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else if (From[fCurChar+1] == 'G')
+            {
+                Dest[dCurChar] = 7;
+                dCurChar++;
+                fCurChar += 2;
+            }
+            else
+            {
+                Dest[dCurChar] = From[fCurChar];
+                dCurChar++;
+                fCurChar++;
+            }
+        }
+        /*
+        else if (From[fCurChar] == '&' && (isalnum(From[fCurChar+1]) || From[fCurChar+1] == '-') )
+        {
+            // &s turns to %s
+            Dest[dCurChar] = '%';
+            dCurChar++;
+            fCurChar++;
+        }
+        else if (From[fCurChar] == '%' && (isalpha(From[fCurChar+1]) || From[fCurChar+1] == '!') )
+        {
+            // % codes turn to &
+            Dest[dCurChar] = '&';
+            dCurChar++;
+            fCurChar++;
+        }
+        */
+        else
+        {
+            Dest[dCurChar] = From[fCurChar];
+
+            fCurChar++;
+            dCurChar++;
+        }
+    }
+
+    Dest[dCurChar] = 0;
+
+}
diff --git a/src/doors/clans-src/langcomp.dsp b/src/doors/clans-src/langcomp.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..c803f0852e5ce8f97f1e7404e1705f1392e17730
--- /dev/null
+++ b/src/doors/clans-src/langcomp.dsp
@@ -0,0 +1,109 @@
+# Microsoft Developer Studio Project File - Name="langcomp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=langcomp - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "langcomp.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "langcomp.mak" CFG="langcomp - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "langcomp - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "langcomp - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "langcomp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "langcomp___Win32_Release"
+# PROP BASE Intermediate_Dir "langcomp___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Win32_Release"
+# PROP Intermediate_Dir "Win32_Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Zp1 /MD /W3 /GX- /Ox /Ot /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /machine:I386
+# SUBTRACT LINK32 /map
+
+!ELSEIF  "$(CFG)" == "langcomp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "langcomp___Win32_Debug"
+# PROP BASE Intermediate_Dir "langcomp___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "win32_debug"
+# PROP Intermediate_Dir "win32_debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c
+# ADD CPP /nologo /Zp1 /MDd /W3 /Gm /GX- /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /debugtype:coff /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "langcomp - Win32 Release"
+# Name "langcomp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\LANGCOMP.C
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\DEFINES.H
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/src/doors/clans-src/language.c b/src/doors/clans-src/language.c
new file mode 100644
index 0000000000000000000000000000000000000000..06b63567257c4bdeaf96c80dc40abd5fb359cb9f
--- /dev/null
+++ b/src/doors/clans-src/language.c
@@ -0,0 +1,147 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Language Initialization and Closure.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "structs.h"
+#include "myopen.h"
+#include "system.h"
+#include "language.h"
+#include "video.h"
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+struct Language *Language;
+extern __BOOL Verbose;
+
+// ------------------------------------------------------------------------- //
+
+  void CheckMem ( void *Test )
+    /*
+     * Gives system error if the pointer is NULL.
+     */
+  {
+    if (Test == NULL)
+    {
+      System_Error("Checkmem Failed.  Please send a copy of this screen to\nthe author to help debug the game.\n");
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void LoadStrings ( _INT16 StartIndex, _INT16 NumStrings, char *szStrings[] )
+    /*
+     * This function loads NumStrings of strings from the language file.
+     * starting with string StartIndex.
+     *
+     * PRE: StartIndex is the first string's index.
+     *      NumStrings is the number of strings to load.
+     * 
+     */
+  {
+    _INT16 CurString;
+
+    for (CurString = 0; CurString < NumStrings; CurString++)
+    {
+      szStrings[CurString] = &Language->BigString[Language->StrOffsets[StartIndex + CurString]];
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  char *MakeStr ( _INT16 length )
+    /*
+     * This returns a pointer to a malloc'd string of length length.
+     */
+  {
+    char *pc;
+
+    pc = malloc(sizeof(char)*length);
+    CheckMem(pc);
+
+    return pc;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Language_Init( char *szLangFile )
+    /*
+     * The language file is loaded.  If it isn't found, the system is shut
+     * down.
+     */
+  {
+    _INT16 iTemp;
+    char szString[50];
+    struct FileHeader FileHeader;
+
+    if (Verbose)
+    {
+      DisplayStr("> Language_Init()\n");
+      delay(500);
+    }
+
+    /* Read in Language File */
+    Language = malloc(sizeof (struct Language));
+    CheckMem(Language);
+    Language->BigString = NULL;
+
+    for (iTemp = 0; iTemp < 2000; iTemp++)
+      Language->StrOffsets[iTemp] = 0;
+
+    MyOpen(szLangFile, "rb", &FileHeader);
+
+    if (!FileHeader.fp)
+    {
+      sprintf(szString, "File not found: %s\n", szLangFile);
+      zputs(szString);
+      System_Close();
+    }
+    fread(Language, sizeof(struct Language), 1, FileHeader.fp);
+
+    Language->BigString = malloc(Language->NumBytes);
+    if (!Language->BigString)
+    {
+	  DisplayStr ("|12Couldn't allocate enough memory to run!");
+      fclose(FileHeader.fp);
+      System_Close();
+    }
+
+    fread(Language->BigString, Language->NumBytes, 1, FileHeader.fp);
+
+    fclose(FileHeader.fp);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Language_Close( void )
+    /*
+     * The language file is freed from memory.
+     */
+  {
+		free(Language->BigString);
+		free(Language);
+  }
diff --git a/src/doors/clans-src/language.h b/src/doors/clans-src/language.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1d97056f117f12a18bd0a937e2265d507ddd98a
--- /dev/null
+++ b/src/doors/clans-src/language.h
@@ -0,0 +1,32 @@
+
+  void Language_Init( char *szLangFile );
+    /*
+     * The language file is loaded.  If it isn't found, the system is shut
+     * down.
+     */
+
+  void Language_Close( void );
+    /*
+     * The language file is freed from memory.
+     */
+
+  void LoadStrings ( _INT16 StartIndex, _INT16 NumStrings, char *szStrings[] );
+    /*
+     * This function loads NumStrings of strings from the language file.
+     * starting with string StartIndex.
+     *
+     * PRE: StartIndex is the first string's index.
+     *      NumStrings is the number of strings to load.
+     * 
+     */
+
+  char *MakeStr ( _INT16 length );
+    /*
+     * This returns a pointer to a malloc'd string of length length.
+     */
+
+  void CheckMem ( void *Test );
+    /*
+     * Gives system error if the pointer is NULL.
+     */
+
diff --git a/src/doors/clans-src/mail.c b/src/doors/clans-src/mail.c
new file mode 100644
index 0000000000000000000000000000000000000000..fe9f311cbf5591d23c23ba62932e6affe65b86f7
--- /dev/null
+++ b/src/doors/clans-src/mail.c
@@ -0,0 +1,1947 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Mail ADT
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#include <dos.h>
+#endif
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "myopen.h"
+#include "user.h"
+#include "door.h"
+#include "alliance.h"
+#include "fight.h"
+#include "video.h"
+#include "packet.h"
+#include "ibbs.h"
+#include "input.h"
+
+extern struct clan *PClan;
+extern struct Language *Language;
+extern struct config *Config;
+extern struct system System;
+extern struct village Village;
+extern struct ibbs IBBS;
+extern struct game Game;
+
+                                    // Message Types:
+#define MT_PUBLIC       0
+#define MT_PRIVATE      1
+#define MT_ALLIANCE     2
+
+                                    // Message Flags:
+#define MF_DELETED      1           // Message has been deleted
+#define MF_NOFROM       2           // No "from" field, automatic message,
+                                    // don't allow replies to it either
+#define MF_ALLYREQ      4           // Ally request message
+#define MF_GLOBAL       8           // League message
+#define MF_ONEVILLONLY  16          // message sent to only ONE village, not all
+
+#define ALL_VILLAGES    -1
+
+_INT16 InputStr( char *String, char *NextString, char *JustLen, _INT16 CurLine);
+void SendMsj ( struct Message *Message, _INT16 WhichVillage );
+
+// ------------------------------------------------------------------------- //
+
+  void GetUserNames ( char *apszUserNames[50], _INT16 WhichVillage, _INT16 *NumUsers,
+    _INT16 ClanIDs[50][2] )
+  {
+    FILE *fpUList;
+    struct UserInfo User;
+    _INT16 CurUser;
+
+    // set all to NULLs
+    for (CurUser = 0; CurUser < 50; CurUser++)
+      apszUserNames[CurUser] = NULL;
+    *NumUsers = 0;
+
+    // open user file
+    fpUList = _fsopen("userlist.dat", "rb", SH_DENYWR);
+    if (!fpUList)    // no user list at all
+      return;
+
+
+    // go through, pick up those users which hail from this village
+
+    for (CurUser = 0;;)
+    {
+      if (EncryptRead(&User, sizeof(struct UserInfo), fpUList, XOR_ULIST) == 0)
+        break;
+
+      // user from that village?
+      if (User.ClanID[0] == WhichVillage)
+      {
+        // found one from there
+        apszUserNames[CurUser] = malloc(strlen(User.szName) + 1);
+        CheckMem(apszUserNames[CurUser]);
+        strcpy(apszUserNames[CurUser], User.szName);
+        ClanIDs[CurUser][0] = User.ClanID[0];
+        ClanIDs[CurUser][1] = User.ClanID[1];
+        CurUser++;
+      }
+    }
+
+    // close file
+    fclose(fpUList);
+
+    *NumUsers = CurUser;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void GenericReply( struct Message *Reply, char *szReply, BOOL AllowReply )
+  {
+    struct Message Message;
+    FILE *fp;
+    _INT16 player_num, result, i, FirstLine, LastLine;
+    char filename[50], key;
+
+    // malloc msg
+    Message.Data.MsgTxt = malloc(4000);
+    CheckMem(Message.Data.MsgTxt);
+
+    Message.Data.MsgTxt[0] = 0;
+
+    // strcpy(Message.szFromName, GlobalPlayerClan->szName);
+    // fromname not used in generic msgs
+    strcpy(Message.szFromName, Reply->szFromName);
+    strcpy(Message.szFromVillageName, Village.Data->szName);
+    Message.ToClanID[0] = Reply->FromClanID[0];
+    Message.ToClanID[1] = Reply->FromClanID[1];
+
+	if(PClan == NULL)
+	{
+	    Message.FromClanID[0] =  -1;
+    	Message.FromClanID[1] =  -1;
+	}
+	else
+	{
+	    Message.FromClanID[0] =  PClan->ClanID[0];
+    	Message.FromClanID[1] =  PClan->ClanID[1];
+	}
+    strcpy(Message.szDate, System.szTodaysDate);
+
+    if (AllowReply == FALSE)
+      Message.Flags = MF_NOFROM;
+
+    Message.PublicMsgIndex = 0;
+    Message.MessageType = MT_PRIVATE;
+
+    strcpy(Message.Data.MsgTxt, szReply);
+
+    Message.Data.Length = strlen(szReply) + 1;
+    Message.Data.NumLines = 1;
+    Message.Data.Offsets[0] = 0;
+    Message.Data.Offsets[1] = 0;
+
+    // save message
+    fp = _fsopen(ST_MSJFILE, "a+b", SH_DENYRW);
+    if (!fp)
+    {
+      free(Message.Data.MsgTxt);
+      DisplayStr(ST_NOMSJFILE);
+      return;
+    }
+    EncryptWrite(&Message, sizeof(Message), fp, XOR_MSG);
+    EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, fp, XOR_MSG);
+    fclose(fp);
+
+    free(Message.Data.MsgTxt);
+	(void)result;
+	(void)LastLine;
+	(void)filename;
+	(void)key;
+	(void)FirstLine;
+	(void)i;
+	(void)player_num;
+  }
+
+
+// ------------------------------------------------------------------------- //
+  void GenericMessage ( char *szString, _INT16 ToClanID[2], _INT16 FromClanID[2], char *szFrom, BOOL AllowReply )
+  {
+    struct Message Message;
+
+    // if clan doesn't exist, return
+    if (ClanExists(ToClanID) == FALSE)  return;
+
+    /* write generic message -- set it up as a "reply" */
+    Message.ToClanID[0] = FromClanID[0];
+    Message.ToClanID[1] = FromClanID[1];
+
+    Message.FromClanID[0] = ToClanID[0];
+    Message.FromClanID[1] = ToClanID[1];
+
+    strcpy(Message.szFromName, szFrom);
+    strcpy(Message.szDate, System.szTodaysDate);
+    strcpy(Message.szFromVillageName, Village.Data->szName);
+    Message.Flags = 0;
+    Message.MessageType = MT_PRIVATE;
+
+    GenericReply(&Message, szString, AllowReply);
+}
+
+
+// ------------------------------------------------------------------------- //
+  void MyWriteMessage2 ( _INT16 ClanID[2], BOOL ToAll,
+      BOOL AllyReq, _INT16 AllianceID, char *szAllyName,
+      BOOL GlobalPost, _INT16 WhichVillage )
+  {
+    struct Message Message;
+    FILE *fp;
+    _INT16 result, NumLines = 0, CurChar = 0, i;
+    char string[128], JustLen = 78;
+    char Line1[128], Line2[128], OldLine[128];
+
+    if (ToAll == FALSE && ClanID[0] == -1)
+    {
+      if (GetClanID( ClanID, FALSE, FALSE, -1, FALSE) == FALSE)
+      {
+        return;
+      }
+    }
+
+    /* malloc msg */
+    Message.Data.MsgTxt = malloc(4000);
+    CheckMem(Message.Data.MsgTxt);
+
+    Message.Data.MsgTxt[0] = 0;
+
+    Message.ToClanID[0] = ClanID[0];
+    Message.ToClanID[1] = ClanID[1];
+    strcpy(Message.szFromName, PClan->szName);
+    strcpy(Message.szFromVillageName, Village.Data->szName);
+    Message.FromClanID[0] = PClan->ClanID[0];
+    Message.FromClanID[1] = PClan->ClanID[1];
+
+    Message.BBSIDFrom = Config->BBSID;
+
+    strcpy(Message.szDate, System.szTodaysDate);
+    Message.Flags = 0;
+    Message.MessageType = MT_PRIVATE;
+
+    if (AllyReq)
+    {
+      Message.Flags |= MF_ALLYREQ;
+      strcpy(Message.szAllyName, szAllyName);
+      Message.AllianceID = AllianceID;
+    }
+    else if (AllianceID != -1)
+    {
+      // not an alliance, but AllyID exists, so make this an alliance-only MSG
+      Message.AllianceID = AllianceID;
+      strcpy(Message.szAllyName, szAllyName);
+      Message.MessageType = MT_ALLIANCE;
+    }
+
+    if (GlobalPost)
+    {
+      Message.Flags |= MF_GLOBAL;
+
+      if (ToAll)
+        Message.MessageType = MT_PUBLIC;
+    }
+
+    // directed at one BBS only
+    if (WhichVillage != -1 && GlobalPost && ClanID[0] == -1)
+      Message.Flags |= MF_ONEVILLONLY;
+
+    rputs(ST_MAILHEADER);
+    rputs(ST_LONGDIVIDER);
+
+    Line1[0] = 0;
+    Line2[0] = 0;
+    OldLine[0] = 0;
+    for (;;)
+    {
+      rputs(ST_MAILENTERCOLOR);
+      result = InputStr(Line1, Line2, &JustLen, NumLines);
+
+      // if no swearing allowed, convert it :)
+      //if (GameInfo.NoSwearing)
+      //    RemoveSwear(Line1);
+
+      if (result == 1)    // save
+      {
+        if (NumLines == 0)
+        {
+          rputs(ST_MAILNOTEXT);
+          continue;
+        }
+
+        /* ask if public post or not */
+        if (ToAll)
+        {
+          /* public post */
+          if (! (GlobalPost && (Message.Flags & MF_ONEVILLONLY))  )
+          {
+            Message.PublicMsgIndex = Village.Data->PublicMsgIndex;
+            Village.Data->PublicMsgIndex++;
+          }
+        }
+        else
+          Message.PublicMsgIndex = 0;
+
+        rputs(ST_MAILSAVED);
+        break;
+      }
+      else if (result == -1)    // abort
+      {
+        rputs(ST_MAILABORTED);
+
+        free(Message.Data.MsgTxt);
+        return;
+      }
+      else if (result == -2)    // start over
+      {
+        rputs(ST_MAILSTARTOVER);
+        NumLines = 0;
+        CurChar = 0;
+        Line1[0] = 0;
+        Line2[0] = 0;
+
+        continue;
+      }
+      else if (result == 3)   // list
+      {
+        if (NumLines == 0)
+        {
+          rputs(ST_MAILNOTEXTYET);
+          continue;
+        }
+        for (i = 0; i < NumLines; i++)
+        {
+          sprintf(string, ST_MAILLIST, i+1, &Message.Data.MsgTxt[ Message.Data.Offsets[i] ]);
+          string[84] = 0;
+          strcat(string, "\n");
+          strcat(string, ST_MAILENTERCOLOR);
+          rputs(string);
+        }
+        continue;
+      }
+      else if (result == 4)   // backspace
+      {
+        if (NumLines == 0)
+          continue;       // can't go back any more
+
+        // otherwise
+        rputs("\n|03Backing up a line\n");
+
+        // else continue
+        NumLines--;
+        CurChar -= (strlen(OldLine) + 1);
+
+        strcpy(Line1, OldLine);
+
+        if (NumLines == 0)
+          OldLine[0] = 0;
+        else
+          strcpy(OldLine, &Message.Data.MsgTxt[Message.Data.Offsets[NumLines-1]]);
+
+        Line2[0] = 0;
+        continue;
+      }
+
+
+      // else continue
+      Message.Data.Offsets[NumLines] = CurChar;
+      strcpy(&Message.Data.MsgTxt[CurChar], Line1);
+      CurChar += (strlen(Line1) + 1);
+
+      strcpy(OldLine, Line1);
+      strcpy(Line1, Line2);
+      NumLines++;
+
+      if (NumLines == 40)
+      {
+        rputs(ST_MAIL40LINES);
+        break;
+      }
+    }
+    Message.Data.Length = CurChar;
+    Message.Data.NumLines = NumLines;
+
+
+    // save message
+
+    // if local post OR globalpost to ALL villages, do this
+    if (  (GlobalPost && WhichVillage == -1) || GlobalPost == FALSE)
+    {
+      fp = _fsopen(ST_MSJFILE, "ab", SH_DENYRW);
+      if (!fp)
+      {
+        rputs(ST_NOMSJFILE);
+        return;
+      }
+      EncryptWrite(&Message, sizeof(Message), fp, XOR_MSG);
+      EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, fp, XOR_MSG);
+      fclose(fp);
+    }
+
+    if (GlobalPost)
+      SendMsj(&Message, WhichVillage);
+
+    free(Message.Data.MsgTxt);
+  }
+
+
+
+
+// ------------------------------------------------------------------------- //
+  _INT16 QInputStr( char *String, char *NextString, char *JustLen, struct Message *Reply,
+      _INT16 CurLine )
+  {
+    _INT16 cur_char = 0, i, FirstLine, LastLine;
+    unsigned char ch, key, string[128];
+
+    rputs(ST_MAILENTERCOLOR);
+    rputs(String);
+    cur_char = strlen(String);
+
+    for (;;)
+    {
+      if (cur_char == (*JustLen) )
+      {
+        String[cur_char] = 0;
+
+        // break off last String
+        for (i = strlen(String); i>0; i--)
+        {
+          if (String[i] == ' ')
+          {
+            i++;
+            break;
+          }
+        }
+
+        if (i > ((*JustLen)/2) )
+        {
+          strcpy(NextString, &String[i]);
+          String[i] = 0;
+
+          for (;i < cur_char; i++)
+            rputs("\b \b");
+
+          rputs("\n");
+          return 0;
+        }
+        else
+        {
+          rputs("\n");
+          NextString[0] = 0;
+          return 0;
+        }
+      }
+
+      ch = od_get_key(TRUE);
+      if (ch == '\b')
+      {
+        if (cur_char>0)
+        {
+          cur_char--;
+          rputs("\b \b");
+        }
+        else if (cur_char == 0 && CurLine > 0)
+          return 4;
+      }
+      else if ( (isalnum(ch) || ispunct(ch)) && (String[cur_char-1] == '%'  || String[cur_char-1]=='&'))
+        continue;
+      else if ( (isdigit(ch) || toupper(ch) == 'S') && String[cur_char-1] == '@')
+        continue;
+      else if (ch == 25)  // CTRL-Y
+      {
+        rputs("\r                                                                     \r");
+        rputs(ST_MAILENTERCOLOR);
+        cur_char = 0;
+        String[0] = 0;
+        NextString[0] = 0;
+
+        continue;
+      }
+      else if (ch== 13)
+      {
+        rputs("\n");
+        String[cur_char]=0;
+        NextString[0]=0;
+        break;
+      }
+/*
+        else if (ch == '\t')    // tab
+        {
+            rputs("     ");
+            String[cur_char] = '\t';
+            cur_char++;
+        }
+*/
+      else if (iscntrl(ch) && ch != '\r' && ch != '\n')
+        continue;
+      else if (ch == '/' && cur_char == 0)
+      {
+        rputs(ST_INPUTSTRCOMMAND);
+
+        key = toupper(od_get_answer("SACQLR?/\r\n"));
+
+        if (key == '?')
+        {
+          rputs(ST_INPUTSTRHELP2);
+          key = toupper(od_get_answer("SACQLR/\r\n"));
+        }
+
+        if (key == 'C' || key == '\r' || key == '\n')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+          continue;
+        }
+        else if (key == 'R')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_INPUTSTRSTARTOVER);
+          rputs(STR_NOYES);
+          rputs("|15");
+
+          if (od_get_answer("YN\r\n") == 'Y')
+          {
+            rputs(ST_YES);
+            rputs("\n");
+            return -2;
+          }
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+        }
+        else if (key == 'S')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_INPUTSTRSAVE);
+          rputs(STR_YESNO);
+          rputs("|15");
+
+          if (od_get_answer("YN\r\n") == 'N')
+          {
+            rputs(ST_LONGSPACES);
+            rputs(ST_MAILENTERCOLOR);
+            continue;
+          }
+
+          rputs(ST_YES);
+          rputs("\n");
+
+          NextString[0] = 0;
+          return 1;
+        }
+        else if (key == 'A')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_INPUTSTRABORT);
+          rputs(STR_NOYES);
+          rputs("|15");
+
+          if (od_get_answer("YN\r\n") == 'Y')
+          {
+            rputs(ST_YES);
+            rputs("\n");
+            return -1;
+          }
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+        }
+        /*
+        else if (key == 'W')
+        {
+          rputs("\r|05Enter new wrap-around detection width x10 [|1379|05] : |05");
+          i = (od_get_answer("2345678")-'0') * 10  - 1;
+          *JustLen = i;
+          rputs("\r                                                                     \r");
+          rputs(ST_MAILENTERCOLOR);
+        }
+        */
+        else if (key == 'L')
+        {
+          rputs("\n");
+          NextString[0]=0;
+          String[0]=0;
+          return 3;
+        }
+        else if (key == 'Q')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+
+          // show old message
+          for (i = 0; i < Reply->Data.NumLines; i++)
+          {
+            sprintf(string, ST_RMAILQUOTELIST , i+1, &Reply->Data.MsgTxt[  Reply->Data.Offsets[i]  ]);
+            string[84] = 0;
+            rputs(string);
+          }
+          rputs(ST_RMAILQUOTECHOOSE);
+          od_input_str(string, 2, '0', '9');
+          FirstLine = atoi(string);
+          if (FirstLine < 1 || FirstLine > Reply->Data.NumLines)
+          {
+            continue;
+          }
+
+          strcpy(String, &Reply->Data.MsgTxt[ Reply->Data.Offsets[ FirstLine-1 ] ]);
+
+          strcpy(string, ST_RMAILQUOTEBRACKET );
+          strcat(string, &Reply->Data.MsgTxt[ Reply->Data.Offsets[ FirstLine-1 ]] );
+          string[78] = 0;
+          strcpy(String, string);
+
+          rputs(ST_LONGSPACES);
+          rputs("|09");
+          rputs(String);
+          rputs("\n");
+          rputs(ST_MAILENTERCOLOR);
+
+          NextString[0]=0;
+          return 0;
+        }
+        else if (key == '/')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+          rputs("/");
+          String[cur_char]= '/';
+          cur_char++;
+        }
+      }
+      else
+      {
+        String[cur_char]=ch;
+        cur_char++;
+        od_putch(ch);
+      }
+    }
+
+	(void)LastLine;
+    return 0;
+  }
+
+
+  void Reply_Message ( struct Message *Reply )
+  {
+    struct Message Message;
+    FILE *fp;
+
+    _INT16 player_num, result, NumLines = 0, CurChar = 0, i, FirstLine, LastLine;
+    _INT16 Quoted = FALSE;
+    char string[128], JustLen = 78;
+    char Line1[128], Line2[128], key, OldLine[128];
+    BOOL MakePublic, GlobalPost = FALSE;
+    _INT16 WhichVillage = 0;
+
+    // malloc msg
+    Message.Data.MsgTxt = malloc(4000);
+    CheckMem(Message.Data.MsgTxt);
+    Message.Data.MsgTxt[0] = 0;
+
+    // Set up header
+    Message.ToClanID[0] = Reply->FromClanID[0];
+    Message.ToClanID[1] = Reply->FromClanID[1];
+    Message.FromClanID[0] =  PClan->ClanID[0];
+    Message.FromClanID[1] =  PClan->ClanID[1];
+    strcpy(Message.szFromName, PClan->szName);
+    strcpy(Message.szDate, System.szTodaysDate);
+    strcpy(Message.szFromVillageName, Village.Data->szName);
+
+    Message.BBSIDFrom = Config->BBSID;
+
+    Message.Flags = 0;
+
+    Message.MessageType = Reply->MessageType;
+
+    if (Reply->MessageType == MT_ALLIANCE)
+    {
+      Message.AllianceID = Reply->AllianceID;
+      strcpy(Message.szAllyName, Reply->szAllyName);
+    }
+
+    if (Reply->Flags & MF_GLOBAL)
+    {
+      // global message
+      GlobalPost = TRUE;
+      WhichVillage = Reply->BBSIDFrom;
+
+      Message.Flags |= MF_GLOBAL;
+
+      // directed at one BBS only
+      if (Reply->Flags & MF_ONEVILLONLY)
+        Message.Flags |= MF_ONEVILLONLY;
+    }
+
+    // ask to quote
+    if (YesNo(ST_RMAILQUOTE) == YES)
+    {
+      rputs(ST_RMAILQFIRSTLINE);
+      od_input_str(string, 2, '0', '9');
+
+      FirstLine = atoi(string);
+
+      if ( (FirstLine < 1 || FirstLine > Reply->Data.NumLines) == FALSE || FirstLine == 0)
+      {
+        if (FirstLine == 0)
+        {
+          rputs(ST_RMAILQUOTEALL);
+          FirstLine = 1;
+          LastLine = Reply->Data.NumLines;
+        }
+        else
+        {
+          rputs(ST_RMAILLASTLINE);
+          od_input_str(string, 2, '0', '9');
+          LastLine = atoi(string);
+
+          if (LastLine > Reply->Data.NumLines)
+            LastLine = Reply->Data.NumLines;
+        }
+
+        if ( (LastLine < 1 || LastLine > Reply->Data.NumLines || LastLine < FirstLine) == FALSE)
+        {
+          if (FirstLine != LastLine)
+          {
+            for (i = FirstLine;  i <= LastLine; i++)
+            {
+              Message.Data.Offsets[NumLines] = CurChar;
+              strcpy(&Message.Data.MsgTxt[CurChar], ST_RMAILQUOTEBRACKET);
+              strcat(&Message.Data.MsgTxt[CurChar], &Reply->Data.MsgTxt[ Reply->Data.Offsets[i-1]] );
+              Message.Data.MsgTxt[CurChar+78] = 0;
+
+              if (CurChar >= 4000)
+                rputs("Mem error in mail\n%P");
+
+              CurChar += (strlen(&Message.Data.MsgTxt[CurChar]) + 1);
+
+              NumLines++;
+            }
+          }
+          else
+          {
+            Message.Data.Offsets[NumLines] = CurChar;
+            strcpy(&Message.Data.MsgTxt[CurChar], ST_RMAILQUOTEBRACKET);
+            strcat(&Message.Data.MsgTxt[CurChar], &Reply->Data.MsgTxt[ Reply->Data.Offsets[FirstLine-1]] );
+            Message.Data.MsgTxt[CurChar+78] = 0;
+
+            CurChar += (strlen(&Message.Data.MsgTxt[CurChar]) + 1);
+
+            if (CurChar >= 4000)
+              rputs("Mem error in mail\n");
+
+            NumLines++;
+          }
+          Quoted = TRUE;
+        }
+      }
+    }
+
+    Line1[0] = 0;
+    Line2[0] = 0;
+
+    rputs(ST_RMAILHEADER);
+    rputs(ST_LONGDIVIDER);
+
+    strcpy(OldLine, "");
+
+    if (Quoted)
+    {
+      rputs(ST_MAILENTERCOLOR);
+      for (i = 0; i < NumLines; i++)
+      {
+        rputs(&Message.Data.MsgTxt[ Message.Data.Offsets[i] ]);
+        rputs(ST_MAILENTERCOLOR);
+        rputs("\n");
+
+        strcpy(OldLine, &Message.Data.MsgTxt[ Message.Data.Offsets[i] ]);
+      }
+    }
+
+    rputs(ST_MAILENTERCOLOR);
+
+    for (;;)
+    {
+      result = QInputStr(Line1, Line2, &JustLen, Reply, NumLines);
+
+      // if no swearing allowed, convert it :)
+      // if (GameInfo.NoSwearing)
+      //     RemoveSwear(Line1);
+
+      if (result == 1)    // save
+      {
+        if (NumLines == 0)
+        {
+          rputs(ST_MAILNOTEXT);
+          continue;
+        }
+
+        /* ask if public post or not */
+        if (Reply->MessageType != MT_PUBLIC)
+          MakePublic = NoYes(ST_MAILPUBLICQ);
+        else
+          MakePublic = YesNo(ST_MAILPUBLICQ);
+
+        if (MakePublic)
+        {
+          Message.MessageType = MT_PUBLIC;
+
+          if (! (GlobalPost && (Message.Flags & MF_ONEVILLONLY))  )
+          {
+            Message.PublicMsgIndex = Village.Data->PublicMsgIndex;
+            Village.Data->PublicMsgIndex++;
+          }
+
+          // make public but limit it depending on original message
+          if (GlobalPost && (Reply->Flags & MF_ONEVILLONLY) == FALSE)
+            WhichVillage = -1;
+        }
+        else
+        {
+          Message.PublicMsgIndex = 0;
+          Message.MessageType = MT_PRIVATE;
+        }
+
+        rputs(ST_MAILSAVED);
+        break;
+      }
+      else if (result == -1)    // abort
+      {
+        rputs(ST_MAILABORTED);
+
+        free(Message.Data.MsgTxt);
+        return;
+      }
+      else if (result == -2)    // start over
+      {
+        rputs(ST_MAILSTARTOVER);
+        NumLines = 0;
+        CurChar = 0;
+        Line1[0] = 0;
+        Line2[0] = 0;
+
+        continue;
+      }
+      else if (result == 3)   // list
+      {
+        if (NumLines == 0)
+        {
+          rputs(ST_MAILNOTEXTYET);
+          continue;
+        }
+        for (i = 0; i < NumLines; i++)
+        {
+          sprintf(string, ST_MAILLIST, i+1, &Message.Data.MsgTxt[ Message.Data.Offsets[i] ]);
+          string[84] = 0;
+          strcat(string, "\n");
+          strcat(string, ST_MAILENTERCOLOR);
+          rputs(string);
+        }
+        continue;
+      }
+      else if (result == 4)   // backspace
+      {
+        if (NumLines == 0)
+          continue;       // can't go back any more
+
+        // otherwise
+        rputs("\n|03Backing up a line\n");
+
+        // else continue
+        NumLines--;
+        CurChar -= (strlen(OldLine) + 1);
+
+        strcpy(Line1, OldLine);
+
+        if (NumLines == 0)
+          OldLine[0] = 0;
+        else
+          strcpy(OldLine, &Message.Data.MsgTxt[Message.Data.Offsets[NumLines-1]]);
+
+        Line2[0] = 0;
+        continue;
+      }
+
+      // else continue
+      Message.Data.Offsets[NumLines] = CurChar;
+      strcpy(&Message.Data.MsgTxt[CurChar], Line1);
+      CurChar += (strlen(Line1) + 1);
+
+      strcpy(OldLine, Line1);
+      strcpy(Line1, Line2);
+      NumLines++;
+
+      if (NumLines == 40)
+      {
+        rputs(ST_MAIL40LINES);
+        break;
+      }
+    }
+    Message.Data.Length = CurChar;
+    Message.Data.NumLines = NumLines;
+
+    // save message
+    if (  (GlobalPost && WhichVillage == -1) || GlobalPost == FALSE)
+    {
+      fp = _fsopen(ST_MSJFILE, "a+b", SH_DENYRW);
+      if (!fp)
+      {
+        rputs(ST_NOMSJFILE);
+        free(Message.Data.MsgTxt);
+        return;
+      }
+      EncryptWrite(&Message, sizeof(struct Message), fp, XOR_MSG);
+      EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, fp, XOR_MSG);
+      fclose(fp);
+    }
+
+    if (GlobalPost)
+      SendMsj(&Message, WhichVillage);
+
+    free(Message.Data.MsgTxt);
+	(void)key;
+	(void)player_num;
+  }
+
+
+// ------------------------------------------------------------------------- //
+  BOOL Mail_Read ( void )
+  {
+    FILE *fp;
+    long CurOffset, CurMsgOffset;
+    _INT16 iTemp, CurLine;
+    struct Message Message;
+    BOOL AllianceFound, NewMail = FALSE, ReplyingToAlly = FALSE, WillAlly;
+    char szString[128], key = 0;
+
+    rputs(ST_RMAILCHECKING);
+
+    CurOffset = 0;
+
+    for (;;)
+    {
+      fp = _fsopen(ST_MSJFILE, "r+b", SH_DENYWR);
+      if (!fp) return FALSE;
+
+      fseek(fp, CurOffset, SEEK_SET);
+
+      CurMsgOffset = ftell(fp);
+      if (!EncryptRead(&Message, sizeof(Message), fp, XOR_MSG))
+      {
+        fclose(fp);
+        break;
+      }
+
+      CurOffset = ftell(fp);
+
+      // Skip message if not this clan's || it's public and it has been read ||
+      //    it has been deleted
+      if ((Message.MessageType == MT_PRIVATE && ((Message.ToClanID[0] != PClan->ClanID[0]) || (Message.ToClanID[1] != PClan->ClanID[1]))) ||
+          (Message.MessageType == MT_PUBLIC && PClan->PublicMsgIndex >= Message.PublicMsgIndex) ||
+          (Message.Flags & MF_DELETED))
+      {
+        fclose(fp);
+        CurOffset += Message.Data.Length;
+        continue;
+      }
+
+      // if an alliesonly msg, see if user is in that alliance, if not, skip
+      if (Message.MessageType == MT_ALLIANCE)
+      {
+        AllianceFound = FALSE;
+        for (iTemp = 0; !AllianceFound && (iTemp < MAX_ALLIES); iTemp++)
+        {
+          if (PClan->Alliances[iTemp] == Message.AllianceID)
+            AllianceFound = TRUE;
+        }
+
+        // if alliance not found, skip message
+        if (AllianceFound == FALSE)
+        {
+          fclose(fp);
+          CurOffset += Message.Data.Length;
+          continue;
+        }
+      }
+
+
+
+
+      // Message IS readable, continue...
+
+      if (PClan->PublicMsgIndex < Message.PublicMsgIndex)
+          PClan->PublicMsgIndex = Message.PublicMsgIndex;
+
+      NewMail = TRUE;
+
+      // Display Msg header
+      rputs(ST_LONGDIVIDER);
+
+      if (Message.Flags & MF_NOFROM)
+        sprintf(szString, ST_RMAILHEADER2,  Message.szDate);
+      else
+        sprintf(szString, ST_RMAILHEADER1,  Message.szFromName,  Message.szDate);
+      rputs(szString);
+
+      if (Message.MessageType == MT_PUBLIC)
+      {
+        sprintf(szString, ST_RMAILPUBLICPOST, Message.PublicMsgIndex);
+        rputs(szString);
+      }
+      rputs("\n");
+
+      if (Message.Flags == MF_ALLYREQ)
+      {
+        sprintf(szString, ST_RMAILSUBJALLY,  Message.szFromName, Message.szAllyName);
+        rputs(szString);
+      }
+      if (Message.MessageType == MT_ALLIANCE)
+      {
+        sprintf(szString, "|0L Alliance: |0M%s.\n" , Message.szAllyName);
+        rputs(szString);
+      }
+
+      if (Message.BBSIDFrom != Config->BBSID)
+      {
+        sprintf(szString, "|0L Origin  : |0M%s\n\r", Message.szFromVillageName);
+        rputs(szString);
+      }
+
+
+      rputs(ST_LONGDIVIDER);
+
+
+      // display message body
+      Message.Data.MsgTxt = malloc(Message.Data.Length);
+      CheckMem(Message.Data.MsgTxt);
+      EncryptRead(Message.Data.MsgTxt, Message.Data.Length, fp, XOR_MSG);
+      CurOffset = ftell(fp);
+      fclose(fp);
+
+      // display message entered
+      for (CurLine = 0; CurLine < Message.Data.NumLines; CurLine++)
+      {
+        if (CurLine == 17)
+        {
+          rputs(ST_MORE);
+          od_sleep(0);
+          if (toupper(od_get_key(TRUE)) == 'N')
+          {
+            rputs(ST_RETURNSPACES);
+            break;
+          }
+          rputs(ST_RETURNSPACES);
+        }
+
+        rputs(ST_RMAILCOLOR);
+        rputs(&Message.Data.MsgTxt[ Message.Data.Offsets[CurLine] ]);
+        rputs("\n|16");
+      }
+
+      // Get input from user
+      if (Message.MessageType == MT_PUBLIC)
+      {
+        /* can't delete message */
+        rputs(ST_RMAILFOOTER1);
+        
+        key = od_get_answer("QRS\r\n");
+        if (key == '\r' || key == '\n')
+          key = 'S';
+      }
+      else if (Message.Flags & MF_NOFROM)
+      {
+        // Can't reply
+        key = 0;
+        door_pause();
+      }
+      else if (Message.Flags & MF_ALLYREQ)
+      {
+        /* ally message, ask if he wants to ally */
+        WillAlly = NoYes(ST_RMAILALLYQ);
+        if (WillAlly == YES)
+        {
+          /* ally here */
+          FormAlliance(Message.AllianceID);
+        }
+
+        ReplyingToAlly = YesNo(ST_RMAILREPLYQ);
+
+        /* make generic message saying he said no */
+        if (WillAlly == FALSE)
+          sprintf(szString, ST_RMAILREJECTALLY, PClan->szName);
+        else
+          sprintf(szString, ST_RMAILAGREEALLY, PClan->szName);
+        GenericReply(&Message, szString, FALSE);
+      }
+      else
+      {
+        /* regular message */
+        rputs(ST_RMAILFOOTER2);
+        
+        key = od_get_answer("QRDS\r\n");
+      }
+
+
+      // Act on user input
+      if ((!(Message.Flags & MF_ALLYREQ) && key == 'R' ) ||
+        ((Message.Flags & MF_ALLYREQ) && ReplyingToAlly == YES) )
+      {
+        if ( (Message.Flags & MF_ALLYREQ) == FALSE)
+          rputs(ST_RMAILREPLY);
+
+        // reply to message here
+        Reply_Message(&Message);
+
+        // can't delete if public post
+        if (Message.MessageType == MT_PUBLIC)
+        {
+          free(Message.Data.MsgTxt);
+          continue;
+        }
+
+        // ask if you want to delete it
+        if ((Message.Flags & MF_ALLYREQ) == FALSE && YesNo(ST_RMAILDELETEQ) == NO)
+        {
+          // doesn't want to
+          free(Message.Data.MsgTxt);
+          continue;
+        }
+
+        // delete message
+        Message.Flags |= MF_DELETED;
+
+        fp = _fsopen(ST_MSJFILE, "r+b", SH_DENYWR);
+        if (!fp)
+        {
+          rputs(ST_NOMSJFILE);
+          free(Message.Data.MsgTxt);
+          return NewMail;
+        }
+        fseek(fp, CurMsgOffset, SEEK_SET);
+
+        EncryptWrite(&Message, sizeof(Message), fp, XOR_MSG);
+        fclose(fp);
+      }
+      if (key == 'D' || key == '\r' || key == '\n' || (Message.Flags & MF_ALLYREQ) || (Message.Flags & MF_NOFROM))
+      {
+        if ((Message.Flags & MF_ALLYREQ) == FALSE && (Message.Flags & MF_NOFROM) == FALSE)
+          rputs(ST_RMAILDELETE);
+        else
+          rputs(ST_RMAILDELETING);
+
+        // delete message
+        Message.Flags |= MF_DELETED;
+
+        fp = _fsopen(ST_MSJFILE, "r+b", SH_DENYWR);
+        if (!fp)
+        {
+          rputs(ST_NOMSJFILE);
+          free(Message.Data.MsgTxt);
+          return NewMail;
+        }
+        fseek(fp, CurMsgOffset, SEEK_SET);
+
+        EncryptWrite(&Message, sizeof(Message), fp, XOR_MSG);
+        fclose(fp);
+      }
+      if (key == 'S')
+        rputs(ST_RMAILSKIP);
+
+      if (key == 'Q')
+      {
+        rputs(ST_RMAILQUIT);
+        free(Message.Data.MsgTxt);
+        return NewMail;
+      }
+
+      free(Message.Data.MsgTxt);
+
+
+    } /* for (;;) */
+
+    return NewMail;
+
+  }
+  _INT16 InputStr( char *String, char *NextString, char *JustLen, _INT16 CurLine)
+  {
+    _INT16 cur_char = 0, i;
+    unsigned char ch, key;
+
+    rputs(ST_MAILENTERCOLOR);
+    rputs(String);
+    cur_char = strlen(String);
+
+    for (;;)
+    {
+      if (cur_char == (*JustLen) )
+      {
+        String[cur_char] = 0;
+
+        // break off last String
+        for (i = strlen(String); i>0; i--)
+        {
+          if (String[i] == ' ')
+          {
+            i++;
+            break;
+          }
+        }
+
+        if (i > ((*JustLen)/2) )
+        {
+          strcpy(NextString, &String[i]);
+          String[i] = 0;
+
+          for (;i < cur_char; i++)
+            rputs("\b \b");
+
+          rputs("\n");
+          return 0;
+        }
+        else
+        {
+          rputs("\n");
+          NextString[0] = 0;
+          return 0;
+        }
+      }
+
+      ch = od_get_key(FALSE);
+      if (ch=='\b')
+      {
+        if (cur_char>0)
+        {
+          cur_char--;
+          rputs("\b \b");
+        }
+        else if (cur_char == 0 && CurLine > 0)
+          return 4;
+      }
+      else if ( (isalnum(ch) || ispunct(ch)) && (String[cur_char-1] == '%'  || String[cur_char-1]=='&') && cur_char > 0)
+        continue;
+      else if ( (isdigit(ch) || toupper(ch) == 'S') && String[cur_char-1] == '@' && cur_char > 0)
+        continue;
+      else if (ch== 13)
+      {
+        rputs("\n");
+        String[cur_char]=0;
+        NextString[0]=0;
+        break;
+      }
+      else if (ch == '\t' && cur_char < 73)
+      {
+        rputs("     ");
+        strcat(&String[cur_char], "     ");
+        cur_char += 5;
+        continue;
+      }
+      else if (ch == 25)  // CTRL-Y
+      {
+        rputs("\r                                                                     \r");
+        rputs(ST_MAILENTERCOLOR);
+        cur_char = 0;
+        String[0] = 0;
+        NextString[0] = 0;
+
+        continue;
+      }
+      else if (iscntrl(ch))
+        continue;
+      else if (ch == '/' && cur_char == 0)
+      {
+        rputs(ST_INPUTSTRCOMMAND);
+
+        key = toupper(od_get_answer("SACLR?/\r\n"));
+
+        if (key == '?')
+        {
+          rputs(ST_INPUTSTRHELP);
+          key = toupper(od_get_answer("SACLR/\r\n"));
+        }
+
+        if (key == 'C' || key == '\r' || key == '\n')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+          continue;
+        }
+        else if (key == 'R')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_INPUTSTRSTARTOVER);
+          rputs(STR_NOYES);
+          rputs("|15");
+
+          if (od_get_answer("YN\r\n") == 'Y')
+          {
+            rputs(ST_YES);
+            rputs("\n");
+            return -2;
+          }
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+        }
+        else if (key == 'S')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_INPUTSTRSAVE);
+          rputs(STR_YESNO);
+          rputs("|15");
+
+          if (od_get_answer("YN\r\n") == 'N')
+          {
+            rputs(ST_LONGSPACES);
+            rputs(ST_MAILENTERCOLOR);
+            continue;
+          }
+
+          rputs(ST_YES);
+          rputs("\n");
+
+          NextString[0] = 0;
+          return 1;
+        }
+        else if (key == 'A')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_INPUTSTRABORT);
+          rputs(STR_NOYES);
+          rputs("|15");
+
+          if (od_get_answer("YN\r\n") == 'Y')
+          {
+            rputs(ST_YES);
+            rputs("\n");
+            return -1;
+          }
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+        }
+        else if (key == 'L')
+        {
+          rputs("\n");
+          NextString[0]=0;
+          String[0]=0;
+          return 3;
+        }
+        else if (key == '/')
+        {
+          rputs(ST_LONGSPACES);
+          rputs(ST_MAILENTERCOLOR);
+          rputs("/");
+          String[cur_char]= '/';
+          cur_char++;
+        }
+      }
+      else
+      {
+        String[cur_char]=ch;
+        cur_char++;
+        od_putch(ch);
+      }
+    }
+
+    return 0;
+  }
+
+
+  void Msg_Create ( _INT16 ToClanID[2], BOOL MessageType, BOOL AllyReq, _INT16 AllianceID,
+      char *szAllyName, BOOL GlobalPost, _INT16 WhichVillage )
+      /*
+       * Allows user to enter a message.
+       *
+       * PRE: ToClanID is the ClanID who will receive the message if it is
+       *        a private message.  Otherwise it is ignored
+       *      MessageType determines what type of message this is.
+       *      AllyReq is TRUE if this is an alliance request.
+       *      AllianceID is the alliance which is sending this message if it
+       *        is an MT_ALLIANCE type of message OR it is an AllyReq
+       *      szAllyName is the name of the alliance sending the message if it
+       *        is an AllyReq or MT_ALLIANCE type.
+       *      GlobalPost is TRUE if it is an IBBS message.
+       *      WhichVillage is the village to receive the message if it is a
+       *        GlobalPost.  Set to ALL_VILLAGES if none specific.
+       */
+  {
+    struct Message Message;
+    FILE *fp;
+    _INT16 result, NumLines = 0, CurChar = 0, i;
+    char string[128], JustLen = 78;
+    char Line1[128], Line2[128], OldLine[128];
+
+    if (MessageType == MT_PRIVATE)
+    {
+      if (GetClanID( ToClanID, FALSE, FALSE, -1, FALSE) == FALSE)
+      {
+        return;
+      }
+    }
+
+    /* malloc msg */
+    Message.Data.MsgTxt = malloc(4000);
+    CheckMem(Message.Data.MsgTxt);
+    Message.Data.MsgTxt[0] = 0;
+
+    // Set up header
+    Message.ToClanID[0] = ToClanID[0];
+    Message.ToClanID[1] = ToClanID[1];
+    Message.FromClanID[0] = PClan->ClanID[0];
+    Message.FromClanID[1] = PClan->ClanID[1];
+    strcpy(Message.szFromName, PClan->szName);
+    strcpy(Message.szDate, System.szTodaysDate);
+    strcpy(Message.szFromVillageName, Village.Data->szName);
+
+    Message.BBSIDFrom = Config->BBSID;
+
+    Message.Flags = 0;
+
+    Message.MessageType = MessageType;
+
+    if (MessageType == MT_ALLIANCE)
+    {
+      Message.AllianceID = AllianceID;
+      strcpy(Message.szAllyName, szAllyName);
+    }
+
+    if (AllyReq)
+    {
+      Message.Flags |= MF_ALLYREQ;
+      strcpy(Message.szAllyName, szAllyName);
+      Message.AllianceID = AllianceID;
+    }
+
+    if (GlobalPost)
+      Message.Flags |= MF_GLOBAL;
+
+    // directed at one BBS only
+    if (WhichVillage != ALL_VILLAGES && GlobalPost && MessageType == MT_PUBLIC)
+      Message.Flags |= MF_ONEVILLONLY;
+
+    rputs(ST_MAILHEADER);
+    rputs(ST_LONGDIVIDER);
+
+    Line1[0] = 0;
+    Line2[0] = 0;
+    OldLine[0] = 0;
+    for (;;)
+    {
+      rputs(ST_MAILENTERCOLOR);
+      result = InputStr(Line1, Line2, &JustLen, NumLines);
+
+      // if no swearing allowed, convert it :)
+      //if (GameInfo.NoSwearing)
+      //    RemoveSwear(Line1);
+
+      if (result == 1)    // save
+      {
+        if (NumLines == 0)
+        {
+          rputs(ST_MAILNOTEXT);
+          continue;
+        }
+
+        /* ask if public post or not */
+        if (Message.MessageType == MT_PUBLIC)
+        {
+          /* public post */
+          if (! (GlobalPost && (Message.Flags & MF_ONEVILLONLY))  )
+          {
+            Message.PublicMsgIndex = Village.Data->PublicMsgIndex;
+            Village.Data->PublicMsgIndex++;
+          }
+        }
+        else
+          Message.PublicMsgIndex = 0;
+
+        rputs(ST_MAILSAVED);
+        break;
+      }
+      else if (result == -1)    // abort
+      {
+        rputs(ST_MAILABORTED);
+
+        free(Message.Data.MsgTxt);
+        return;
+      }
+      else if (result == -2)    // start over
+      {
+        rputs(ST_MAILSTARTOVER);
+        NumLines = 0;
+        CurChar = 0;
+        Line1[0] = 0;
+        Line2[0] = 0;
+
+        continue;
+      }
+      else if (result == 3)   // list
+      {
+        if (NumLines == 0)
+        {
+          rputs(ST_MAILNOTEXTYET);
+          continue;
+        }
+        for (i = 0; i < NumLines; i++)
+        {
+          sprintf(string, ST_MAILLIST, i+1, &Message.Data.MsgTxt[ Message.Data.Offsets[i] ]);
+          string[84] = 0;
+          strcat(string, "\n");
+          strcat(string, ST_MAILENTERCOLOR);
+          rputs(string);
+        }
+        continue;
+      }
+      else if (result == 4)   // backspace
+      {
+        if (NumLines == 0)
+          continue;       // can't go back any more
+
+        // otherwise
+        rputs("\n|03Backing up a line\n");
+
+        // else continue
+        NumLines--;
+        CurChar -= (strlen(OldLine) + 1);
+
+        strcpy(Line1, OldLine);
+
+        if (NumLines == 0)
+          OldLine[0] = 0;
+        else
+          strcpy(OldLine, &Message.Data.MsgTxt[Message.Data.Offsets[NumLines-1]]);
+
+        Line2[0] = 0;
+        continue;
+      }
+
+
+      // else continue
+      Message.Data.Offsets[NumLines] = CurChar;
+      strcpy(&Message.Data.MsgTxt[CurChar], Line1);
+      CurChar += (strlen(Line1) + 1);
+
+      strcpy(OldLine, Line1);
+      strcpy(Line1, Line2);
+      NumLines++;
+
+      if (NumLines == 40)
+      {
+        rputs(ST_MAIL40LINES);
+        break;
+      }
+    }
+    Message.Data.Length = CurChar;
+    Message.Data.NumLines = NumLines;
+
+
+    // if local post OR globalpost to ALL villages, do this
+    if (  (GlobalPost && WhichVillage == ALL_VILLAGES) || GlobalPost == FALSE)
+    {
+      fp = _fsopen(ST_MSJFILE, "ab", SH_DENYRW);
+      if (!fp)
+      {
+        rputs(ST_NOMSJFILE);
+        return;
+      }
+      EncryptWrite(&Message, sizeof(struct Message), fp, XOR_MSG);
+      EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, fp, XOR_MSG);
+      fclose(fp);
+    }
+
+    if (GlobalPost)
+      SendMsj(&Message, WhichVillage);
+
+    free(Message.Data.MsgTxt);
+  }
+
+
+  void Mail_Write ( _INT16 MessageType )
+  {
+    _INT16 DummyID[2];
+
+    DummyID[0] = -1;
+    DummyID[1] = -1;
+
+    Msg_Create ( DummyID, MessageType, FALSE, -1, NULL, FALSE, -1);
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void Mail_Maint ( void )
+  {
+    FILE *OldMessage, *NewMessage;
+    struct Message Message;
+
+    DisplayStr("* Mail_Maint()\n");
+
+    OldMessage = _fsopen("clans.msj", "rb", SH_DENYRW);
+    if (OldMessage)     // MSJ file exists, so go on
+    {
+      NewMessage = _fsopen("tmp.$$$", "wb", SH_DENYRW);
+      if (!NewMessage)
+      {
+        DisplayStr("Error opening temp file\n");
+        sleep(3);
+        return;
+      }
+
+      for (;;)
+      {
+        if (!EncryptRead(&Message, sizeof(struct Message), OldMessage, XOR_MSG))
+          break;
+
+        if (Message.Flags & MF_DELETED)
+  //FIXME:      DaysBetween(Message.Date, GameInfo.TheDate) > 7)
+        {
+          // deleted or else a week old, so skip it
+          fseek(OldMessage, Message.Data.Length, SEEK_CUR);
+        }
+        else
+        {
+          /* write it, not read yet */
+          Message.Data.MsgTxt = malloc(Message.Data.Length);
+          CheckMem(Message.Data.MsgTxt);
+
+          // write it to new file
+          EncryptRead(Message.Data.MsgTxt, Message.Data.Length, OldMessage, XOR_MSG);
+
+          EncryptWrite(&Message, sizeof(struct Message), NewMessage, XOR_MSG);
+          EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, NewMessage, XOR_MSG);
+
+          free(Message.Data.MsgTxt);
+        }
+      }
+
+      fclose(NewMessage);
+      fclose(OldMessage);
+
+      // delete old, and rename new
+      unlink("clans.msj");
+      rename("tmp.$$$", "clans.msj");
+    }
+  }
+
+  void Mail_RequestAlliance (struct Alliance *Alliance)
+  {
+    _INT16 iTemp, NumAlliances = 0;
+    _INT16 ClanId[2], CurClan;
+    char szToName[25], szFileName[40];
+    FILE *fpPlayerFile;
+    struct clan *TmpClan;
+
+    // see if this alliance has too many members
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (Alliance->Member[iTemp][0] != -1)
+        NumAlliances++;
+
+    if (NumAlliances == MAX_ALLIANCEMEMBERS)
+    {
+      rputs(ST_ALLIANCEATMAX);
+      return;
+    }
+
+    /* find player as you would if writing mail. */
+    if (GetClanID( ClanId, FALSE, FALSE, Alliance->ID, FALSE ) == FALSE)
+    {
+      rputs("\n\n");
+      return;
+    }
+
+    /* ask if he wants to invite this guy for sure */
+    if (NoYes(ST_ALLIANCESURE) == NO)
+    {
+      rputs(ST_ABORTED);
+      return;
+    }
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    GetClan(ClanId, TmpClan);
+
+    // see if in this alliance already
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (TmpClan->Alliances[iTemp] == Alliance->ID)
+        break;
+
+    if (iTemp != MAX_ALLIES)
+    {
+      rputs(ST_ALLIANCEALREADY);
+      FreeClan(TmpClan);
+      return;
+    }
+
+    /* see if he has too many allies */
+    NumAlliances = 0;
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (TmpClan->Alliances[iTemp] != -1)
+        NumAlliances++;
+
+    if (NumAlliances == MAX_ALLIES)
+    {
+      rputs(ST_ALLIANCEOTHERMAX);
+      FreeClan(TmpClan);
+      return;
+    }
+
+    /* if so, set up message but with ALLY flag */
+    rputs(ST_ALLIANCELETTER);
+    MyWriteMessage2(ClanId, FALSE, TRUE, Alliance->ID, Alliance->szName, FALSE, -1);
+
+    FreeClan(TmpClan);
+	(void)szFileName;
+	(void)fpPlayerFile;
+	(void)CurClan;
+	(void)szToName;
+  }
+
+  void Mail_WriteToAllies( struct Alliance *Alliance )
+  {
+    _INT16 ClanId[2];
+
+    ClanId[0] = -1;
+    ClanId[1] = -1;
+    MyWriteMessage2(ClanId, TRUE, FALSE, Alliance->ID, Alliance->szName, FALSE, -1);
+  }
+
+
+
+
+
+  void SendMsj ( struct Message *Message, _INT16 WhichVillage )
+  {
+    // if WhichVillage == -1, do a for loop and send packet to all BBSes
+
+    struct Packet Packet;
+    _INT16 ClanID[2], CurBBS;
+    FILE *fp;
+
+
+    Packet.Active = TRUE;
+    Packet.BBSIDFrom = IBBS.Data->BBSID;
+    Packet.PacketType = PT_MSJ;
+    strcpy(Packet.szDate, System.szTodaysDate);
+    Packet.PacketLength = sizeof(struct Message) + Message->Data.Length;
+    strcpy(Packet.GameID, Game.Data->GameID);
+
+    if (WhichVillage != -1)
+    {
+      Packet.BBSIDTo = WhichVillage;
+
+      fp = fopen("tmp.$$$", "wb");
+      if (!fp)    return;
+
+      /* write packet */
+      EncryptWrite(&Packet, sizeof(struct Packet), fp, XOR_PACKET);
+
+      EncryptWrite(Message, sizeof(struct Message), fp, XOR_PACKET);
+      EncryptWrite(Message->Data.MsgTxt, Message->Data.Length, fp, XOR_PACKET);
+
+      fclose(fp);
+
+      // send packet to BBS
+      IBBS_SendPacketFile(Packet.BBSIDTo, "tmp.$$$");
+      unlink("tmp.$$$");
+    }
+    else
+    {
+      // go through ALL BBSes and send this to them all
+
+      for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+      {
+        if (IBBS.Data->Nodes[CurBBS].Active == FALSE ||
+          CurBBS+1 == IBBS.Data->BBSID)
+          continue;
+
+        Packet.BBSIDTo = CurBBS+1;
+
+        fp = fopen("tmp.$$$", "wb");
+        if (!fp)    return;
+
+        /* write packet */
+        EncryptWrite(&Packet, sizeof(struct Packet), fp, XOR_PACKET);
+
+        EncryptWrite(Message, sizeof(struct Message), fp, XOR_PACKET);
+        EncryptWrite(Message->Data.MsgTxt, Message->Data.Length, fp, XOR_PACKET);
+
+        fclose(fp);
+
+        // send packet to BBS
+        IBBS_SendPacketFile(Packet.BBSIDTo, "tmp.$$$");
+        unlink("tmp.$$$");
+      }
+    }
+	(void)ClanID;
+  }
+
+  void PostMsj ( struct Message *Message )
+  {
+    // open our .msj file, append this and update MsgPublicIndex if this
+    // is a public post (i.e. MsgPublicIndex != 0)
+
+    // if MsgPublicIndex == 0, leave the msj alone since it is a private post
+
+    FILE *fp;
+
+    fp = fopen(ST_MSJFILE, "ab");
+
+    if (fp)
+    {
+      // if public post (MsgPublicIndex != 0), update msgPublicIndex
+      if (Message->MessageType == MT_PUBLIC )
+        Message->PublicMsgIndex = Village.Data->PublicMsgIndex++;
+
+      EncryptWrite(Message, sizeof(struct Message), fp, XOR_MSG);
+      EncryptWrite(Message->Data.MsgTxt, Message->Data.Length, fp, XOR_MSG);
+      fclose(fp);
+    }
+  }
+
+  void GlobalMsgPost ( void )
+  {
+    // choose what type of post:
+    //
+    //  public (everyone sees)
+    //  private (direct)
+
+    char cKey, *apszVillageNames[MAX_IBBSNODES], *apszUserNames[50],
+        *pszChoices[2] = { "1. Public", "2. Private" };
+    _INT16 iTemp, NumVillages, WhichVillage, NumClans;
+    _INT16 ClanIDs[50][2], WhichClan, ClanID[2], PostType;
+    unsigned char VillageIndex[MAX_IBBSNODES];
+
+    GetStringChoice (pszChoices, 2, "|0SWhat type of post?\n|0E> |0F",
+        &PostType, TRUE, DT_LONG, TRUE);
+
+    if (PostType == -1)
+      return;
+
+    // load up village names
+    NumVillages = 0;
+    for (iTemp = 0; iTemp < MAX_IBBSNODES; iTemp++)
+    {
+      apszVillageNames[iTemp] = NULL;
+
+      // skip if our village
+      if (iTemp+1 == IBBS.Data->BBSID)
+        continue;
+
+      if (IBBS.Data->Nodes[iTemp].Active)
+      {
+        apszVillageNames[NumVillages] = IBBS.Data->Nodes[iTemp].Info.pszVillageName;
+        VillageIndex[NumVillages] = iTemp+1;
+        NumVillages++;
+      }
+    }
+
+    if (PostType == 0)
+    {
+      // public
+      if (YesNo("|0SWrite to a specific village?  (No=All villages)") == YES)
+      {
+        // specific village, choose one
+        GetStringChoice(apszVillageNames, NumVillages,
+          "|0SEnter the name of the village\n|0G> |0F",
+          &WhichVillage, TRUE, DT_LONG, TRUE);
+
+        if (WhichVillage == -1)
+        {
+          rputs(ST_ABORTED);
+          return;
+        }
+        WhichVillage = VillageIndex[ WhichVillage ];
+      }
+      else
+      {
+        // write to all villages
+        WhichVillage = -1;
+      }
+
+      ClanID[0] = -1;
+      ClanID[1] = -1;
+
+      MyWriteMessage2 ( ClanID, TRUE, FALSE, -1, "", TRUE, WhichVillage);
+    }
+    else
+    {
+      // private
+
+      // specific village, choose one
+      GetStringChoice(apszVillageNames, NumVillages,
+        "|0SEnter the name of the village\n|0G> |0F",
+        &WhichVillage, TRUE, DT_LONG, TRUE);
+
+      if (WhichVillage == -1)
+      {
+        rputs(ST_ABORTED);
+        return;
+      }
+      WhichVillage = VillageIndex[ WhichVillage ];
+
+      // load up names of characters from that village
+      GetUserNames(apszUserNames, WhichVillage, &NumClans, ClanIDs);
+
+      // choose one
+      GetStringChoice(apszUserNames, NumClans,
+        "|0SEnter the name of the clan to write to\n|0G> |0F",
+        &WhichClan, TRUE, DT_WIDE, TRUE);
+
+      if (WhichClan == -1)
+      {
+        rputs(ST_ABORTED);
+        for (iTemp = 0; iTemp < 50; iTemp++)
+        {
+          if (apszUserNames[iTemp])
+            free(apszUserNames[iTemp]);
+        }
+        return;
+      }
+
+      ClanID[0] = ClanIDs[ WhichClan ][0];
+      ClanID[1] = ClanIDs[ WhichClan ][1];
+
+      for (iTemp = 0; iTemp < 50; iTemp++)
+      {
+        if (apszUserNames[iTemp])
+          free(apszUserNames[iTemp]);
+      }
+
+      MyWriteMessage2 ( ClanID, FALSE, FALSE, -1, "", TRUE, WhichVillage );
+    }
+	(void)cKey;
+}
diff --git a/src/doors/clans-src/mail.h b/src/doors/clans-src/mail.h
new file mode 100644
index 0000000000000000000000000000000000000000..909e5dcdeca8f3867ebdc750bb4d67603f8fb6a7
--- /dev/null
+++ b/src/doors/clans-src/mail.h
@@ -0,0 +1,28 @@
+/*
+ * Mail ADT
+ *
+ *
+ */
+
+
+  _INT16 Mail_Read ( void );
+
+  void Mail_Write ( _INT16 MessageType );
+
+  void Mail_RequestAlliance (struct Alliance *Alliance);
+
+  void Mail_WriteToAllies( struct Alliance *Alliance );
+
+  void GenericReply( struct Message *Reply, char *szReply, BOOL AllowReply );
+
+  void GenericMessage ( char *szString, _INT16 ToClanID[2], _INT16 FromClanID[2], char *szFrom, BOOL AllowReply );
+
+  void MyWriteMessage2 ( _INT16 ClanID[2], BOOL ToAll,
+      BOOL AllyReq, _INT16 AllianceID, char *szAllyName,
+      BOOL GlobalPost, _INT16 WhichVillage );
+
+  void PostMsj ( struct Message *Message );
+
+  void Mail_Maint ( void );
+
+  void GlobalMsgPost ( void );
diff --git a/src/doors/clans-src/maint.c b/src/doors/clans-src/maint.c
new file mode 100644
index 0000000000000000000000000000000000000000..867ec185b87843f4546805dcad4336df46fee549
--- /dev/null
+++ b/src/doors/clans-src/maint.c
@@ -0,0 +1,112 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Maintenance ADT -- all maintenance functions should go here.
+ *
+ */
+#ifdef __unix__
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "structs.h"
+#include "misc.h"
+#include "maint.h"
+#include "video.h"
+#include "system.h"
+#include "user.h"
+#include "ibbs.h"
+#include "alliance.h"
+#include "trades.h"
+#include "village.h"
+#include "pawn.h"
+#include "npc.h"
+#include "mail.h"
+
+extern struct game Game;
+extern struct system System;
+extern struct ibbs IBBS;
+
+  void Maintenance ( void )
+    /*
+     * Daily maintenance is run.
+     *
+     *  If this is an IBBS game AND maint was already run, it will not run
+     *  again.  Otherwise, Maintenance() will ALWAYS run.
+     *
+     * PreCondition   System is initialized (excluding Door_Init).
+     *
+     */
+  {
+    DisplayStr("|09Maintenance running\n");
+
+    // if IBBS game AND maintenance already run, don't run it again
+    // otherwise, run it again
+    // REP: remove FALSE so cheating not allowed
+    if ((DaysBetween(Game.Data->szTodaysDate, System.szTodaysDate) <= 0) &&
+#ifdef PRELAB
+         Game.Data->InterBBS && FALSE)
+#else
+         Game.Data->InterBBS)
+#endif
+    {
+      System_Error("Maintenance already run today.\n");
+    }
+
+    // update today's date
+    strcpy(Game.Data->szTodaysDate, System.szTodaysDate);
+
+
+    // if the game has not yet begun, skip reset of maintenance
+    if (Game.Data->GameState == 1 || Game.Data->GameState == 2)
+    {
+      DisplayStr("* Game currently not in progress, maintenance skipped.\n");
+      return;
+    }
+
+
+    System_Maint();
+
+    Village_Maint();
+
+    IBBS_Maint();
+
+    User_Maint();
+
+    Mail_Maint();
+
+    NPC_Maint();
+
+    Trades_Maint();
+
+    PS_Maint();
+
+    // remove disbanding user names
+    unlink("disband.dat");
+
+    Alliance_Maint();
+
+    DisplayStr("Done.\n");
+
+  }
diff --git a/src/doors/clans-src/maint.h b/src/doors/clans-src/maint.h
new file mode 100644
index 0000000000000000000000000000000000000000..d62446e2faa3d71bdd5b858a316c504847cb73fc
--- /dev/null
+++ b/src/doors/clans-src/maint.h
@@ -0,0 +1,9 @@
+
+  void Maintenance ( void );
+    /*
+     * Daily maintenance is run.
+     *
+     *  If this is an IBBS game AND maint was already run, it will not run
+     *  again.  Otherwise, Maintenance() will ALWAYS run.
+     */
+
diff --git a/src/doors/clans-src/makefile b/src/doors/clans-src/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..54b72bcbf7474577517d35ccf9836c6308f215db
--- /dev/null
+++ b/src/doors/clans-src/makefile
@@ -0,0 +1,182 @@
+# CC = tcc
+# FLAGS = -ml -wall -C
+# DELETE = del
+# EXEFILE = .exe
+
+OS	:=	$(shell uname | tr "[A-Z]" "[a-z]")
+ifeq ($(OS),netbsd)
+FLAGS	+=	-D__unix__
+endif
+# Somebody make this compile under gcc. :-)  I'll get you started:
+CC = gcc
+FLAGS += -O2 -Wall -I/usr/bbs/sbbs/src/src/odoors -L../libs.${OS}
+ifdef PROFILE
+FLAGS	+=	-pg
+endif
+ifdef DEBUG
+FLAGS	+=	-g
+endif
+# FLAGS = -O -Wall
+DELETE = rm -f
+EXEFILE = .${OS}
+#
+# See convert.txt for more suggestions.
+
+OBJS = clans.o video.o system.o\
+	parsing.o ibbs.o myopen.o language.o\
+	door.o village.o input.o help.o game.o user.o\
+	misc.o maint.o spells.o clansini.o class.o menus.o\
+	crc.o items.o mail.o fight.o scores.o pawn.o reg.o\
+	npc.o quests.o news.o empire.o alliance.o menus2.o\
+	voting.o trades.o myibbs.o wb_fapnd.o
+
+#all: clans.exe reset.exe pcedit.exe langcomp.exe mcomp.exe
+all: clans$(EXEFILE) langcomp$(EXEFILE) mcomp$(EXEFILE) reset$(EXEFILE) pcedit$(EXEFILE)
+
+clean:
+	$(DELETE) *.o
+	$(DELETE) clans$(EXEFILE)
+	$(DELETE) langcomp$(EXEFILE)
+	$(DELETE) mcomp$(EXEFILE)
+	$(DELETE) reset$(EXEFILE)
+	$(DELETE) pcedit$(EXEFILE)
+
+clans$(EXEFILE):      $(OBJS) unix_wrappers.o
+ifdef PROFILE
+	$(CC) $(FLAGS) $(OBJS) -lODoors_p unix_wrappers.o -o clans$(EXEFILE)
+else
+	$(CC) $(FLAGS) $(OBJS) -lODoors unix_wrappers.o -o clans$(EXEFILE)
+endif
+#	$(CC) $(FLAGS) @comp.lst
+
+unix_wrappers.o : unix_wrappers.c unix_wrappers.h
+	$(CC) $(FLAGS) -c unix_wrappers.c
+
+clans.o:      clans.c
+	$(CC) $(FLAGS) -c clans.c
+
+alliance.o: alliance.c alliance.h
+	$(CC) $(FLAGS) -c alliance.c
+
+tasker.o:     tasker.c
+	$(CC) $(FLAGS) -c tasker.c
+
+video.o:      video.c
+	$(CC) $(FLAGS) -c video.c
+
+system.o:     system.c
+	$(CC) $(FLAGS) -c system.c
+
+parsing.o:    parsing.c
+	$(CC) $(FLAGS) -c parsing.c
+
+ibbs.o:       ibbs.c
+	$(CC) $(FLAGS) -c ibbs.c
+
+# 12/23/2001 [au] dropped from use
+#tslicer.o:    tslicer.c
+#	$(CC) $(FLAGS) -c tslicer.c
+
+myopen.o:     myopen.c
+	$(CC) $(FLAGS) -c myopen.c
+
+language.o:   language.c
+	$(CC) $(FLAGS) -c language.c
+
+door.o:       door.c
+	$(CC) $(FLAGS) -c door.c
+
+village.o:    village.c
+	$(CC) $(FLAGS) -c village.c
+
+input.o:      input.c
+	$(CC) $(FLAGS) -c input.c
+
+help.o:       help.c
+	$(CC) $(FLAGS) -c help.c
+
+game.o:       game.c
+	$(CC) $(FLAGS) -c game.c
+
+user.o:       user.c
+	$(CC) $(FLAGS) -c user.c
+
+misc.o:       misc.c
+	$(CC) $(FLAGS) -c misc.c
+
+maint.o:      maint.c
+	$(CC) $(FLAGS) -c maint.c
+
+spells.o:     spells.c
+	$(CC) $(FLAGS) -c spells.c
+
+clansini.o:   clansini.c
+	$(CC) $(FLAGS) -c clansini.c
+
+class.o:      class.c
+	$(CC) $(FLAGS) -c class.c
+
+menus.o:      menus.c
+	$(CC) $(FLAGS) -c menus.c
+
+crc.o:        crc.c
+	$(CC) $(FLAGS) -c crc.c
+
+items.o:      items.c
+	$(CC) $(FLAGS) -c items.c
+
+mail.o:       mail.c
+	$(CC) $(FLAGS) -c mail.c
+
+fight.o:      fight.c
+	$(CC) $(FLAGS) -c fight.c
+
+scores.o:     scores.c
+	$(CC) $(FLAGS) -c scores.c
+
+pawn.o:       pawn.c
+	$(CC) $(FLAGS) -c pawn.c
+
+reg.o:        reg.c
+	$(CC) $(FLAGS) -c reg.c
+
+npc.o:        npc.c
+	$(CC) $(FLAGS) -c npc.c
+
+quests.o:     quests.c
+	$(CC) $(FLAGS) -c quests.c
+
+news.o:       news.c
+	$(CC) $(FLAGS) -c news.c
+
+empire.o:     empire.c
+	$(CC) $(FLAGS) -c empire.c
+
+menus2.o:     menus2.c
+	$(CC) $(FLAGS) -c menus2.c
+
+voting.o:     voting.c
+	$(CC) $(FLAGS) -c voting.c
+
+trades.o:     trades.c
+	$(CC) $(FLAGS) -c trades.c
+
+myibbs.o:     myibbs.c
+	$(CC) $(FLAGS) -c myibbs.c
+
+wb_fapnd.o:     wb_fapnd.c
+	$(CC) $(FLAGS) -c wb_fapnd.c
+
+langcomp$(EXEFILE):      langcomp.c
+	$(CC) $(FLAGS) langcomp.c -o langcomp$(EXEFILE)
+
+reset$(EXEFILE): reset.c myopen.h parsing.h crc.h structs.h k_config.h unix_wrappers.o 
+	$(CC) $(FLAGS) reset.c myopen.o parsing.o crc.o unix_wrappers.o -o reset$(EXEFILE) -lcurses
+
+
+mcomp$(EXEFILE):      mcomp.c
+	$(CC) $(FLAGS) mcomp.c -o mcomp$(EXEFILE)
+
+pcedit$(EXEFILE):      pcedit.c myopen.o unix_wrappers.o myopen.h unix_wrappers.h
+	$(CC) $(FLAGS) pcedit.c myopen.o unix_wrappers.o -o pcedit$(EXEFILE)
+
diff --git a/src/doors/clans-src/mcomp.c b/src/doors/clans-src/mcomp.c
new file mode 100644
index 0000000000000000000000000000000000000000..90cd5de49f502e68aa7c8142e19100cbe8c75101
--- /dev/null
+++ b/src/doors/clans-src/mcomp.c
@@ -0,0 +1,284 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/* Monster Compiler */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+//#include <OpenDoor.h>
+#include "structs.h"
+
+#define TRUE                1
+#define FALSE               0
+#define MAX_SPELLS          40
+#define MAX_MEMBERS         20
+#define MAX_ITEMS_HELD      30
+#define MAX_MONSTERS        255
+#define MAX_MON_WORDS       14
+#define MAX_TOKEN_CHARS     32
+#define NUM_ATTRIBUTES      6
+
+char *papszMonKeyWords[MAX_MON_WORDS] =
+{
+    "Name",
+    "HP",
+    "Agility",
+    "Dexterity",
+    "Strength",
+    "Wisdom",
+    "ArmorStr",
+    "Weapon",
+    "Shield",
+    "Armor",
+    "Difficulty",
+    "SP",
+    "Spell",
+    "Undead"
+};
+
+struct pc TmpMonster;
+
+int main (int argc, char *argv[] )
+{
+    FILE *fpMonIn, *fpMonOut;
+	char szLine[255], *pcCurrentPos;
+//	char szString[255];
+	char szToken[MAX_TOKEN_CHARS + 1];
+//	char *pcAt;
+	unsigned _INT16 uCount;
+	_INT16 iKeyWord;
+    _INT16 iTemp;
+//	_INT16 OrigMonIn;
+    _INT16 MonIndex[MAX_MONSTERS];  /* difficulties of all monsters,
+                                    0 means no monster */
+    _INT16 CurMonster = -1, LastSpellSlot = 0;
+
+    if (argc != 3)
+    {
+        printf("Format:  mcomp <monster.txt> <output.mon>\n\n");
+        exit(0);
+    }
+
+    fpMonIn = fopen(argv[1], "r");
+    if (!fpMonIn)
+	{
+        printf("Error opening %s.\n", argv[1]);
+        exit(0);
+	}
+
+    fpMonOut = fopen(argv[2], "w+b");
+    if (!fpMonOut)
+	{
+        printf("Error opening %s.\n", argv[2]);
+        exit(0);
+	}
+
+    /* generate index while doing list */
+
+    /* for now, write a blank index */
+    for (iTemp = 0; iTemp < MAX_MONSTERS; iTemp++)
+        MonIndex[iTemp] = 0;
+
+    fwrite(MonIndex, sizeof(MonIndex), 1, fpMonOut);
+
+    for (;;)
+	{
+		/* read in a line */
+        if (fgets(szLine, 255, fpMonIn) == NULL) break;
+
+		/* Ignore all of line after comments or CR/LF char */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos)
+		{
+            /* skip all comment lines */
+			if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+			   || *pcCurrentPos == '%' || *pcCurrentPos == '#')
+			{
+				*pcCurrentPos='\0';
+				break;
+			}
+			++pcCurrentPos;
+		 }
+
+		/* Search for beginning of first token on line */
+		pcCurrentPos=(char *)szLine;
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* If no token was found, proceed to process the next line */
+		if(!*pcCurrentPos) continue;
+
+		/* Get first token from line */
+		uCount=0;
+		while(*pcCurrentPos && !isspace(*pcCurrentPos))
+		{
+			if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+			++pcCurrentPos;
+		}
+		if(uCount<=MAX_TOKEN_CHARS)
+			szToken[uCount]='\0';
+		else
+			szToken[MAX_TOKEN_CHARS]='\0';
+
+		/* Find beginning of keyword parameter */
+		while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+		/* Trim trailing spaces from setting string */
+		for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+		{
+			if(isspace(pcCurrentPos[uCount]))
+			{
+				pcCurrentPos[uCount]='\0';
+			}
+		else
+			{
+				break;
+			}
+		}
+
+		if (szToken[0] == '$')
+			break;
+
+		/* Loop through list of keywords */
+        for(iKeyWord = 0; iKeyWord < MAX_MON_WORDS; ++iKeyWord)
+		{
+			/* If keyword matches */
+            if(stricmp(szToken, papszMonKeyWords[iKeyWord]) == 0)
+			{
+				/* Process token */
+				switch (iKeyWord)
+				{
+                    case 0 :    /* NAME of monster */
+                        /* write previous monster to file then */
+                        if (CurMonster != -1)
+                        {
+                            fwrite(&TmpMonster, sizeof(struct pc), 1, fpMonOut);
+                        }
+
+                        /* see if out of items memory yet */
+                        ++CurMonster;
+                        if (CurMonster == MAX_MONSTERS)
+						{
+							break;
+						}
+
+                        /* initialize it */
+                        memset(&TmpMonster, 0, sizeof(struct pc));
+                        strcpy(TmpMonster.szName, pcCurrentPos);
+                        TmpMonster.HP = TmpMonster.MaxHP = 30;
+                        TmpMonster.SP = TmpMonster.MaxSP = 0;
+
+                        for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+                            TmpMonster.Attributes[iTemp] = 10;
+
+                        TmpMonster.Status = Here;
+
+                        TmpMonster.Weapon = 0;
+                        TmpMonster.Shield = 0;
+                        TmpMonster.Armor = 0;
+
+                        TmpMonster.WhichRace = -1;
+                        TmpMonster.WhichClass = -1;
+
+                        TmpMonster.Difficulty = 0;
+                        TmpMonster.Level = 0;
+                        TmpMonster.Undead = FALSE;
+
+                        for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+                            TmpMonster.SpellsKnown[iTemp] = 0;
+                        for (iTemp = 0; iTemp < 10; iTemp++)
+                            TmpMonster.SpellsInEffect[iTemp].SpellNum = -1;
+                        LastSpellSlot = 0;
+
+                        printf("Monster : %s\n", TmpMonster.szName);
+						break;
+                    case 1 :    /* HP */
+                        printf("    - hp  : %d\n", atoi(pcCurrentPos));
+                        TmpMonster.HP = TmpMonster.MaxHP = atoi(pcCurrentPos);
+						break;
+                    case 2 :    /* agility */
+                    case 3 :    /* Dexterity */
+                    case 4 :    /* Strength */
+                    case 5 :    /* Wisdom */
+                    case 6 :    /* ArmorStr */
+                        TmpMonster.Attributes[iKeyWord - 2] = atoi(pcCurrentPos);
+						break;
+                    case 7 :    /* Weapon */
+                        TmpMonster.Weapon = atoi(pcCurrentPos);
+
+                        printf("    - wep: %d\n", TmpMonster.Weapon);
+						break;
+                    case 8 :    /* Shield */
+                        TmpMonster.Shield = atoi(pcCurrentPos);
+
+                        printf("    - shi: %d\n", TmpMonster.Shield);
+						break;
+                    case 9 :    /* Armor */
+                        TmpMonster.Armor = atoi(pcCurrentPos);
+
+                        printf("    - amr: %d\n", TmpMonster.Armor);
+						break;
+                    case 10 :    /* difficulty */
+                        TmpMonster.Difficulty =
+                            MonIndex[CurMonster] = atoi(pcCurrentPos);
+
+                        TmpMonster.Level = TmpMonster.Difficulty;
+
+                        printf("    - dif: %d\n", MonIndex[CurMonster]);
+						break;
+                    case 11 :    /* SP */
+                        printf("    - sp  : %d\n", atoi(pcCurrentPos));
+                        TmpMonster.SP = TmpMonster.MaxSP = atoi(pcCurrentPos);
+						break;
+                    case 12 :   /* spell! */
+                        TmpMonster.SpellsKnown[LastSpellSlot] = atoi(pcCurrentPos);
+                        LastSpellSlot++;
+                        break;
+                    case 13 :   // undead
+                        TmpMonster.Undead = TRUE;
+                        break;
+
+
+				}
+				break;
+			}
+		}
+    }
+
+    /* write last monster */
+    fwrite(&TmpMonster, sizeof(struct pc), 1, fpMonOut);
+
+    /* rewrite index */
+    fseek(fpMonOut, 0L, SEEK_SET);
+    fwrite(MonIndex, sizeof(MonIndex), 1, fpMonOut);
+
+	/* since they started at -1 and not 0 */
+    CurMonster++;
+
+    printf("%d Monster found.\n%ld bytes used", CurMonster, (long) CurMonster*sizeof(struct pc));
+
+    fclose(fpMonIn);
+    fclose(fpMonOut);
+	return(0);
+}
diff --git a/src/doors/clans-src/mcomp.dsp b/src/doors/clans-src/mcomp.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..1cda76fa08c8127d18783edf312a232a1786c260
--- /dev/null
+++ b/src/doors/clans-src/mcomp.dsp
@@ -0,0 +1,105 @@
+# Microsoft Developer Studio Project File - Name="mcomp" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=mcomp - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "mcomp.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "mcomp.mak" CFG="mcomp - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "mcomp - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "mcomp - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "mcomp - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "mcomp___Win32_Release"
+# PROP BASE Intermediate_Dir "mcomp___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Win32_Release"
+# PROP Intermediate_Dir "Win32_Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Zp1 /MD /W3 /GX- /Ox /Ot /Oy /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /profile
+
+!ELSEIF  "$(CFG)" == "mcomp - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "mcomp___Win32_Debug"
+# PROP BASE Intermediate_Dir "mcomp___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Win32_Debug"
+# PROP Intermediate_Dir "Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c
+# ADD CPP /nologo /Zp1 /MDd /W3 /Gm /GX- /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /debugtype:both /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "mcomp - Win32 Release"
+# Name "mcomp - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\MCOMP.C
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/src/doors/clans-src/menus.c b/src/doors/clans-src/menus.c
new file mode 100644
index 0000000000000000000000000000000000000000..b95a5a0cdf226d1f1f79b8576b11edd3aea230fe
--- /dev/null
+++ b/src/doors/clans-src/menus.c
@@ -0,0 +1,1253 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "user.h"
+#include "door.h"
+#include "input.h"
+#include "help.h"
+#include "fight.h"
+#include "mail.h"
+#include "scores.h"
+#include "items.h"
+#include "pawn.h"
+#include "quests.h"
+#include "alliance.h"
+#include "npc.h"
+#include "village.h"
+#include "trades.h"
+#include "menus2.h"
+#include "fight.h"
+#include "village.h"
+#include "empire.h"
+#include "mail.h"
+#include "ibbs.h"
+#include "reg.h"
+#include "system.h"
+#include "user.h"
+
+
+#define MT_PUBLIC       0
+#define MT_PRIVATE      1
+#define MT_ALLIANCE     2
+
+extern struct Language *Language;
+extern struct village Village;
+extern struct clan *PClan;
+extern struct game Game;
+BOOL FirstTimeInMain = FALSE;
+extern struct config *Config;
+
+// ------------------------------------------------------------------------- //
+  _INT16 WorldMenu ( void )
+  {
+    char *szTheOptions[7];
+    _INT16 iTemp;
+
+    LoadStrings(990, 7, szTheOptions);
+
+
+    if (!PClan->TravelHelp)
+    {
+      PClan->TravelHelp = TRUE;
+      Help("World Travel", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      switch(GetChoice("Travel Menu", ST_ENTEROPTION, szTheOptions, "OQ?VTHS", 'Q', TRUE))
+      {
+        case 'O' :    /* other villages */
+          IBBS_SeeVillages(FALSE);
+          break;
+        case 'T' :    /* travel to other town */
+          // FIXME: This may cause problems in the future:  what if a
+          // user calls and plays around 11:50pm and then calls back
+          // at 12:05, he'll be able to travel!?
+          if (Game.Data->ClanTravel == FALSE)
+          {
+            rputs("\n|07Clan travel has been disabled in this league.\n%P");
+            return 0;
+          }
+
+          if (PClan->FirstDay)
+            rputs("|07You may not travel to another BBS until tomorrow\n%P");
+          else
+            IBBS_SeeVillages(TRUE);
+          break;
+        case 'Q' :    /* return to previous menu */
+          return 0;
+        case '?' :    /* redisplay options */
+          break;
+        case 'V' :    /* stats */
+          ClanStats(PClan, TRUE);
+				break;
+        case 'H' :  /* help */
+          GeneralHelp(ST_VILLHLP);
+          break;
+        case 'S' :  /* current trip info */
+          IBBS_CurrentTravelInfo();
+          break;
+      }
+    }
+	(void)iTemp;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void AddChatFile(char *szString, char *pszFileName)
+  {
+    FILE *fpChatFile;
+    _INT16 LinesRead, iTemp;
+    char *szOldLines[42];
+    char *szNewLines[42];
+
+    fpChatFile = fopen(pszFileName, "r");
+
+    if (!fpChatFile)
+    {
+      /* no file, make it */
+      fpChatFile = fopen(pszFileName, "w");
+      /* write string */
+      fputs(szString, fpChatFile);
+      fclose(fpChatFile);
+      return;
+    }
+
+    for (iTemp = 0; iTemp < 42; iTemp++)
+    {
+      szOldLines[iTemp] = malloc(90);
+      CheckMem(szOldLines[iTemp]);
+      szNewLines[iTemp] = malloc(90);
+      CheckMem(szNewLines[iTemp]);
+    }
+
+    /* found file, read in lines */
+
+    /* read 42 lines */
+
+    LinesRead = 0;
+    for (iTemp = 0; iTemp < 42; iTemp++)
+    {
+      if (fgets(szOldLines[LinesRead], 89, fpChatFile) == 0)
+        break;
+
+      ++LinesRead;
+    }
+    fclose(fpChatFile);
+
+    /* if there were 42 lines, delete first line */
+    if (LinesRead == 42)
+    {
+      for (iTemp = 0; iTemp < 42; iTemp++)
+        strcpy(szNewLines[iTemp], szOldLines[iTemp + 1]);
+
+      /* first line deleted, now write them to file */
+      fpChatFile = fopen(pszFileName, "w");
+      if (fpChatFile)
+      {
+        for (iTemp = 0; iTemp < 42; iTemp++)
+        {
+          fputs(szNewLines[iTemp], fpChatFile);
+        }
+
+        /* write OUR new string */
+        fputs(szString, fpChatFile);
+        fclose(fpChatFile);
+      }
+    }
+    else
+    {
+      /* just write them to file and add our own */
+      fpChatFile = fopen(pszFileName, "w");
+      if (fpChatFile)
+      {
+        for (iTemp = 0; iTemp < LinesRead; iTemp++)
+          fputs(szOldLines[iTemp], fpChatFile);
+
+        /* write OUR new string */
+        fputs(szString, fpChatFile);
+        fclose(fpChatFile);
+      }
+    }
+
+    for (iTemp = 0; iTemp < 42; iTemp++)
+    {
+      free(szOldLines[iTemp]);
+      free(szNewLines[iTemp]);
+    }
+  }
+
+  void Menus_ChatRoom ( char *pszFileName )
+  {
+    char szLine[128];
+    char szString[128];
+    _INT16 LinesInput;
+    BOOL FirstTime;
+
+    /* display file */
+    od_clr_scr();
+  //    GameInfo.NoPause = TRUE;
+    Display(pszFileName);
+  //    GameInfo.NoPause = FALSE;
+
+    /* ask if user wants to add some words */
+    if (NoYes(ST_CHATADDQ) == NO)
+    {
+      /* no, leave now! */
+      rputs("\n");
+      return;
+    }
+
+    rputs(ST_CHATENTERCOMMENT);
+    // loop until blank line or 3 lines input
+    FirstTime = TRUE;
+    for (LinesInput = 0; LinesInput < 3; LinesInput++)
+    {
+      // get his input
+      szString[0] = 0;
+      rputs("|0A> |0F");
+      GetStr(szString, 77, TRUE);
+
+      if (strlen(szString) < 2)
+      {
+        // rputs(ST_ABORTED);
+        return;
+      }
+
+      if (FirstTime)
+      {
+        /* first write clan name on one line */
+        strcpy(szLine, "|0B");
+        strcat(szLine, PClan->szName);
+        strcat(szLine, "\n");
+        AddChatFile(szLine, pszFileName);
+
+        FirstTime = FALSE;
+      }
+
+      // write quote to file
+      strcpy(szLine, "|0B> |0C");
+      strcat(szLine, szString);
+      strcat(szLine, "\n");
+
+      /* add it on */
+      AddChatFile(szLine, pszFileName);
+    }
+
+    rputs("\n");
+  }
+
+
+// ------------------------------------------------------------------------- //
+  _INT16 MainMenu ( void )
+  {
+    char *szTheOptions[20], DefaultAction, szMainMenu[20],
+         *szSecret = "/e/Secret";
+    struct UserInfo User;
+    _INT16 iTemp, BannerShown;
+
+    BannerShown = RANDOM(5) + 1;
+
+    LoadStrings(970, 20, szTheOptions);
+    sprintf(szMainMenu, "Main Menu%d", BannerShown);
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      if (!FirstTimeInMain)
+      {
+        Help("Main Title", ST_MENUSHLP);
+        FirstTimeInMain = TRUE;
+      }
+
+      if (PClan->FightsLeft == 0 || NumMembers(PClan, TRUE) == 0)
+        DefaultAction = 'Q';
+      else
+        DefaultAction = 'E';
+
+      switch(GetChoice(szMainMenu, ST_ENTEROPTION, szTheOptions, "EQ?VMWCTPUH/N!1A2345", DefaultAction, TRUE))
+      {
+        case '!' :    /* delete clan */
+          if (NoYes("|0SAre you sure you wish to delete your clan?!") == YES)
+          {
+            DeleteClan(PClan->ClanID, PClan->szName, FALSE);
+
+            // if interbbs, send packet to main BBS saying this guy
+            // was deleted and that he should be removed from the userlist
+            rputs("|14You have been successfully deleted from the game.\n|07Please play again.\n%P");
+
+            if (Game.Data->InterBBS)
+            {
+              // remove user from league
+              User.ClanID[0] = PClan->ClanID[0];
+              User.ClanID[1] = PClan->ClanID[1];
+
+              User.Deleted = FALSE; // don't care
+
+              strcpy(User.szMasterName, PClan->szUserName);
+              strcpy(User.szName, PClan->szName);
+
+              LeagueKillUser (&User);
+            }
+
+            User_Destroy();
+            System_Close();
+          }
+          break;
+        case 'E' :    /* the mines */
+          return 1;
+        case 'Q' :    /* Quit */
+          return -1;
+        case '?' :    /* redisplay options */
+          break;
+        case 'V' :    /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case 'M' :    /* market */
+          return 2;
+        case 'C' :    /* comm. menu */
+          return 3;
+        case 'B' :    /* clan relations menu */
+          return 4;
+        case 'W' :  /* world travel */
+          return 5;
+        case 'T' :  /* town hall */
+          return 6;
+        case 'P' :  /* empire menu */
+          return 7;
+        case 'U' :  /* church menu */
+          return 9;
+        case 'H' :  /* training hall */
+          return 10;
+        case 'A' :  /* alliance menu */
+          return 11;
+        case '/' :  //chat villagers
+          ChatVillagers(WN_STREET);
+          break;
+        case 'N' :  // newbie help
+          GeneralHelp(ST_NEWBIEHLP);
+          break;
+        case '1' :
+          // od_printf("mem = %ld, stack = %u\n\r", farcoreleft(), stackavail());
+          // give gold
+
+#ifdef PRELAB
+
+          Village.Data->MarketQuality = ((Village.Data->MarketQuality+1)%4);
+
+          rputs("Cheat ON!\n");
+          PClan->Empire.VaultGold += 320000;
+          PClan->Empire.Land += 10;
+          PClan->FightsLeft = 20;
+          PClan->QuestToday = FALSE;
+          for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+          {
+            if (PClan->Member[iTemp])
+            {
+              PClan->Member[iTemp]->Status = Here;
+            }
+          }
+          Fight_Heal(PClan);
+#else
+          rputs("Debugging flag is off.\n");
+#endif
+
+          /*
+          PClan->Empire.Land += 10;
+          PClan->Empire.VaultGold += 1000;
+          PClan->Empire.Army.Followers += 200;
+          Village.Empire.Army.Followers += 200;
+          Village.Empire.VaultGold += 2000;
+          Village.Empire.Land += 20;
+          */
+          door_pause();
+          break;
+        case '2' :  // secret #2
+          if (BannerShown != 2)
+            rputs(ST_SECRET2);
+          else
+            RunEvent(FALSE, szSecret, "2", NULL, NULL);
+          break;
+        case '3' :  // secret #3
+          RunEvent(FALSE, szSecret, "3", NULL, NULL);
+          break;
+        case '4' :  // secret #4
+          RunEvent(FALSE, szSecret, "4", NULL, NULL);
+          break;
+        case '5' :  // secret #5
+          if (BannerShown != 5)
+            rputs(ST_SECRET5);
+          else
+            RunEvent(FALSE, szSecret, "5", NULL, NULL);
+          break;
+      }
+    }
+	(void)iTemp;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 MineMenu ( void )
+  {
+    char *szTheOptions[9];
+    _INT16 iTemp;
+    char DefaultAction;
+
+    LoadStrings( 930, 9, szTheOptions);
+
+    if (!PClan->MineHelp)
+    {
+      PClan->MineHelp = TRUE;
+      Help("Mine Help", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    Help("Mines", ST_MENUSHLP);
+
+    /* get a choice */
+    for (;;)
+    {
+      if (PClan->FightsLeft == 0 || NumMembers(PClan, TRUE) == 0)
+        DefaultAction = 'Q';
+      else
+        DefaultAction = 'L';
+
+      switch(GetChoice("Mine Menu", ST_ENTEROPTION, szTheOptions, "LFQ?VCG/W", DefaultAction, TRUE))
+      {
+        case 'W' :  // who's here?
+          DisplayScores(FALSE);
+          break;
+        case 'G' :  /* Quest */
+          /* if all guys dead, tell guy can't fight */
+          if (NumMembers(PClan, TRUE) == 0)
+          {
+            rputs(ST_FIGHT0);
+            break;
+          }
+          // if (PClan->QuestToday && Debug == FALSE)
+          if (PClan->QuestToday)
+          {
+            rputs("\n|15You have already gone on a quest today.  Please try again tomorrow!\n%P");
+            break;
+          }
+
+          Quests_GoQuest();
+          break;
+        case 'L' :    /* the mines */
+          if (PClan->FightsLeft == 0)
+            rputs("|07You have no more fights left for today.\n%P");
+          else
+          {
+            /* if all guys dead, tell guy can't fight */
+            if (NumMembers(PClan, TRUE) == 0)
+            {
+              /* tell him all members are dead, come again tomorrow */
+              rputs(ST_FIGHT0);
+              break;
+            }
+
+            // sometimes find treasure
+            if (RANDOM(15) == 0)
+            {
+              Items_FindTreasureChest();
+            }
+            // sometimes run a random event
+            else if (RANDOM(7) == 0)
+            {
+              // run random event using file corresponding to
+              // level groupings
+              if (PClan->MineLevel == 0)
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              else if (PClan->MineLevel == 1)
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              else if (PClan->MineLevel == 2)
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              else if (PClan->MineLevel == 3)
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              else if (PClan->MineLevel == 4)
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              else if (PClan->MineLevel <= 10)
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              else
+                RunEvent(FALSE, "/e/Eva", "", NULL, NULL);
+              door_pause();
+            }
+            else
+            {
+              Fight_Monster( PClan->MineLevel, "/m/Output");
+            }
+            User_Write();
+          }
+          break;
+        case 'F' :  /* fight another clan */
+          if (PClan->ClanFights == 0)
+            rputs("|07You have no more clan battles.\n%P");
+          else
+          {
+            Fight_Clan();
+            User_Write();
+          }
+          break;
+        case 'C' :    /* change level */
+          if (!PClan->MineLevelHelp)
+          {
+            PClan->MineLevelHelp = TRUE;
+            Help("Mine Level", ST_NEWBIEHLP);
+          }
+
+          iTemp = (_INT16) GetLong("|0SEnter level of mine to change to.", PClan->MineLevel, 20);
+          /* NO MORE REG!
+          if (iTemp >= 5 &&
+            IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE)
+          {
+            rputs("\n|12Sorry, you may only play up to the 4th level of the mines in the unregistered\nversion.  Please encourage your sysop to register.\n%P");
+            break;
+          }
+          */
+          if (iTemp)
+            PClan->MineLevel = iTemp;
+          break;
+        case 'Q' :    /* return to previous menu */
+          return 0;
+        case '?' :    /* redisplay options */
+          break;
+        case 'V' :    /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case '/' :  //chat villagers
+          ChatVillagers(WN_MINE);
+          break;
+      }
+    }
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 CommunicationsMenu ( void )
+  {
+    char *szTheOptions[8];
+    char szString[128];
+    _INT16 iTemp, ClanId[2];
+
+    LoadStrings(205, 8, szTheOptions);
+
+    if (!PClan->CommHelp)
+    {
+      PClan->CommHelp = TRUE;
+      Help("Communications", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    for (;;)
+    {
+      rputs("\n\n");
+
+      switch(GetChoice("Mail Menu", ST_ENTEROPTION, szTheOptions, "CWPUQV?G", 'Q', TRUE))
+      {
+        case 'C' :      /* check mail */
+          if (Mail_Read() == FALSE)
+            rputs("|15Sorry, no mail found.\n%P");
+          break;
+        case 'W' :      /* write mail */
+          Mail_Write(MT_PRIVATE);
+          break;
+        case 'P' :      /* public mail */
+          Mail_Write(MT_PUBLIC);
+          break;
+        case 'U' :      /* update lastread pointer */
+          sprintf(szString, "|03The last message you read was #%d.\nSet to which message? ",
+            PClan->PublicMsgIndex);
+          PClan->PublicMsgIndex = GetLong(szString, PClan->PublicMsgIndex, Village.Data->PublicMsgIndex-1);
+          break;
+        case 'Q' :      /* return */
+          return 0;
+        case 'V' :      /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case '?' :      /* redisplay options */
+          break;
+        case 'G' :
+          if (Game.Data->InterBBS == FALSE)
+            rputs("Option available only in IBBS!\n");
+          else
+            GlobalMsgPost();
+          break;
+      }
+    }
+	(void)ClanId;
+	(void)iTemp;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void WizardShop ( void )
+  {
+    char *szTheOptions[6], szString[128];
+    _INT16 iTemp, ItemIndex;
+    long ExamineCost;
+
+    LoadStrings(1320, 6, szTheOptions);
+
+    if (!PClan->WizardHelp)
+    {
+      PClan->WizardHelp = TRUE;
+      Help("Wizard", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    // if no wizard shop, tell him
+    if (Village.Data->WizardLevel == 0)
+    {
+      rputs(ST_WIZ0);
+      return;
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+      switch(GetChoice("Wizard Menu", ST_ENTEROPTION, szTheOptions, "SBXQ?V", 'Q', TRUE))
+      {
+        case 'Q' :  // quit
+          return;
+        case 'S' :  /* scrolls */
+          Item_BuyItem(I_SCROLL);
+          break;
+        case 'B' :  /* books */
+          Item_BuyItem(I_BOOK);
+          break;
+        case 'X' :  // examine item
+          // list items
+          // choose one
+          // if not a book or scroll, tell him "I only examine magical items!"
+          // tell him cost (30% of item cost?)
+          // examine it? yes/no
+          // take gold
+          // show help
+
+
+          ListItems(PClan);
+
+          // which item to examine?
+          ItemIndex = GetLong(ST_WIZ1, 0, 30);
+
+          if (ItemIndex == 0) break;
+
+          ItemIndex--;
+
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_INVALIDITEM);
+            break;
+          }
+
+          // show item
+          ShowItemStats(&PClan->Items[ItemIndex], PClan);
+
+          if (PClan->Items[ItemIndex].cType != I_SCROLL &&
+              PClan->Items[ItemIndex].cType != I_BOOK)
+          {
+            rputs(ST_WIZ2);
+            break;
+          }
+
+          ExamineCost = PClan->Items[ItemIndex].lCost/4;
+
+          sprintf(szString, ST_WIZ3, ExamineCost, PClan->Empire.VaultGold);
+
+          rputs(szString);
+          if (PClan->Empire.VaultGold < ExamineCost)
+          {
+            rputs(ST_FMENUNOAFFORD);
+            break;
+          }
+          if (YesNo(ST_WIZ4) == YES)
+          {
+            Help(PClan->Items[ItemIndex].szName, ST_WIZHLP);
+            PClan->Empire.VaultGold -= ExamineCost;
+            door_pause();
+          }
+          break;
+        case 'V' :  // clan stats
+          ClanStats(PClan, TRUE);
+          break;
+      }
+    }
+	(void)iTemp;
+  }
+
+  _INT16 MarketMenu ( void )
+  {
+    char *szTheOptions[10];
+    _INT16 iTemp;
+
+    LoadStrings(231, 9, szTheOptions);
+    szTheOptions[9] = "Wizard's Shop";
+
+    if (!PClan->MarketHelp)
+    {
+      PClan->MarketHelp = TRUE;
+      Help("Market", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+      switch(GetChoice("Market Menu", ST_ENTEROPTION, szTheOptions, "WQ?VAST/PZ", 'Q', TRUE))
+      {
+        case 'W' :    /* buy weapon */
+          Item_BuyItem(I_WEAPON);
+          break;
+        case 'A' :    /* buy armor */
+          Item_BuyItem(I_ARMOR);
+          break;
+        case 'S' :    /* buy shield */
+          Item_BuyItem(I_SHIELD);
+          break;
+        case 'Z' :  // wizard's shop
+          WizardShop();
+          break;
+        case 'T' :  /* trading */
+          if (PClan->FirstDay)
+            rputs("|07You cannot trade until tomorrow.\n%P");
+          else
+            Trades_MakeTrade();
+          break;
+        case 'P' :  // pawn shop
+          PawnShop();
+          break;
+        case 'Q' :    /* return to previous menu */
+          return 0;
+        case '?' :    /* redisplay options */
+          break;
+        case 'V' :    /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case '/' :  //chat villagers
+          ChatVillagers(WN_MARKET);
+          break;
+      }
+    }
+	(void)iTemp;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 AlliancesMenu ( void )
+  {
+    struct Alliance *Alliances[MAX_ALLIANCES];
+    _INT16 iTemp, NumAlliances, WhichAlliance, NumUserAlliances;
+    char cKey, szChoices[MAX_ALLIANCES + 5], szFileName[13];
+    char *szString;
+
+    if (!PClan->AllyHelp)
+    {
+      PClan->AllyHelp = TRUE;
+      Help("Alliances", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    GetAlliances(Alliances);
+
+    szString = MakeStr(128);
+
+    // display them, if any
+    rputs(ST_AMENU0);    // show title
+    rputs(ST_LONGLINE);
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+    {
+      if (Alliances[iTemp] == NULL) break;
+
+      // od_printf("(%c) %s\n\r", iTemp+'A', Alliances[iTemp]->szName);
+      sprintf(szString, ST_AMENU1, iTemp+'A', Alliances[iTemp]->szName);
+      rputs(szString);
+
+      szChoices[iTemp] = iTemp + 'A';
+    }
+    NumAlliances = iTemp;
+
+    // see how many alliances the user has
+    NumUserAlliances = 0;
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      if (PClan->Alliances[iTemp] != -1)
+        NumUserAlliances++;
+
+    // make options ... "ABC....Q\r\n"
+    szChoices[ NumAlliances ] = 'Q';
+    szChoices[ NumAlliances + 1 ] = 'Z';
+    szChoices[ NumAlliances + 2 ] = '\r';
+    szChoices[ NumAlliances + 3 ] = '\n';
+    szChoices[ NumAlliances + 4 ] = 0;
+
+    rputs(ST_AMENU2);
+
+    rputs(ST_LONGLINE); rputs(" ");
+    rputs(ST_ENTEROPTION);
+
+    cKey = od_get_answer(szChoices);
+
+    if (cKey == 'Z')
+    {
+      rputs(ST_CREATEALLIANCE);
+      if (PClan->MadeAlliance)
+        rputs("\n|07You have already created an alliance.\n");
+      else
+      {
+        // ask user if he wants to build one
+        // if (NoYes("Create alliance?") == YES)
+        if (NoYes(ST_MAKEALLIANCEQ) == YES)
+        {
+          if (NumAlliances == MAX_ALLIANCES)
+          {
+            // rputs("|09You cannot create a new alliance, there are already too many\n");
+            rputs(ST_CANTBUILD);
+          }
+          else if (NumUserAlliances == MAX_ALLIES)
+          {
+            // see if already too many alliances for this guy
+            rputs("|09You're already in the max. alliances. can't join anymore.\n");
+          }
+          else
+          {
+            Alliances[NumAlliances] = malloc(sizeof(struct Alliance));
+            CheckMem(Alliances[NumAlliances]);
+
+            CreateAlliance(Alliances[ NumAlliances ], Alliances);
+            UpdateAlliances(Alliances);
+            PClan->MadeAlliance = TRUE;
+            if (EnterAlliance(Alliances[ NumAlliances ]))
+            {
+              // remove chatfile first
+              sprintf(szFileName, "hall%02d.txt", Alliances[NumAlliances]->ID);
+              unlink(szFileName);
+
+              // remove from user's alliance list
+              for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+                if (PClan->Alliances[iTemp] == Alliances[NumAlliances]->ID)
+                  PClan->Alliances[iTemp] = -1;
+
+              // only if he is the ORIGINAL creator will he have flag set
+              if (Alliances[NumAlliances]->OriginalCreatorID[0] == PClan->ClanID[0] &&
+                Alliances[NumAlliances]->OriginalCreatorID[1] == PClan->ClanID[1])
+              {
+                PClan->MadeAlliance = FALSE;
+              }
+
+              KillAlliance(Alliances[NumAlliances]->ID);
+
+              // delete alliance since user chose to
+              free(Alliances[NumAlliances]);
+
+              Alliances[NumAlliances] = NULL;
+            }
+          }
+        }
+      }
+    }
+    else if (cKey != 'Q' && cKey != '\r' && cKey != '\n')
+    {
+      WhichAlliance = cKey - 'A';
+
+      sprintf(szString, "%s\n", Alliances[ WhichAlliance ]->szName);
+      rputs(szString);
+
+      // see if in that alliance
+      for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      {
+        if (PClan->Alliances[ iTemp ] == Alliances[ WhichAlliance ]->ID)
+          break;
+      }
+
+      if (iTemp != MAX_ALLIES)
+      {
+        // in that alliance, enter it
+
+        if (EnterAlliance(Alliances[ WhichAlliance ]))
+        {
+          // remove chatfile first
+          sprintf(szFileName, "hall%02d.txt", Alliances[WhichAlliance]->ID);
+          unlink(szFileName);
+
+          // only if he is the ORIGINAL creator will he have flag set
+          if (Alliances[WhichAlliance]->OriginalCreatorID[0] == PClan->ClanID[0] &&
+            Alliances[WhichAlliance]->OriginalCreatorID[1] == PClan->ClanID[1])
+          {
+            PClan->MadeAlliance = FALSE;
+          }
+
+          // remove from user's alliance list
+          for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+            if (PClan->Alliances[iTemp] == Alliances[WhichAlliance]->ID)
+              PClan->Alliances[iTemp] = -1;
+
+          KillAlliance(Alliances[WhichAlliance]->ID);
+
+          // delete hall since user chose to
+          free(Alliances[WhichAlliance]);
+
+          Alliances[WhichAlliance] = NULL;
+        }
+      }
+      else
+      {
+        // not in alliance
+        rputs("\n |0CYou are not in that alliance.\n");
+        if (YesNo(" |0SWrite a message to the alliance's creator?") == YES)
+        {
+          MyWriteMessage2(Alliances[WhichAlliance]->CreatorID, FALSE, FALSE, -1, "", FALSE, -1);
+        }
+      }
+    }
+    else  // quit
+      rputs(ST_QUIT);
+
+    // deinit alliances and update to file
+    UpdateAlliances(Alliances);
+
+    // free up mem used by alliances
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      if (Alliances[iTemp])
+      {
+        free(Alliances[iTemp]);
+        Alliances[iTemp] = NULL;
+      }
+
+    free(szString);
+
+    return 0;
+  }
+
+
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 ChurchMenu ( void )
+  {
+    char *szTheOptions[9];
+    char szString[80];
+    _INT16 iTemp, Event;
+
+    // ST_CHURCHOP0
+    LoadStrings(890, 9, szTheOptions);
+
+    if (!PClan->ChurchHelp)
+    {
+      PClan->ChurchHelp = TRUE;
+      Help("Church Menu", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    /* if no church yet, tell user */
+    if (Village.Data->ChurchLevel == 0)
+    {
+      rputs("\n|07There is currently no church in the village.\n%P");
+      return 0;
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      /* church info */
+      rputs("\n\n");
+      rputs(ST_LONGLINE);
+
+      sprintf(szString, " |0CLevel of Church: |0M%d\n", Village.Data->ChurchLevel);
+      rputs(szString);
+
+      switch(GetChoice("Church Menu", ST_ENTEROPTION, szTheOptions, "MBPDQ?VU/", 'Q', TRUE))
+      {
+        case 'M' :      /* attend mass */
+          if (PClan->AttendedMass)
+          {
+            rputs("|07You've already attended today's mass.\n%P");
+            break;
+          }
+          PClan->AttendedMass = TRUE;
+
+          RunEvent(FALSE, "/e/Church", "", NULL, NULL);
+          door_pause();
+          break;
+        case 'P' :      /* pray */
+          if (PClan->Prayed)
+          {
+            rputs("|07You've already prayed today.\n%P");
+            break;
+          }
+          PClan->Prayed = TRUE;
+
+          RunEvent(FALSE, "/e/Pray", "", NULL, NULL);
+          door_pause();
+          break;
+        case 'B' :      /* ask for blessing */
+          // FIXME: make better?
+          if (Village.Data->ChurchLevel < 2)
+          {
+            rputs("|07This church isn't of a high enough level.  You aren't able to find a priest.\n%P");
+            break;
+          }
+
+          if (PClan->GotBlessing)
+          {
+            rputs("|07You've already gotten a blessing today.\n%P");
+            break;
+          }
+          PClan->GotBlessing = TRUE;
+
+          rputs("\n|06A priest blesses your clan.\n\n");
+
+          /* give XP */
+          for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+          {
+            if (PClan->Member[iTemp] && PClan->Member[iTemp]->Status == Here)
+            {
+              PClan->Member[iTemp]->SP = PClan->Member[iTemp]->MaxSP;
+            }
+          }
+          rputs("|14Your clan regenerates all its lost skill points!\n%P");
+          break;
+        case 'D' :      /* resurrect somebody */
+          if (Village.Data->ChurchLevel < 3)
+          {
+            rputs("|07This church isn't capable of that at its current level.\n%P");
+            break;
+          }
+          ResurrectDead( FALSE );
+          break;
+        case 'U' :      /* revive unconscious */
+          if (Village.Data->ChurchLevel < 2)
+          {
+            rputs("|07This church isn't capable of that at its current level.\n%P");
+            break;
+          }
+          ResurrectDead( TRUE );
+          break;
+        case 'Q' :      /* return to previous menu */
+          return 0;
+        case '?' :      /* redisplay options */
+          break;
+        case 'V' :      /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case '/' :  //chat villagers
+          ChatVillagers(WN_CHURCH);
+          break;
+      }
+    }
+	(void)Event;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 THallMenu ( void )
+  {
+    char *szTheOptions[7];
+    char szString[80];
+    _INT16 iTemp;
+
+    LoadStrings(655, 7, szTheOptions);
+
+    if (!PClan->THallHelp)
+    {
+      PClan->THallHelp = TRUE;
+      Help("Training Hall Menu", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    /* if no training hall yet, tell user */
+    if (Village.Data->TrainingHallLevel == 0)
+    {
+      rputs("\n|07There is currently no training hall in the village.\n%P");
+      return 0;
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      /* training info */
+      rputs("\n\n");
+      rputs(ST_LONGLINE);
+
+      sprintf(szString, " |0CLevel of Hall  : |0M%d\n", Village.Data->TrainingHallLevel);
+      rputs(szString);
+
+      switch(GetChoice("Training Hall", ST_ENTEROPTION, szTheOptions, "TALQ?V/", 'Q', TRUE))
+      {
+        case 'T' :      /* train member */
+          TrainMember();
+          break;
+        case 'A' :      /* add a member */
+          /* if too many members, tell user */
+          AddMember();
+          break;
+        case 'L' :      /* release member */
+          ReleaseMember();
+          /* list members */
+          /* see which one he wants */
+          /* confirm release of member */
+          break;
+        case 'Q' :      /* return to previous menu */
+          return 0;
+        case '?' :      /* redisplay options */
+          break;
+        case 'V' :      /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case '/' :  //chat villagers
+          ChatVillagers(WN_THALL);
+          break;
+      }
+    }
+	(void)iTemp;
+  }
+
+
+
+
+// ------------------------------------------------------------------------- //
+
+  void GameLoop( void )
+  {
+    _INT16 MenuNum = 0;
+    BOOL Quit = FALSE;
+    char szString[80];
+
+    while (!Quit)
+    {
+      switch(MenuNum)
+      {
+        case 0 :  /* Main menu */
+          rputs(ST_4RETURNS);
+          MenuNum = MainMenu();
+          break;
+        case 1 :  /* mines */
+          rputs(ST_4RETURNS);
+          MenuNum = MineMenu();
+          break;
+        case 2 :  /* MarketMenu */
+          rputs(ST_4RETURNS);
+          MenuNum = MarketMenu();
+          break;
+        case 3 :  /* CommMenu */
+          rputs(ST_4RETURNS);
+          MenuNum = CommunicationsMenu();
+          break;
+        case 5 :  /* World Travel Menu */
+          if (Game.Data->InterBBS)
+          {
+            rputs(ST_4RETURNS);
+            MenuNum = WorldMenu();
+          }
+          else
+          {
+            // rputs("|07World Travel is only permitted in InterBBS games.\n%P");
+            rputs(ST_MAIN5);
+            rputs("\n\n");
+            MenuNum = MainMenu();
+          }
+          break;
+        case 6 :  /* Town Hall Menu */
+          rputs(ST_4RETURNS);
+
+          if (!PClan->TownHallHelp)
+          {
+            PClan->TownHallHelp = TRUE;
+            Help("Town Hall", ST_NEWBIEHLP);
+            rputs("\n%P");
+          }
+
+          /* see if ruler */
+          if (Village.Data->RulingClanId[0] == -1)
+          {
+            /* no ruler yet, ask if he wants to rule */
+            // currently no ruler
+            sprintf(szString, ST_MAIN6, Village.Data->szName);
+            rputs(szString);
+
+            if (YesNo("|0SDoes your clan wish to rule the village?") == YES)
+            {
+              Village_NewRuler();
+            }
+          }
+          //MenuNum = 0;
+          //break;
+
+          if (Village.Data->RulingClanId[0] != PClan->ClanID[0] ||
+            Village.Data->RulingClanId[1] != PClan->ClanID[1])
+          {
+            MenuNum = OutsiderTownHallMenu();
+          }
+          else
+            MenuNum = TownHallMenu();
+          break;
+        case 7 :  /* empire Menu */
+          rputs(ST_4RETURNS);
+          if (Game.Data->ClanEmpires)
+            Empire_Manage(&PClan->Empire);
+          else
+            rputs("Clan empires are disabled.\n%P");
+            MenuNum = 0;
+          break;
+        case 9 :  /* church */
+          rputs(ST_4RETURNS);
+          MenuNum = ChurchMenu();
+          break;
+        case 10 :  /* training hall */
+          rputs(ST_4RETURNS);
+          MenuNum = THallMenu();
+          break;
+        case 11 :  /* Alliances */
+          rputs(ST_4RETURNS);
+          MenuNum = AlliancesMenu();
+          break;
+        case -1 : /* quit */
+          Quit = TRUE;
+          break;
+      }
+    }
+  }
+
diff --git a/src/doors/clans-src/menus.h b/src/doors/clans-src/menus.h
new file mode 100644
index 0000000000000000000000000000000000000000..90ee4bfc69be623b078f37ad68de32bf3511404a
--- /dev/null
+++ b/src/doors/clans-src/menus.h
@@ -0,0 +1,6 @@
+
+  void GameLoop( void );
+
+  void Menus_ChatRoom ( char *pszFileName );
+
+  _INT16 WorldMenu ( void );
diff --git a/src/doors/clans-src/menus2.c b/src/doors/clans-src/menus2.c
new file mode 100644
index 0000000000000000000000000000000000000000..958b4d096307341093d1a0856a5d42e903b285a8
--- /dev/null
+++ b/src/doors/clans-src/menus2.c
@@ -0,0 +1,521 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "user.h"
+#include "help.h"
+#include "door.h"
+#include "input.h"
+#include "reg.h"
+
+extern struct Language *Language;
+extern struct village Village;
+extern struct clan *PClan;
+extern struct game Game;
+extern struct config *Config;
+
+  void ResurrectDead( BOOL Unconscious )
+  {
+    _INT16 NumDead = 0, iTemp, WhichOne, MaxRes;
+    long Cost;
+    char szString[128], cInput;
+
+    // if reached max..
+    if (Unconscious)
+    {
+      MaxRes = Village.Data->ChurchLevel + 1;
+      if (PClan->ResUncToday == MaxRes)
+      {
+        rputs("|07This level of church cannot revive any more unconscious today.\n%P");
+        return;
+      }
+    }
+    else
+    {
+      MaxRes = Village.Data->ChurchLevel;
+      if (PClan->ResDeadToday == MaxRes)
+      {
+        rputs("|07This level of church cannot raise any more dead today.\n%P");
+        return;
+      }
+    }
+
+
+    /* if nobody dead in party, tell him */
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp])
+      {
+        if (Unconscious == FALSE &&
+          PClan->Member[iTemp]->Status == Dead)
+          NumDead++;
+        else if (Unconscious == TRUE &&
+          PClan->Member[iTemp]->Status == Unconscious)
+          NumDead++;
+      }
+    }
+    if (NumDead == 0)
+    {
+      if (Unconscious == FALSE)
+        rputs("\n|07No members of your party need resurrection from the dead.\n%P");
+      else
+        rputs("\n|07No members of your party are unconscious.\n%P");
+      return;
+    }
+
+    /* if nobody dead in party, tell him */
+    rputs(ST_LONGLINE);
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp] &&
+        PClan->Member[iTemp]->Status == Dead && Unconscious == FALSE)
+      {
+        sprintf(szString, " |0A(|0B%c|0A) |0C%s\n", iTemp + 'A', PClan->Member[iTemp]->szName);
+        rputs(szString);
+      }
+      else if (PClan->Member[iTemp] &&
+        PClan->Member[iTemp]->Status == Unconscious && Unconscious == TRUE)
+      {
+        sprintf(szString, " |0A(|0B%c|0A) |0C%s\n", iTemp + 'A', PClan->Member[iTemp]->szName);
+        rputs(szString);
+      }
+    }
+    rputs(" |0A(|0BQ|0A) |0CAbort\n");
+
+    rputs(ST_LONGLINE);
+    rputs(" |0AWhich to resurrect? [|0BEnter=Abort|0A] : |15");
+    cInput = toupper(od_get_key(TRUE));
+
+    if (cInput == 'Q' || cInput == '\r' || cInput == '\n')
+    {
+      rputs(ST_ABORTED);
+      return;
+    }
+
+    WhichOne = cInput - 'A';
+
+    sprintf(szString, "%c\n", cInput);
+    rputs(szString);
+
+    /* if that dude is alive, tell them */
+    if (PClan->Member[ WhichOne ] == NULL ||
+        (cInput-'A') > MAX_MEMBERS || (cInput-'A') < 0)
+    {
+      rputs("|12Member not found.\n%P");
+      return;
+    }
+
+    if (!Unconscious && PClan->Member[ WhichOne ]->Status != Dead)
+    {
+      rputs("|12That member isn't dead!\n%P");
+      return;
+    }
+    if (Unconscious && PClan->Member[ WhichOne ]->Status != Unconscious)
+    {
+      rputs("|12That member isn't unconscious!\n%P");
+      return;
+    }
+
+    /* else tell them how much it costs */
+    if (Unconscious == FALSE)
+      Cost = ((long)PClan->Member[ WhichOne ]->Level + 1L) * 750L;
+    else
+      Cost = ((long)PClan->Member[ WhichOne ]->Level + 1L) * 300L;
+
+    sprintf(szString, "\n|0CIt will cost you %ld gold.\n", Cost);
+    rputs(szString);
+
+    /* if not enough dough, say go away */
+    if (PClan->Empire.VaultGold < Cost)
+    {
+      rputs("|12You cannot afford it!\n%P");
+      return;
+    }
+
+    /* if enough, ask NoYes if wish to revive */
+    sprintf(szString, "|0CAre you sure you wish to resurrect |0B%s|0C?",
+      PClan->Member[WhichOne]->szName);
+
+    if (NoYes(szString) == YES)
+    {
+      /* if so, revive stats et al */
+
+      PClan->Member[ WhichOne ]->HP = PClan->Member[ WhichOne ]->MaxHP;
+      PClan->Member[ WhichOne ]->SP = PClan->Member[ WhichOne ]->MaxSP;
+      PClan->Member[ WhichOne ]->Status = Here;
+
+      PClan->Empire.VaultGold -= Cost;
+
+      if (Unconscious == FALSE)
+        sprintf(szString, "%s has been resurrected from the dead!\n%%P",
+          PClan->Member[ WhichOne ]->szName);
+      else
+        sprintf(szString, "%s has been revived!\n%%P",
+          PClan->Member[ WhichOne ]->szName);
+      rputs(szString);
+
+      if (Unconscious)
+        PClan->ResUncToday++;
+      else
+        PClan->ResDeadToday++;
+    }
+  }
+
+
+  void ReleaseMember ( void )
+  {
+    /* list members */
+    /* see which one he wants */
+    /* confirm release of member */
+
+    _INT16 iTemp, WhichOne, Choice;
+    long Cost;
+    char szString[128], cInput;
+
+    rputs(ST_LONGLINE);
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp])
+      {
+        sprintf(szString, " |0A(|0B%c|0A) |0C%-15s ",
+          iTemp + 'A', PClan->Member[iTemp]->szName);
+
+        if (PClan->Member[iTemp]->Status == Here)
+          strcat(szString, "|14(alive)\n");
+        else if (PClan->Member[iTemp]->Status == Unconscious)
+          strcat(szString, "|12(unconscious)\n");
+        else if (PClan->Member[iTemp]->Status == Dead)
+          strcat(szString, "|04(dead)\n");
+
+        rputs(szString);
+      }
+    }
+    rputs(" |0A(|0BQ|0A) |0CAbort\n");
+
+    rputs(ST_LONGLINE);
+    rputs(" |0AWhich to release? [|0BEnter=abort|0A] : |0F");
+
+    for (;;)
+    {
+      cInput = toupper(od_get_key(TRUE));
+
+      if (cInput == 'Q' || cInput == '\r' || cInput == '\n')
+      {
+        rputs(ST_ABORTED);
+        return;
+      }
+
+      WhichOne = cInput - 'A';
+
+      if (WhichOne >= 0 && WhichOne < MAX_MEMBERS &&
+        PClan->Member[WhichOne])
+        break;
+    }
+    sprintf(szString, "%s\n", PClan->Member[WhichOne]->szName);
+    rputs(szString);
+
+    // if he is not a perm. member, tell user
+    if (WhichOne >= Game.Data->MaxPermanentMembers)
+    {
+      rputs("|04That is not a permanent member.  He will be released at the end of the day.\n%P");
+      return;
+    }
+
+    /* confirm it */
+    //sprintf(szString, "|0SAre you sure you wish to remove %s from the clan?",
+    sprintf(szString, ST_REMOVEMEM, PClan->Member[ WhichOne ]->szName);
+    if (NoYes(szString) == YES)
+    {
+      // %s removed from clan
+      sprintf(szString, ST_REMOVED,
+        PClan->Member[ WhichOne ]->szName);
+      rputs(szString);
+
+      /* release member */
+      /* release data from his links */
+      for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+      {
+        /* if held by deleted char, remove link */
+        if (PClan->Items[iTemp].Available &&
+          PClan->Items[iTemp].UsedBy == WhichOne+1)
+        {
+          PClan->Items[iTemp].UsedBy = 0;
+        }
+      }
+
+
+      free(PClan->Member[ WhichOne ]);
+      PClan->Member[ WhichOne ] = NULL;
+    }
+	(void)Choice;
+	(void)Cost;
+  }
+
+  void AddMember ( void )
+  {
+    struct pc *TmpPC;
+    _INT16 EmptySlot, iTemp, NumMembers;
+
+    NumMembers = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp] && iTemp < Game.Data->MaxPermanentMembers &&
+        PClan->Member[iTemp]->Undead == FALSE)
+        NumMembers++;
+    }
+
+    /* see if too many members already */
+    if (NumMembers >= Game.Data->MaxPermanentMembers)
+    {
+      // rputs("|07Your clan has the maximum number of permanent members already.\n%P");
+      rputs(ST_TOOMANYMEMBERS);
+      return;
+    }
+
+    /* train dude */
+
+    /* search for empty slot in player list */
+    for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+      if (PClan->Member[iTemp] == NULL)
+        break;
+
+    EmptySlot = iTemp;
+
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+    if (iTemp == 0)
+      PC_Create(TmpPC, TRUE);
+    else
+      PC_Create(TmpPC, FALSE);
+
+    PClan->Member[EmptySlot] = malloc(sizeof(struct pc));
+    CheckMem(PClan->Member[EmptySlot]);
+    // CopyPC(PClan->Member[EmptySlot], TmpPC);
+    *PClan->Member[EmptySlot] = *TmpPC;
+    free(TmpPC);
+  }
+
+  void TrainMember ( void )
+  {
+    /* ask for which one */
+    /* see if that member has any training points */
+    /* if not, boot him */
+    /* else, give listing of attributes which can be "trained" */
+
+    _INT16 iTemp, WhichOne = 0, Choice;
+    long Cost;
+    char szString[128], cInput;
+    BOOL Done = FALSE, DoneTraining = FALSE;
+    char *szTheOptions[11];
+
+    /* cost to upgrade stat */
+    _INT16 TCost[8] = { 10, 10, 20, 10, 30, 40, 10, 10 };
+    _INT16 IncreaseAmount;
+
+    for (iTemp = 0; iTemp < 8; iTemp++)
+    {
+      TCost[iTemp] -= Village.Data->TrainingHallLevel;
+    }
+
+    szTheOptions[0] = ST_ATTRNAME0;
+    szTheOptions[1] = ST_ATTRNAME1;
+    szTheOptions[2] = ST_ATTRNAME2;
+    szTheOptions[3] = ST_ATTRNAME3;
+    szTheOptions[4] = ST_ATTRNAME4;
+    szTheOptions[5] = ST_ATTRNAME5;
+    szTheOptions[6] = "HP";
+    szTheOptions[7] = "SP";
+    szTheOptions[8] = "View Stats";
+    szTheOptions[9] = "Help";
+    szTheOptions[10]= "Quit";
+
+    while (!DoneTraining)
+    {
+      rputs(ST_LONGLINE);
+      for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+      {
+        if (PClan->Member[iTemp] &&
+          PClan->Member[iTemp]->Status == Here)
+        {
+          sprintf(szString, " |0A(|0B%c|0A) |0C%-15s |03(%d tpoints)\n", iTemp + 'A', PClan->Member[iTemp]->szName,
+            PClan->Member[iTemp]->TrainingPoints);
+          rputs(szString);
+        }
+      }
+      rputs(" |0A(|0BQ|0A) |0CQuit\n");
+
+      rputs(ST_LONGLINE);
+      rputs(" |0SWho to train? [|0BEnter=Return|0A] : |0F");
+
+      for (;;)
+      {
+        cInput = toupper(od_get_key(TRUE));
+
+        if (cInput == 'Q' || cInput == '\r' || cInput == '\n')
+        {
+          DoneTraining = TRUE;
+          break;
+        }
+
+        WhichOne = cInput - 'A';
+        if (WhichOne >= 0 && WhichOne < Game.Data->MaxPermanentMembers &&
+          PClan->Member[WhichOne])
+          break;
+      }
+
+      if (DoneTraining)
+        break;
+
+      sprintf(szString, "%s\n\r", PClan->Member[WhichOne]->szName);
+      rputs(szString);
+
+      /* if that dude is alive, tell them */
+      if (PClan->Member[ WhichOne ]->Status != Here)
+      {
+        rputs("|04Member is not conscious and cannot train.\n%P");
+        continue;
+      }
+
+      if (PClan->Member[WhichOne]->TrainingPoints == 0)
+      {
+        rputs("|07That member has no training points!\n%P");
+        continue;
+      }
+
+      /* if that dude is alive, tell them */
+/* NO MORE REG
+      if (PClan->Member[ WhichOne ]->Level > 5 &&
+        IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE)
+      {
+        rputs("\n|12Members cannot be trained beyond level 5 in the unregistered version.\n%P");
+        continue;
+      }
+*/
+
+      Done = FALSE;
+      while (!Done)
+      {
+        sprintf(szString, "\n\n |0BTraining %s\n",
+          PClan->Member[WhichOne]->szName);
+        rputs(szString);
+        rputs(ST_LONGLINE);
+        /* list attributes */
+        for (iTemp = 0; iTemp < 8; iTemp++)
+        {
+          sprintf(szString, " |0A(|0B%d|0A) |0C%-20s |06(%2d tpoints)\n",
+            iTemp+1, szTheOptions[iTemp], TCost[iTemp]);
+          rputs(szString);
+        }
+        rputs(" |0A(|0BV|0A) |0CView Stats\n");
+        rputs(" |0A(|0B?|0A) |0CHelp on Stats\n");
+        rputs(" |0A(|0BQ|0A) |0CAbort\n\n");
+        rputs(" |0CPlease choose an attribute to upgrade.\n");
+        sprintf(szString, " |0B%s |0Chas |0B%d |0Ctraining point(s) to use.\n",
+          PClan->Member[WhichOne]->szName,
+          PClan->Member[WhichOne]->TrainingPoints);
+        rputs(szString);
+        rputs(ST_LONGLINE);
+
+        switch(Choice = GetChoice("", ST_ENTEROPTION, szTheOptions, "12345678V?Q", 'Q', TRUE))
+        {
+          case '1' :  /* agility */
+          case '2' :  /* dexterity */
+          case '3' :  /* strength */
+          case '4' :  /* wisdom */
+          case '5' :  /* armor str */
+          case '6' :  /* charisma */
+          case '7' :  /* hp */
+          case '8' :  /* mp */
+            /* see if enough TPoints */
+            if (PClan->Member[WhichOne]->TrainingPoints <
+              TCost[Choice - '1'])
+            {
+              rputs("|04Not enough training points!\n%P");
+              break;
+            }
+
+            PClan->Member[WhichOne]->TrainingPoints -=
+              TCost[Choice - '1'];
+
+            /* upgrade stat */
+            if (Choice >= '1' && Choice <= '6')
+            {
+              PClan->Member[WhichOne]->Attributes[Choice-'1']++;
+
+              sprintf(szString, "|03%s's %s increases by |141|03.\n",
+                PClan->Member[WhichOne]->szName,
+                szTheOptions[Choice -'1']);
+              rputs(szString);
+            }
+            else if (Choice == '7')
+            {
+              /* HP increase */
+              IncreaseAmount = (3 + RANDOM(5) + RANDOM(5));
+              PClan->Member[WhichOne]->MaxHP += IncreaseAmount;
+
+              sprintf(szString, "|03%s's max HP increases by |14%d|03.\n",
+                PClan->Member[WhichOne]->szName, IncreaseAmount);
+              rputs(szString);
+            }
+            else if (Choice == '8')
+            {
+              /* SP increase */
+              IncreaseAmount = (2 + RANDOM(3) + RANDOM(3));
+              PClan->Member[WhichOne]->MaxSP += IncreaseAmount;
+
+              sprintf(szString, "|03%s's max SP increases by |14%d|03.\n",
+                PClan->Member[WhichOne]->szName, IncreaseAmount);
+              rputs(szString);
+            }
+            door_pause();
+            break;
+          case 'Q' :  /* quit */
+            Done = TRUE;
+            break;
+          case 'V' :  /* view stats */
+            ShowPlayerStats(PClan->Member[WhichOne], FALSE);
+            door_pause();
+            break;
+          case '?' :  /* help file */
+            GeneralHelp(ST_STATSHLP);
+            break;
+        }
+      }
+    }
+
+    // return
+	(void)Cost;
+  }
+
diff --git a/src/doors/clans-src/menus2.h b/src/doors/clans-src/menus2.h
new file mode 100644
index 0000000000000000000000000000000000000000..58698a68a977e115e196cd171506cc06eca27479
--- /dev/null
+++ b/src/doors/clans-src/menus2.h
@@ -0,0 +1,7 @@
+
+  void ResurrectDead( BOOL Unconscious );
+
+  void ReleaseMember ( void );
+  void AddMember ( void );
+
+  void TrainMember ( void );
diff --git a/src/doors/clans-src/misc.c b/src/doors/clans-src/misc.c
new file mode 100644
index 0000000000000000000000000000000000000000..6398bfc5f15088aca5e47004fbcc7bcda23c44b1
--- /dev/null
+++ b/src/doors/clans-src/misc.c
@@ -0,0 +1,97 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Miscellaneous functions we need
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "defines.h"
+
+#define TOTAL_MONTHS	12
+
+  long DaysSinceJan1( char szTheDate[] )
+  {
+    long CurMonth, Days = 0, ThisMonth, ThisYear, ThisDay;
+    BOOL LeapYear;
+    _INT16 NumDaysPerMonth[2][TOTAL_MONTHS] = {
+      { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+      { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }  };
+
+    ThisDay = atoi(&szTheDate[3]);
+    ThisMonth = atoi(szTheDate);
+    ThisYear = atoi(&szTheDate[6]);
+
+    for (CurMonth = 1; CurMonth < ThisMonth; CurMonth++)
+    {
+      LeapYear = (ThisYear % 4) == 0;
+
+      Days += (long) NumDaysPerMonth[LeapYear + 0][CurMonth - 1];
+    }
+
+    Days += ThisDay;
+
+    return (Days);
+
+  }
+
+  long DaysSince1970 ( char szTheDate[] )
+  {
+    long Days = 0, ThisYear, CurYear;
+    BOOL LeapYear;
+
+    ThisYear = atoi(&szTheDate[6]);
+
+    for (CurYear = 1970; CurYear < ThisYear; CurYear++)
+    {
+      LeapYear = (CurYear % 4) == 0;
+
+      if (LeapYear)
+        Days += 366;
+      else
+        Days += 365;
+    }
+
+    Days += DaysSinceJan1(szTheDate);
+
+    return (Days);
+  }
+
+  long DaysBetween ( char szFirstDate[], char szLastDate[] )
+    /*
+     * This function returns the number of days between the first date and
+     * last date.
+     *
+     *
+     * DaysBetween = LastDate - FirstDate
+     *
+     *
+     * LastDate is MOST recent date.
+     */
+  {
+    long Days;
+
+    Days = DaysSince1970(szLastDate) - DaysSince1970(szFirstDate);
+
+    return (Days);
+  }
+
diff --git a/src/doors/clans-src/misc.h b/src/doors/clans-src/misc.h
new file mode 100644
index 0000000000000000000000000000000000000000..57ba33e989192501f9c79f6dbec86ef6401a00c5
--- /dev/null
+++ b/src/doors/clans-src/misc.h
@@ -0,0 +1,14 @@
+
+  long DaysBetween ( char szFirstDate[], char szLastDate[] );
+    /*
+     * This function returns the number of days between the first date and
+     * last date.
+     *
+     *
+     * DaysBetween = LastDate - FirstDate
+     *
+     *
+     * LastDate is MOST recent date.
+     */
+
+  long DaysSince1970 ( char szTheDate[] );
diff --git a/src/doors/clans-src/mstrings.h b/src/doors/clans-src/mstrings.h
new file mode 100644
index 0000000000000000000000000000000000000000..338e8ea7fa6c8166f977b5dfd4e9da3ffee61b08
--- /dev/null
+++ b/src/doors/clans-src/mstrings.h
@@ -0,0 +1,1061 @@
+// MStrings.H
+//
+// Contains the string definitions.
+
+#define ERRORBASE		900
+
+#define ST_PAUSE        &Language->BigString[Language->StrOffsets[1]]
+#define ST_MORE         &Language->BigString[Language->StrOffsets[2]]
+#define ST_NOCLAN       &Language->BigString[Language->StrOffsets[3]]
+#define ST_ABORTED      &Language->BigString[Language->StrOffsets[4]]
+#define ST_ENTEROPTION  &Language->BigString[Language->StrOffsets[5]]
+#define ST_YES          &Language->BigString[Language->StrOffsets[6]]
+#define ST_NO           &Language->BigString[Language->StrOffsets[7]]
+#define ST_VILLNOAFFORD &Language->BigString[Language->StrOffsets[8]]
+#define ST_QUIT         &Language->BigString[Language->StrOffsets[9]]
+
+#define ST_ATTRNAME0    &Language->BigString[Language->StrOffsets[10]]
+#define ST_ATTRNAME1    &Language->BigString[Language->StrOffsets[11]]
+#define ST_ATTRNAME2    &Language->BigString[Language->StrOffsets[12]]
+#define ST_ATTRNAME3    &Language->BigString[Language->StrOffsets[13]]
+#define ST_ATTRNAME4    &Language->BigString[Language->StrOffsets[14]]
+#define ST_ATTRNAME5    &Language->BigString[Language->StrOffsets[15]]
+#define ST_APPROVALRISE &Language->BigString[Language->StrOffsets[18]]
+#define ST_APPROVALDROP &Language->BigString[Language->StrOffsets[19]]
+
+#define ST_LONGDIVIDER  &Language->BigString[Language->StrOffsets[20]]
+#define ST_LONGLINE     &Language->BigString[Language->StrOffsets[21]]
+#define ST_INVALIDITEM  &Language->BigString[Language->StrOffsets[22]]
+#define ST_SPELLSKNOWN  &Language->BigString[Language->StrOffsets[30]]
+
+#define ST_STUFF1       &Language->BigString[Language->StrOffsets[31]]
+#define ST_STUFF2       &Language->BigString[Language->StrOffsets[32]]
+#define ST_STUFF3       &Language->BigString[Language->StrOffsets[33]]
+#define ST_STUFF4       &Language->BigString[Language->StrOffsets[34]]
+#define ST_STUFF5       &Language->BigString[Language->StrOffsets[35]]
+#define ST_STUFF6       &Language->BigString[Language->StrOffsets[36]]
+#define ST_STUFF7       &Language->BigString[Language->StrOffsets[37]]
+#define ST_STUFF8       &Language->BigString[Language->StrOffsets[38]]
+#define ST_STUFF9       &Language->BigString[Language->StrOffsets[39]]
+#define ST_STUFF10      &Language->BigString[Language->StrOffsets[40]]
+
+#define ST_COLOR00      &Language->BigString[Language->StrOffsets[50]]
+#define ST_COLOR01      &Language->BigString[Language->StrOffsets[51]]
+#define ST_COLOR02      &Language->BigString[Language->StrOffsets[52]]
+#define ST_COLOR03      &Language->BigString[Language->StrOffsets[53]]
+#define ST_COLOR04      &Language->BigString[Language->StrOffsets[54]]
+#define ST_COLOR05      &Language->BigString[Language->StrOffsets[55]]
+#define ST_COLOR06      &Language->BigString[Language->StrOffsets[56]]
+#define ST_COLOR07      &Language->BigString[Language->StrOffsets[57]]
+#define ST_COLOR08      &Language->BigString[Language->StrOffsets[58]]
+#define ST_COLOR09      &Language->BigString[Language->StrOffsets[59]]
+#define ST_COLOR10      &Language->BigString[Language->StrOffsets[60]]
+#define ST_COLOR11      &Language->BigString[Language->StrOffsets[61]]
+#define ST_COLOR12      &Language->BigString[Language->StrOffsets[62]]
+#define ST_COLOR13      &Language->BigString[Language->StrOffsets[63]]
+#define ST_COLOR14      &Language->BigString[Language->StrOffsets[64]]
+#define ST_COLOR15      &Language->BigString[Language->StrOffsets[65]]
+#define ST_COLOR16      &Language->BigString[Language->StrOffsets[66]]
+
+#define ST_BMENU0       &Language->BigString[Language->StrOffsets[70]]
+#define ST_BMENU1       &Language->BigString[Language->StrOffsets[71]]
+#define ST_BMENU2       &Language->BigString[Language->StrOffsets[72]]
+#define ST_BMENU3       &Language->BigString[Language->StrOffsets[73]]
+#define ST_BMENU4       &Language->BigString[Language->StrOffsets[74]]
+#define ST_BMENU5       &Language->BigString[Language->StrOffsets[75]]
+#define ST_BMENU6       &Language->BigString[Language->StrOffsets[76]]
+#define ST_BMENU7       &Language->BigString[Language->StrOffsets[77]]
+#define ST_BMENU8       &Language->BigString[Language->StrOffsets[78]]
+#define ST_BMENU9       &Language->BigString[Language->StrOffsets[79]]
+#define ST_BMENU10      &Language->BigString[Language->StrOffsets[80]]
+#define ST_BMENU11      &Language->BigString[Language->StrOffsets[81]]
+#define ST_BMENU12      &Language->BigString[Language->StrOffsets[82]]
+#define ST_BMENU13      &Language->BigString[Language->StrOffsets[83]]
+#define ST_BMENU14      &Language->BigString[Language->StrOffsets[84]]
+#define ST_BMENU15      &Language->BigString[Language->StrOffsets[85]]
+#define ST_BMENU16      &Language->BigString[Language->StrOffsets[86]]
+#define ST_BMENU17      &Language->BigString[Language->StrOffsets[87]]
+#define ST_BMENU18      &Language->BigString[Language->StrOffsets[88]]
+#define ST_BMENU19      &Language->BigString[Language->StrOffsets[89]]
+#define ST_BMENU20      &Language->BigString[Language->StrOffsets[90]]
+#define ST_BMENU21      &Language->BigString[Language->StrOffsets[91]]
+#define ST_BMENU22      &Language->BigString[Language->StrOffsets[92]]
+#define ST_BMENU23      &Language->BigString[Language->StrOffsets[93]]
+#define ST_BMENU24      &Language->BigString[Language->StrOffsets[94]]
+#define ST_BMENU25      &Language->BigString[Language->StrOffsets[95]]
+#define ST_BMENU26      &Language->BigString[Language->StrOffsets[96]]
+#define ST_BMENU27      &Language->BigString[Language->StrOffsets[97]]
+#define ST_BMENU28      &Language->BigString[Language->StrOffsets[98]]
+#define ST_BMENU29      &Language->BigString[Language->StrOffsets[99]]
+
+
+
+#define ST_NOHELP           &Language->BigString[Language->StrOffsets[100]]
+#define ST_NOHELPFILE       &Language->BigString[Language->StrOffsets[101]]
+#define ST_HELPLINE         &Language->BigString[Language->StrOffsets[102]]
+#define ST_HELPHINT         &Language->BigString[Language->StrOffsets[103]]
+#define ST_DISPLAYTOPICS    &Language->BigString[Language->StrOffsets[104]]
+#define ST_INVALIDTOPIC     &Language->BigString[Language->StrOffsets[105]]
+#define ST_HELPEND          &Language->BigString[Language->StrOffsets[106]]
+#define ST_HELPPAUSE        &Language->BigString[Language->StrOffsets[107]]
+
+#define ST_ALLIANCEATMAX    &Language->BigString[Language->StrOffsets[120]]
+#define ST_ALLIANCESURE     &Language->BigString[Language->StrOffsets[121]]
+#define ST_ALLIANCEALREADY  &Language->BigString[Language->StrOffsets[123]]
+#define ST_ALLIANCEOTHERMAX &Language->BigString[Language->StrOffsets[124]]
+#define ST_ALLIANCELETTER   &Language->BigString[Language->StrOffsets[125]]
+#define ST_NOALLIANCES      &Language->BigString[Language->StrOffsets[126]]
+#define ST_ALLIANCES        &Language->BigString[Language->StrOffsets[127]]
+
+
+#define ST_NOALLIANCES      &Language->BigString[Language->StrOffsets[126]]
+#define ST_ALLIANCES        &Language->BigString[Language->StrOffsets[127]]
+
+#define ST_TMENUSTAT0       &Language->BigString[Language->StrOffsets[130]]
+#define ST_TMENUSTAT1       &Language->BigString[Language->StrOffsets[131]]
+#define ST_TMENUSTAT2       &Language->BigString[Language->StrOffsets[132]]
+/* approval ratings */
+#define ST_APPCONSTANT      &Language->BigString[Language->StrOffsets[133]]
+#define ST_APPIMPROVING     &Language->BigString[Language->StrOffsets[134]]
+#define ST_APPIMPROVINGSLIGHT &Language->BigString[Language->StrOffsets[135]]
+#define ST_APPWORSENING     &Language->BigString[Language->StrOffsets[136]]
+#define ST_APPWORSENINGSLIGHT &Language->BigString[Language->StrOffsets[137]]
+#define ST_TMENUSTAT3       &Language->BigString[Language->StrOffsets[138]]
+#define ST_TMENUSTAT4       &Language->BigString[Language->StrOffsets[139]]
+#define ST_TMENUSTAT5       &Language->BigString[Language->StrOffsets[140]]
+#define ST_TMENUSTAT6       &Language->BigString[Language->StrOffsets[141]]
+#define ST_TMENU1           &Language->BigString[Language->StrOffsets[142]]
+#define ST_TMENU2           &Language->BigString[Language->StrOffsets[143]]
+#define ST_TMENU3           &Language->BigString[Language->StrOffsets[144]]
+#define ST_TMENU4           &Language->BigString[Language->StrOffsets[145]]
+#define ST_TMENU5           &Language->BigString[Language->StrOffsets[146]]
+#define ST_TMENU6           &Language->BigString[Language->StrOffsets[147]]
+#define ST_TMENU7           &Language->BigString[Language->StrOffsets[148]]
+#define ST_TMENU10          &Language->BigString[Language->StrOffsets[150]]
+#define ST_TMENU10Q         &Language->BigString[Language->StrOffsets[151]]
+#define ST_TMENU11          &Language->BigString[Language->StrOffsets[152]]
+#define ST_TMENU12          &Language->BigString[Language->StrOffsets[153]]
+#define ST_TMENU13          &Language->BigString[Language->StrOffsets[154]]
+#define ST_TMENU14          &Language->BigString[Language->StrOffsets[155]]
+#define ST_TMENU15Q         &Language->BigString[Language->StrOffsets[156]]
+#define ST_TMENU16          &Language->BigString[Language->StrOffsets[157]]
+#define ST_TMENU17          &Language->BigString[Language->StrOffsets[158]]
+#define ST_TMENU18          &Language->BigString[Language->StrOffsets[159]]
+
+#define ST_T2MENUSTAT0      &Language->BigString[Language->StrOffsets[160]]
+#define ST_T2MENUSTAT1      &Language->BigString[Language->StrOffsets[161]]
+#define ST_T2MENUSTAT2      &Language->BigString[Language->StrOffsets[162]]
+#define ST_T2MENUSTAT3      &Language->BigString[Language->StrOffsets[163]]
+#define ST_T2MENUSTAT4      &Language->BigString[Language->StrOffsets[164]]
+#define ST_T2MENUSTAT5      &Language->BigString[Language->StrOffsets[165]]
+#define ST_T2MENUSTAT6      &Language->BigString[Language->StrOffsets[166]]
+#define ST_T2MENU1Q         &Language->BigString[Language->StrOffsets[167]]
+#define ST_T2MENU1          &Language->BigString[Language->StrOffsets[168]]
+#define ST_T2MENU2          &Language->BigString[Language->StrOffsets[169]]
+#define ST_T2MENU3          &Language->BigString[Language->StrOffsets[170]]
+
+#define ST_EMENU1           &Language->BigString[Language->StrOffsets[171]]
+#define ST_EMENU2           &Language->BigString[Language->StrOffsets[172]]
+#define ST_EMENU3           &Language->BigString[Language->StrOffsets[173]]
+#define ST_EMENU4           &Language->BigString[Language->StrOffsets[174]]
+
+#define ST_CHATADDQ         &Language->BigString[Language->StrOffsets[175]]
+#define ST_CHATENTERCOMMENT &Language->BigString[Language->StrOffsets[176]]
+#define ST_NORULERTOSPEAKOF &Language->BigString[Language->StrOffsets[177]]
+#define ST_SPEAKGOODQ       &Language->BigString[Language->StrOffsets[178]]
+#define ST_SPEAKBADQ        &Language->BigString[Language->StrOffsets[179]]
+#define ST_SPEAKNOEFFECT    &Language->BigString[Language->StrOffsets[180]]
+#define ST_SPEAKRESULT1     &Language->BigString[Language->StrOffsets[181]]
+#define ST_SPEAKRESULT2     &Language->BigString[Language->StrOffsets[182]]
+
+#define ST_EMENU5           &Language->BigString[Language->StrOffsets[185]]
+#define ST_EMENU6           &Language->BigString[Language->StrOffsets[186]]
+#define ST_EMENU7           &Language->BigString[Language->StrOffsets[187]]
+#define ST_EMENU8           &Language->BigString[Language->StrOffsets[188]]
+#define ST_EMENU9           &Language->BigString[Language->StrOffsets[189]]
+#define ST_EMENU10          &Language->BigString[Language->StrOffsets[190]]
+#define ST_EMENU11          &Language->BigString[Language->StrOffsets[191]]
+#define ST_EMENU12          &Language->BigString[Language->StrOffsets[192]]
+#define ST_EMENU13          &Language->BigString[Language->StrOffsets[193]]
+#define ST_EMENU14          &Language->BigString[Language->StrOffsets[194]]
+#define ST_EMENU15          &Language->BigString[Language->StrOffsets[195]]
+#define ST_EMENU16          &Language->BigString[Language->StrOffsets[196]]
+#define ST_EMENU17          &Language->BigString[Language->StrOffsets[197]]
+#define ST_EMENU18          &Language->BigString[Language->StrOffsets[198]]
+
+#define ST_BEFORECHAT       &Language->BigString[Language->StrOffsets[200]]
+#define ST_AFTERCHAT        &Language->BigString[Language->StrOffsets[201]]
+#define ST_4RETURNS         &Language->BigString[Language->StrOffsets[202]]
+
+#define ST_LOCAL1           &Language->BigString[Language->StrOffsets[220]]
+#define ST_LOCAL2           &Language->BigString[Language->StrOffsets[221]]
+#define ST_LOCAL3           &Language->BigString[Language->StrOffsets[222]]
+#define ST_LOCAL4           &Language->BigString[Language->StrOffsets[223]]
+#define ST_LOCAL5           &Language->BigString[Language->StrOffsets[224]]
+#define ST_LOCAL6           &Language->BigString[Language->StrOffsets[225]]
+#define ST_LOCAL7           &Language->BigString[Language->StrOffsets[226]]
+#define ST_LOCAL8           &Language->BigString[Language->StrOffsets[227]]
+#define ST_LOCAL9           &Language->BigString[Language->StrOffsets[228]]
+#define ST_LOCAL10          &Language->BigString[Language->StrOffsets[229]]
+#define ST_LOCAL11          &Language->BigString[Language->StrOffsets[230]]
+
+#define ST_FIGHT0           &Language->BigString[Language->StrOffsets[240]]
+#define ST_FIGHTOVER1       &Language->BigString[Language->StrOffsets[241]]
+#define ST_FIGHTCLANALREADY &Language->BigString[Language->StrOffsets[242]]
+#define ST_FIGHTVSHEADER    &Language->BigString[Language->StrOffsets[243]]
+#define ST_FIGHTPSTATS      &Language->BigString[Language->StrOffsets[244]]
+#define ST_FIGHTOPTIONS     &Language->BigString[Language->StrOffsets[245]]
+#define ST_FIGHTYOURCOLOR   &Language->BigString[Language->StrOffsets[246]]
+#define ST_FIGHTENEMYCOLOR  &Language->BigString[Language->StrOffsets[247]]
+#define ST_FIGHTMISS        &Language->BigString[Language->StrOffsets[248]]
+#define ST_FIGHTITEMDESTROYED &Language->BigString[Language->StrOffsets[249]]
+#define ST_FIGHTATTACK      &Language->BigString[Language->StrOffsets[250]]
+#define ST_FIGHTXP          &Language->BigString[Language->StrOffsets[251]]
+#define ST_FIGHTKILLED      &Language->BigString[Language->StrOffsets[252]]
+#define ST_FIGHTMORTALWOUND &Language->BigString[Language->StrOffsets[253]]
+#define ST_FIGHTKNOCKEDOUT  &Language->BigString[Language->StrOffsets[254]]
+#define ST_FIGHTGETGOLD     &Language->BigString[Language->StrOffsets[255]]
+#define ST_FIGHTTAXEDGOLD   &Language->BigString[Language->StrOffsets[256]]
+#define ST_FIGHTTARGET1     &Language->BigString[Language->StrOffsets[257]]
+#define ST_FIGHTTARGETLIST1 &Language->BigString[Language->StrOffsets[258]]
+#define ST_FIGHTTARGETLIST2 &Language->BigString[Language->StrOffsets[259]]
+#define ST_FIGHTTARGETNOTHERE &Language->BigString[Language->StrOffsets[260]]
+#define ST_FIGHTVICTORY     &Language->BigString[Language->StrOffsets[261]]
+#define ST_FIGHTDEFEAT      &Language->BigString[Language->StrOffsets[262]]
+#define ST_FIGHTRUNAWAY     &Language->BigString[Language->StrOffsets[263]]
+#define ST_FIGHTNORUN       &Language->BigString[Language->StrOffsets[264]]
+#define ST_FIGHTNORUN2      &Language->BigString[Language->StrOffsets[265]]
+
+#define ST_TOWN0            &Language->BigString[Language->StrOffsets[270]]
+#define ST_TOWN1            &Language->BigString[Language->StrOffsets[271]]
+#define ST_TOWN2            &Language->BigString[Language->StrOffsets[272]]
+#define ST_TOWN3            &Language->BigString[Language->StrOffsets[273]]
+#define ST_TOWN4            &Language->BigString[Language->StrOffsets[274]]
+#define ST_TOWN5            &Language->BigString[Language->StrOffsets[275]]
+
+#define ST_CSPELL0          &Language->BigString[Language->StrOffsets[280]]
+#define ST_CSPELL1          &Language->BigString[Language->StrOffsets[281]]
+#define ST_CSPELL2          &Language->BigString[Language->StrOffsets[282]]
+#define ST_CSPELL3          &Language->BigString[Language->StrOffsets[283]]
+#define ST_CSPELL4          &Language->BigString[Language->StrOffsets[284]]
+#define ST_CSPELL5          &Language->BigString[Language->StrOffsets[285]]
+#define ST_SPELLFAIL        &Language->BigString[Language->StrOffsets[286]]
+#define ST_SPELLNOUNDEAD    &Language->BigString[Language->StrOffsets[287]]
+
+#define ST_FORTOP0          &Language->BigString[Language->StrOffsets[300]]
+#define ST_FORTOP1          &Language->BigString[Language->StrOffsets[301]]
+#define ST_FORTOP2          &Language->BigString[Language->StrOffsets[302]]
+#define ST_FORTOP3          &Language->BigString[Language->StrOffsets[303]]
+#define ST_FORTOP4          &Language->BigString[Language->StrOffsets[304]]
+#define ST_FORTOP5          &Language->BigString[Language->StrOffsets[305]]
+#define ST_FORTOP6          &Language->BigString[Language->StrOffsets[306]]
+#define ST_FORTOP7          &Language->BigString[Language->StrOffsets[307]]
+#define ST_FORTOP8          &Language->BigString[Language->StrOffsets[308]]
+#define ST_FORTOP9          &Language->BigString[Language->StrOffsets[309]]
+
+#define ST_BANKOP0          &Language->BigString[Language->StrOffsets[315]]
+#define ST_BANKOP1          &Language->BigString[Language->StrOffsets[316]]
+#define ST_BANKOP2          &Language->BigString[Language->StrOffsets[317]]
+#define ST_BANKOP3          &Language->BigString[Language->StrOffsets[318]]
+#define ST_BANKOP4          &Language->BigString[Language->StrOffsets[319]]
+#define ST_BANKOP5          &Language->BigString[Language->StrOffsets[320]]
+#define ST_BANKOP6          &Language->BigString[Language->StrOffsets[321]]
+#define ST_BANKOP7          &Language->BigString[Language->StrOffsets[322]]
+
+#define ST_REBELOP0         &Language->BigString[Language->StrOffsets[325]]
+#define ST_REBELOP1         &Language->BigString[Language->StrOffsets[326]]
+#define ST_REBELOP2         &Language->BigString[Language->StrOffsets[327]]
+#define ST_REBELOP3         &Language->BigString[Language->StrOffsets[328]]
+#define ST_REBELOP4         &Language->BigString[Language->StrOffsets[329]]
+#define ST_REBELOP5         &Language->BigString[Language->StrOffsets[330]]
+#define ST_REBELOP6         &Language->BigString[Language->StrOffsets[331]]
+#define ST_REBELOP7         &Language->BigString[Language->StrOffsets[332]]
+#define ST_REBELOP8         &Language->BigString[Language->StrOffsets[333]]
+#define ST_REBELOP9         &Language->BigString[Language->StrOffsets[334]]
+
+#define ST_TOWNOP0          &Language->BigString[Language->StrOffsets[335]]
+#define ST_TOWNOP1          &Language->BigString[Language->StrOffsets[336]]
+#define ST_TOWNOP2          &Language->BigString[Language->StrOffsets[337]]
+#define ST_TOWNOP3          &Language->BigString[Language->StrOffsets[338]]
+#define ST_TOWNOP4          &Language->BigString[Language->StrOffsets[339]]
+#define ST_TOWNOP5          &Language->BigString[Language->StrOffsets[340]]
+#define ST_TOWNOP6          &Language->BigString[Language->StrOffsets[341]]
+#define ST_TOWNOP7          &Language->BigString[Language->StrOffsets[342]]
+#define ST_TOWNOP8          &Language->BigString[Language->StrOffsets[343]]
+#define ST_TOWNOP9          &Language->BigString[Language->StrOffsets[344]]
+#define ST_TOWNOP10         &Language->BigString[Language->StrOffsets[345]]
+#define ST_TOWNOP11         &Language->BigString[Language->StrOffsets[346]]
+#define ST_TOWNOP12         &Language->BigString[Language->StrOffsets[347]]
+#define ST_TOWNOP13         &Language->BigString[Language->StrOffsets[348]]
+
+#define ST_BMENUOP0         &Language->BigString[Language->StrOffsets[350]]
+#define ST_BMENUOP1         &Language->BigString[Language->StrOffsets[351]]
+#define ST_BMENUOP2         &Language->BigString[Language->StrOffsets[352]]
+#define ST_BMENUOP3         &Language->BigString[Language->StrOffsets[353]]
+#define ST_BMENUOP4         &Language->BigString[Language->StrOffsets[354]]
+#define ST_BMENUOP5         &Language->BigString[Language->StrOffsets[355]]
+#define ST_BMENUOP6         &Language->BigString[Language->StrOffsets[356]]
+#define ST_BMENUOP7         &Language->BigString[Language->StrOffsets[357]]
+#define ST_BMENUOP8         &Language->BigString[Language->StrOffsets[358]]
+#define ST_BMENUOP9         &Language->BigString[Language->StrOffsets[359]]
+
+#define ST_MTROOPOP0        &Language->BigString[Language->StrOffsets[360]]
+#define ST_MTROOPOP1        &Language->BigString[Language->StrOffsets[361]]
+#define ST_MTROOPOP2        &Language->BigString[Language->StrOffsets[362]]
+#define ST_MTROOPOP3        &Language->BigString[Language->StrOffsets[363]]
+#define ST_MTROOPOP4        &Language->BigString[Language->StrOffsets[364]]
+#define ST_MTROOPOP5        &Language->BigString[Language->StrOffsets[365]]
+#define ST_MTROOPOP6        &Language->BigString[Language->StrOffsets[366]]
+#define ST_MTROOPOP7        &Language->BigString[Language->StrOffsets[367]]
+
+#define ST_RTROOPOP0        &Language->BigString[Language->StrOffsets[370]]
+#define ST_RTROOPOP1        &Language->BigString[Language->StrOffsets[371]]
+#define ST_RTROOPOP2        &Language->BigString[Language->StrOffsets[372]]
+#define ST_RTROOPOP3        &Language->BigString[Language->StrOffsets[373]]
+#define ST_RTROOPOP4        &Language->BigString[Language->StrOffsets[374]]
+#define ST_RTROOPOP5        &Language->BigString[Language->StrOffsets[375]]
+
+#define ST_T2MENUOP0        &Language->BigString[Language->StrOffsets[380]]
+#define ST_T2MENUOP1        &Language->BigString[Language->StrOffsets[381]]
+#define ST_T2MENUOP2        &Language->BigString[Language->StrOffsets[382]]
+#define ST_T2MENUOP3        &Language->BigString[Language->StrOffsets[383]]
+#define ST_T2MENUOP4        &Language->BigString[Language->StrOffsets[384]]
+#define ST_T2MENUOP5        &Language->BigString[Language->StrOffsets[385]]
+#define ST_T2MENUOP6        &Language->BigString[Language->StrOffsets[386]]
+#define ST_T2MENUOP7        &Language->BigString[Language->StrOffsets[387]]
+#define ST_T2MENUOP8        &Language->BigString[Language->StrOffsets[388]]
+
+#define ST_EMENUOP0         &Language->BigString[Language->StrOffsets[390]]
+#define ST_EMENUOP1         &Language->BigString[Language->StrOffsets[391]]
+#define ST_EMENUOP2         &Language->BigString[Language->StrOffsets[392]]
+#define ST_EMENUOP3         &Language->BigString[Language->StrOffsets[393]]
+#define ST_EMENUOP4         &Language->BigString[Language->StrOffsets[394]]
+#define ST_EMENUOP5         &Language->BigString[Language->StrOffsets[395]]
+#define ST_EMENUOP6         &Language->BigString[Language->StrOffsets[396]]
+#define ST_EMENUOP7         &Language->BigString[Language->StrOffsets[397]]
+#define ST_EMENUOP8         &Language->BigString[Language->StrOffsets[398]]
+
+#define ST_VSTATHEADER      &Language->BigString[Language->StrOffsets[400]]
+#define ST_VSTATS1          &Language->BigString[Language->StrOffsets[401]]
+#define ST_VSTATS2          &Language->BigString[Language->StrOffsets[402]]
+#define ST_VSTATS3          &Language->BigString[Language->StrOffsets[403]]
+#define ST_VSTATS4          &Language->BigString[Language->StrOffsets[404]]
+#define ST_VSTATS5          &Language->BigString[Language->StrOffsets[405]]
+#define ST_VSTATS6          &Language->BigString[Language->StrOffsets[406]]
+#define ST_VSTATS7          &Language->BigString[Language->StrOffsets[407]]
+#define ST_VSTATS8          &Language->BigString[Language->StrOffsets[408]]
+#define ST_VSTATS9          &Language->BigString[Language->StrOffsets[409]]
+#define ST_VSTATS10         &Language->BigString[Language->StrOffsets[410]]
+#define ST_VSTATS11         &Language->BigString[Language->StrOffsets[411]]
+#define ST_VSTATS12         &Language->BigString[Language->StrOffsets[412]]
+#define ST_VSTATS13         &Language->BigString[Language->StrOffsets[413]]
+
+#define ST_FORTNOBUILT      &Language->BigString[Language->StrOffsets[420]]
+#define ST_FORTOPTION1      &Language->BigString[Language->StrOffsets[421]]
+#define ST_FORTOPTION2      &Language->BigString[Language->StrOffsets[422]]
+#define ST_FORTOPTION3      &Language->BigString[Language->StrOffsets[423]]
+#define ST_FORTOPTION4      &Language->BigString[Language->StrOffsets[424]]
+#define ST_FORTOPTION5      &Language->BigString[Language->StrOffsets[425]]
+#define ST_FORTOPTION6      &Language->BigString[Language->StrOffsets[426]]
+#define ST_FORTOPTION7      &Language->BigString[Language->StrOffsets[427]]
+#define ST_FORTOPTION8      &Language->BigString[Language->StrOffsets[428]]
+#define ST_FORTOPTION9      &Language->BigString[Language->StrOffsets[429]]
+#define ST_FMENUTITLE       &Language->BigString[Language->StrOffsets[430]]
+#define ST_FMENUTITLE2      &Language->BigString[Language->StrOffsets[431]]
+#define ST_FMENUTITLE3      &Language->BigString[Language->StrOffsets[432]]
+#define ST_FMENUHAVELAND    &Language->BigString[Language->StrOffsets[433]]
+#define ST_FMENUBUYLAND     &Language->BigString[Language->StrOffsets[434]]
+#define ST_FMENUNOAFFORD    &Language->BigString[Language->StrOffsets[435]]
+#define ST_FMENUBUYLANDQ    &Language->BigString[Language->StrOffsets[436]]
+#define ST_FMENUBOUGHTLAND  &Language->BigString[Language->StrOffsets[437]]
+#define ST_FMENUNOLAND      &Language->BigString[Language->StrOffsets[438]]
+#define ST_FMENUHAVEFORT    &Language->BigString[Language->StrOffsets[439]]
+#define ST_FMENUBUILDFORT   &Language->BigString[Language->StrOffsets[440]]
+#define ST_FMENUBUILDFORTQ  &Language->BigString[Language->StrOffsets[441]]
+#define ST_FMENUBUILTFORT   &Language->BigString[Language->StrOffsets[442]]
+#define ST_FMENUNOFORTTOUP  &Language->BigString[Language->StrOffsets[443]]
+#define ST_FMENUFORTDAMAGED &Language->BigString[Language->StrOffsets[444]]
+#define ST_FMENUFORTUPCOST  &Language->BigString[Language->StrOffsets[445]]
+#define ST_FMENUUPKEEPQ     &Language->BigString[Language->StrOffsets[446]]
+#define ST_FMENUUPKEEPDONE  &Language->BigString[Language->StrOffsets[447]]
+#define ST_FMENUUPCASTLE    &Language->BigString[Language->StrOffsets[448]]
+#define ST_FMENUUPCASTLEQ   &Language->BigString[Language->StrOffsets[449]]
+
+#define ST_PSTATS0          &Language->BigString[Language->StrOffsets[450]]
+#define ST_PSTATS1          &Language->BigString[Language->StrOffsets[451]]
+#define ST_PSTATS2          &Language->BigString[Language->StrOffsets[452]]
+#define ST_PSTATS3          &Language->BigString[Language->StrOffsets[453]]
+#define ST_PSTATS4          &Language->BigString[Language->StrOffsets[454]]
+#define ST_PSTATS5          &Language->BigString[Language->StrOffsets[455]]
+#define ST_PSTATS6          &Language->BigString[Language->StrOffsets[456]]
+#define ST_PSTATS7          &Language->BigString[Language->StrOffsets[457]]
+#define ST_PSTATS8          &Language->BigString[Language->StrOffsets[458]]
+#define ST_PSTATS9          &Language->BigString[Language->StrOffsets[459]]
+#define ST_PSTATS10         &Language->BigString[Language->StrOffsets[460]]
+#define ST_PSTATS11         &Language->BigString[Language->StrOffsets[461]]
+#define ST_PSTATS12         &Language->BigString[Language->StrOffsets[462]]
+#define ST_PSTATS13         &Language->BigString[Language->StrOffsets[463]]
+#define ST_PSTATS14         &Language->BigString[Language->StrOffsets[464]]
+#define ST_PSTATS15         &Language->BigString[Language->StrOffsets[465]]
+#define ST_PSTATS16         &Language->BigString[Language->StrOffsets[466]]
+#define ST_PSTATS17         &Language->BigString[Language->StrOffsets[467]]
+#define ST_ISTATS0          &Language->BigString[Language->StrOffsets[468]]
+#define ST_ISTATS1          &Language->BigString[Language->StrOffsets[469]]
+#define ST_ISTATS2          &Language->BigString[Language->StrOffsets[470]]
+#define ST_ISTATS3          &Language->BigString[Language->StrOffsets[471]]
+#define ST_ISTATS4          &Language->BigString[Language->StrOffsets[472]]
+#define ST_ISTATS5          &Language->BigString[Language->StrOffsets[473]]
+#define ST_ISTATS6          &Language->BigString[Language->StrOffsets[474]]
+#define ST_ISTATS7          &Language->BigString[Language->StrOffsets[475]]
+#define ST_ISTATS8          &Language->BigString[Language->StrOffsets[476]]
+#define ST_ISTATS9          &Language->BigString[Language->StrOffsets[477]]
+#define ST_ISTATS10         &Language->BigString[Language->StrOffsets[478]]
+#define ST_ISTATS11         &Language->BigString[Language->StrOffsets[479]]
+
+#define ST_SCOREHEADER      &Language->BigString[Language->StrOffsets[480]]
+#define ST_SCORELINE        &Language->BigString[Language->StrOffsets[481]]
+
+#define ST_CSTATS0          &Language->BigString[Language->StrOffsets[490]]
+#define ST_CSTATS1          &Language->BigString[Language->StrOffsets[491]]
+#define ST_CSTATS2          &Language->BigString[Language->StrOffsets[492]]
+#define ST_CSTATS3          &Language->BigString[Language->StrOffsets[493]]
+#define ST_CSTATS4          &Language->BigString[Language->StrOffsets[494]]
+#define ST_CSTATS5          &Language->BigString[Language->StrOffsets[495]]
+
+#define ST_EMENU26          &Language->BigString[Language->StrOffsets[520]]
+#define ST_EMENU27          &Language->BigString[Language->StrOffsets[521]]
+#define ST_EMENU28          &Language->BigString[Language->StrOffsets[522]]
+#define ST_EMENU29          &Language->BigString[Language->StrOffsets[523]]
+#define ST_EMENU30          &Language->BigString[Language->StrOffsets[524]]
+
+#define ST_ISTATS12         &Language->BigString[Language->StrOffsets[530]]
+#define ST_ISTATS13         &Language->BigString[Language->StrOffsets[531]]
+#define ST_ISTATS14         &Language->BigString[Language->StrOffsets[532]]
+#define ST_ISTATS15         &Language->BigString[Language->StrOffsets[533]]
+#define ST_ISTATS16         &Language->BigString[Language->StrOffsets[534]]
+#define ST_ISTATS17         &Language->BigString[Language->StrOffsets[535]]
+#define ST_ISTATS18         &Language->BigString[Language->StrOffsets[536]]
+#define ST_ISTATS19         &Language->BigString[Language->StrOffsets[537]]
+#define ST_ISTATS20         &Language->BigString[Language->StrOffsets[538]]
+#define ST_ISTATS21         &Language->BigString[Language->StrOffsets[539]]
+#define ST_ISTATS22         &Language->BigString[Language->StrOffsets[540]]
+#define ST_ISTATS23         &Language->BigString[Language->StrOffsets[541]]
+#define ST_ISTATS24         &Language->BigString[Language->StrOffsets[542]]
+#define ST_ISTATS25         &Language->BigString[Language->StrOffsets[543]]
+#define ST_ISTATS26         &Language->BigString[Language->StrOffsets[544]]
+#define ST_ISTATS27         &Language->BigString[Language->StrOffsets[545]]
+#define ST_ISTATS28         &Language->BigString[Language->StrOffsets[546]]
+#define ST_ISTATS29         &Language->BigString[Language->StrOffsets[547]]
+#define ST_ISTATS30         &Language->BigString[Language->StrOffsets[548]]
+
+#define ST_FMENUUPCASTLEDONE &Language->BigString[Language->StrOffsets[550]]
+#define ST_FMENUNOMOREUP     &Language->BigString[Language->StrOffsets[551]]
+#define ST_FMENUNOFORTREPAIR &Language->BigString[Language->StrOffsets[552]]
+#define ST_FMENUFORTNODAMAGE &Language->BigString[Language->StrOffsets[553]]
+#define ST_FMENUFORTREPAIRCOST &Language->BigString[Language->StrOffsets[554]]
+#define ST_FMENUFORTREPAIRGOLD &Language->BigString[Language->StrOffsets[555]]
+#define ST_FMENUFORTREPAIRPAY &Language->BigString[Language->StrOffsets[556]]
+#define ST_FMENUFORTNOREPAIR &Language->BigString[Language->StrOffsets[557]]
+#define ST_FMENUFORTREPAIRDONE &Language->BigString[Language->StrOffsets[558]]
+#define ST_FMENUTROOPSNOFORT &Language->BigString[Language->StrOffsets[559]]
+#define ST_FMENUATTACKNOFORT &Language->BigString[Language->StrOffsets[560]]
+#define ST_FMENUSTUFF1      &Language->BigString[Language->StrOffsets[561]]
+#define ST_FORTTITLE        &Language->BigString[Language->StrOffsets[562]]
+#define ST_FMENUSTUFF2      &Language->BigString[Language->StrOffsets[563]]
+
+
+#define ST_MTROOPHEADER     &Language->BigString[Language->StrOffsets[570]]
+#define ST_MTROOPCOST1      &Language->BigString[Language->StrOffsets[571]]
+#define ST_MTROOPCOST2      &Language->BigString[Language->StrOffsets[572]]
+#define ST_MTROOPCOST3      &Language->BigString[Language->StrOffsets[573]]
+#define ST_MTROOPCOST4      &Language->BigString[Language->StrOffsets[574]]
+#define ST_MMENURESERVETROOPS &Language->BigString[Language->StrOffsets[575]]
+#define ST_MMENURETURN      &Language->BigString[Language->StrOffsets[576]]
+#define ST_MMENUTROOPSTATUS &Language->BigString[Language->StrOffsets[577]]
+#define ST_MMENUTRAIN1      &Language->BigString[Language->StrOffsets[578]]
+#define ST_MMENUTRAIN2      &Language->BigString[Language->StrOffsets[579]]
+#define ST_MMENUTRAIN3      &Language->BigString[Language->StrOffsets[580]]
+#define ST_MMENUTRAIN4      &Language->BigString[Language->StrOffsets[581]]
+#define ST_MMENUNEEDFORKNIGHT &Language->BigString[Language->StrOffsets[582]]
+#define ST_MMENUTRAIN5      &Language->BigString[Language->StrOffsets[583]]
+#define ST_MMENUTRAIN6      &Language->BigString[Language->StrOffsets[584]]
+#define ST_MMENUNEEDFORCATA &Language->BigString[Language->StrOffsets[585]]
+#define ST_MMENUTRAIN7      &Language->BigString[Language->StrOffsets[586]]
+#define ST_MMENUTRAIN8      &Language->BigString[Language->StrOffsets[587]]
+
+#define ST_WEAPONSAVAILABLE &Language->BigString[Language->StrOffsets[600]]
+#define ST_ARMORAVAILABLE   &Language->BigString[Language->StrOffsets[601]]
+#define ST_SHIELDSAVAILABLE &Language->BigString[Language->StrOffsets[602]]
+#define ST_ITEMHEADER       &Language->BigString[Language->StrOffsets[603]]
+#define ST_ITEMLINE         &Language->BigString[Language->StrOffsets[604]]
+#define ST_ITEMOPTIONS      &Language->BigString[Language->StrOffsets[605]]
+#define ST_ITEMPROMPT       &Language->BigString[Language->StrOffsets[606]]
+#define ST_ITEMHELPTITLE    &Language->BigString[Language->StrOffsets[607]]
+#define ST_ITEMABORTED      &Language->BigString[Language->StrOffsets[608]]
+#define ST_ITEMCOSTIS       &Language->BigString[Language->StrOffsets[609]]
+#define ST_ITEMBUYTHIS      &Language->BigString[Language->StrOffsets[610]]
+#define ST_ITEMNOMOREROOM   &Language->BigString[Language->StrOffsets[611]]
+#define ST_ITEMNOAFFORD     &Language->BigString[Language->StrOffsets[612]]
+#define ST_ITEMMATERIALS    &Language->BigString[Language->StrOffsets[613]]
+#define ST_ITEMCHOOSEONE    &Language->BigString[Language->StrOffsets[614]]
+
+#define ST_GETCLASS0        &Language->BigString[Language->StrOffsets[650]]
+#define ST_GETCLASS1        &Language->BigString[Language->StrOffsets[651]]
+#define ST_GETCLASS2        &Language->BigString[Language->StrOffsets[652]]
+#define ST_CHOOSECLASS      &Language->BigString[Language->StrOffsets[653]]
+
+#define ST_THALLOP0         &Language->BigString[Language->StrOffsets[655]]
+#define ST_THALLOP1         &Language->BigString[Language->StrOffsets[656]]
+#define ST_THALLOP2         &Language->BigString[Language->StrOffsets[657]]
+#define ST_THALLOP3         &Language->BigString[Language->StrOffsets[658]]
+#define ST_THALLOP4         &Language->BigString[Language->StrOffsets[659]]
+#define ST_THALLOP5         &Language->BigString[Language->StrOffsets[660]]
+
+#define ST_SCHEMETITLE      &Language->BigString[Language->StrOffsets[670]]
+#define ST_SCHEME1          &Language->BigString[Language->StrOffsets[671]]
+#define ST_SCHEME2          &Language->BigString[Language->StrOffsets[672]]
+#define ST_SCHEME3          &Language->BigString[Language->StrOffsets[673]]
+#define ST_SCHEME4          &Language->BigString[Language->StrOffsets[674]]
+#define ST_SCHEME5          &Language->BigString[Language->StrOffsets[675]]
+#define ST_SCHEME6          &Language->BigString[Language->StrOffsets[676]]
+#define ST_SCHEME7          &Language->BigString[Language->StrOffsets[677]]
+#define ST_SCHEME8          &Language->BigString[Language->StrOffsets[678]]
+#define ST_SCHEME9          &Language->BigString[Language->StrOffsets[679]]
+#define ST_SCHEME10         &Language->BigString[Language->StrOffsets[680]]
+#define ST_SCHEMEMENU1      &Language->BigString[Language->StrOffsets[685]]
+#define ST_SCHEMEMENU2      &Language->BigString[Language->StrOffsets[686]]
+#define ST_SCHEMEMENU3      &Language->BigString[Language->StrOffsets[687]]
+#define ST_SCHEMEMENU4      &Language->BigString[Language->StrOffsets[688]]
+#define ST_SCHEMEMENU5      &Language->BigString[Language->StrOffsets[689]]
+#define ST_SCHEMEMENU6      &Language->BigString[Language->StrOffsets[690]]
+#define ST_SCHEMEMENU7      &Language->BigString[Language->StrOffsets[691]]
+#define ST_SCHEMEMENU8      &Language->BigString[Language->StrOffsets[692]]
+#define ST_SCHEMEMENU9      &Language->BigString[Language->StrOffsets[693]]
+
+#define ST_MAILHEADER       &Language->BigString[Language->StrOffsets[700]]
+#define ST_MAILENTERCOLOR   &Language->BigString[Language->StrOffsets[701]]
+#define ST_MAILNOTEXT       &Language->BigString[Language->StrOffsets[702]]
+#define ST_MAILSAVED        &Language->BigString[Language->StrOffsets[703]]
+#define ST_MAILABORTED      &Language->BigString[Language->StrOffsets[704]]
+#define ST_MAILSTARTOVER    &Language->BigString[Language->StrOffsets[705]]
+#define ST_MAILNOTEXTYET    &Language->BigString[Language->StrOffsets[706]]
+#define ST_MAILLIST         &Language->BigString[Language->StrOffsets[707]]
+#define ST_MAIL40LINES      &Language->BigString[Language->StrOffsets[708]]
+
+#define ST_RMAILCHECKING    &Language->BigString[Language->StrOffsets[720]]
+#define ST_RMAILHEADER1     &Language->BigString[Language->StrOffsets[721]]
+#define ST_RMAILHEADER2     &Language->BigString[Language->StrOffsets[722]]
+#define ST_RMAILPUBLICPOST  &Language->BigString[Language->StrOffsets[723]]
+#define ST_RMAILSUBJALLY    &Language->BigString[Language->StrOffsets[724]]
+#define ST_RETURNSPACES     &Language->BigString[Language->StrOffsets[725]]
+#define ST_RMAILCOLOR       &Language->BigString[Language->StrOffsets[726]]
+#define ST_RMAILALLYQ       &Language->BigString[Language->StrOffsets[727]]
+#define ST_RMAILREPLYQ      &Language->BigString[Language->StrOffsets[728]]
+#define ST_RMAILREJECTALLY  &Language->BigString[Language->StrOffsets[729]]
+#define ST_RMAILAGREEALLY   &Language->BigString[Language->StrOffsets[730]]
+#define ST_RMAILFOOTER1     &Language->BigString[Language->StrOffsets[731]]
+#define ST_RMAILFOOTER2     &Language->BigString[Language->StrOffsets[732]]
+#define ST_RMAILREPLY       &Language->BigString[Language->StrOffsets[733]]
+#define ST_RMAILDELETEQ     &Language->BigString[Language->StrOffsets[734]]
+#define ST_RMAILDELETE      &Language->BigString[Language->StrOffsets[735]]
+#define ST_RMAILDELETING    &Language->BigString[Language->StrOffsets[736]]
+#define ST_RMAILSKIP        &Language->BigString[Language->StrOffsets[737]]
+#define ST_RMAILQUIT        &Language->BigString[Language->StrOffsets[738]]
+
+#define ST_INPUTSTRCOMMAND  &Language->BigString[Language->StrOffsets[740]]
+#define ST_INPUTSTRHELP     &Language->BigString[Language->StrOffsets[741]]
+#define ST_LONGSPACES       &Language->BigString[Language->StrOffsets[742]]
+#define ST_INPUTSTRSTARTOVER &Language->BigString[Language->StrOffsets[743]]
+#define ST_INPUTSTRSAVE     &Language->BigString[Language->StrOffsets[744]]
+#define ST_INPUTSTRABORT    &Language->BigString[Language->StrOffsets[745]]
+
+#define ST_RMAILQUOTE       &Language->BigString[Language->StrOffsets[750]]
+#define ST_RMAILQFIRSTLINE  &Language->BigString[Language->StrOffsets[751]]
+#define ST_RMAILQUOTEALL    &Language->BigString[Language->StrOffsets[752]]
+#define ST_RMAILLASTLINE    &Language->BigString[Language->StrOffsets[753]]
+#define ST_RMAILQUOTEBRACKET &Language->BigString[Language->StrOffsets[754]]
+#define ST_RMAILHEADER      &Language->BigString[Language->StrOffsets[755]]
+#define ST_MAILPUBLICQ      &Language->BigString[Language->StrOffsets[756]]
+#define ST_INPUTSTRHELP2    &Language->BigString[Language->StrOffsets[757]]
+#define ST_RMAILQUOTELIST   &Language->BigString[Language->StrOffsets[758]]
+#define ST_RMAILQUOTECHOOSE &Language->BigString[Language->StrOffsets[759]]
+
+#define ST_NEWSNEWCLAN      &Language->BigString[Language->StrOffsets[800]]
+#define ST_NEWSFOR          &Language->BigString[Language->StrOffsets[801]]
+#define ST_NEWSNEWRULER     &Language->BigString[Language->StrOffsets[802]]
+#define ST_NEWSNEWBANK      &Language->BigString[Language->StrOffsets[803]]
+#define ST_NEWSUPGRADEBANK  &Language->BigString[Language->StrOffsets[804]]
+#define ST_NEWSRULERSPEECH  &Language->BigString[Language->StrOffsets[805]]
+#define ST_NEWSNEWFLAG      &Language->BigString[Language->StrOffsets[806]]
+#define ST_NEWSNEWCHURCH    &Language->BigString[Language->StrOffsets[807]]
+#define ST_NEWSUPGRADECHURCH &Language->BigString[Language->StrOffsets[808]]
+#define ST_NEWSNEWTHALL     &Language->BigString[Language->StrOffsets[809]]
+#define ST_NEWSUPGRADETHALL &Language->BigString[Language->StrOffsets[810]]
+#define ST_NEWSABDICATED    &Language->BigString[Language->StrOffsets[811]]
+#define ST_NEWSSPEAKMSG     &Language->BigString[Language->StrOffsets[813]]
+#define ST_NEWSEMBEZZLE     &Language->BigString[Language->StrOffsets[815]]
+#define ST_NEWSTAX1         &Language->BigString[Language->StrOffsets[816]]
+#define ST_NEWSTAX2         &Language->BigString[Language->StrOffsets[817]]
+#define ST_NEWSTAX3         &Language->BigString[Language->StrOffsets[818]]
+#define ST_NEWSFIGHT1       &Language->BigString[Language->StrOffsets[819]]
+#define ST_NEWSFIGHT2       &Language->BigString[Language->StrOffsets[820]]
+#define ST_NEWSFIGHT3       &Language->BigString[Language->StrOffsets[821]]
+#define ST_NEWSFIGHT4       &Language->BigString[Language->StrOffsets[822]]
+#define ST_NEWSSMITHY       &Language->BigString[Language->StrOffsets[823]]
+#define ST_NEWSLOCALRESET   &Language->BigString[Language->StrOffsets[829]]
+#define ST_NEWSWAITRESET    &Language->BigString[Language->StrOffsets[830]]
+#define ST_NEWSLCRESET      &Language->BigString[Language->StrOffsets[831]]
+#define ST_NEWSJOINIBBS     &Language->BigString[Language->StrOffsets[832]]
+#define ST_NEWSCLANENTER    &Language->BigString[Language->StrOffsets[833]]
+#define ST_NEWSCLANEXIT     &Language->BigString[Language->StrOffsets[834]]
+#define ST_USERLISTH        &Language->BigString[Language->StrOffsets[835]]
+#define ST_NEWSNEWTOWN      &Language->BigString[Language->StrOffsets[836]]
+#define ST_NEWSDONATED      &Language->BigString[Language->StrOffsets[837]]
+#define ST_OUTBOUNDFILE     &Language->BigString[Language->StrOffsets[838]]
+#define ST_TOOMANYMEMBERS   &Language->BigString[Language->StrOffsets[839]]
+#define ST_REMOVEMEM        &Language->BigString[Language->StrOffsets[840]]
+#define ST_REMOVED          &Language->BigString[Language->StrOffsets[841]]
+#define ST_NEWSFIGHT5       &Language->BigString[Language->StrOffsets[842]]
+#define ST_NEWSFIGHT6       &Language->BigString[Language->StrOffsets[843]]
+
+#define ST_MAIN0            &Language->BigString[Language->StrOffsets[880]]
+#define ST_MAIN1            &Language->BigString[Language->StrOffsets[881]]
+#define ST_MAIN2            &Language->BigString[Language->StrOffsets[882]]
+#define ST_MAIN3            &Language->BigString[Language->StrOffsets[883]]
+#define ST_MAIN4            &Language->BigString[Language->StrOffsets[884]]
+#define ST_MAIN5            &Language->BigString[Language->StrOffsets[885]]
+#define ST_MAIN6            &Language->BigString[Language->StrOffsets[886]]
+#define ST_NODOORFILE       &Language->BigString[Language->StrOffsets[887]]
+
+#define ST_CHURCHOP0        &Language->BigString[Language->StrOffsets[890]]
+#define ST_CHURCHOP1        &Language->BigString[Language->StrOffsets[891]]
+#define ST_CHURCHOP2        &Language->BigString[Language->StrOffsets[892]]
+#define ST_CHURCHOP3        &Language->BigString[Language->StrOffsets[893]]
+#define ST_CHURCHOP4        &Language->BigString[Language->StrOffsets[894]]
+#define ST_CHURCHOP5        &Language->BigString[Language->StrOffsets[895]]
+#define ST_CHURCHOP6        &Language->BigString[Language->StrOffsets[896]]
+#define ST_CHURCHOP7        &Language->BigString[Language->StrOffsets[897]]
+#define ST_CHURCHOP8        &Language->BigString[Language->StrOffsets[898]]
+#define ST_CHURCHOP9        &Language->BigString[Language->StrOffsets[899]]
+
+
+#define ST_ERRORVILLAGEDAT  &Language->BigString[Language->StrOffsets[900]]
+#define ST_ERRORPC          &Language->BigString[Language->StrOffsets[901]]
+#define ST_CLANSPCFILE      &Language->BigString[Language->StrOffsets[902]]
+#define ST_VILLAGEDATFILE   &Language->BigString[Language->StrOffsets[903]]
+#define ST_MSJFILE          &Language->BigString[Language->StrOffsets[904]]
+#define ST_NOMSJFILE        &Language->BigString[Language->StrOffsets[905]]
+#define ST_RULERHLP         &Language->BigString[Language->StrOffsets[906]]
+#define ST_NEWBIEHLP        &Language->BigString[Language->StrOffsets[907]]
+#define ST_CLANSHLP         &Language->BigString[Language->StrOffsets[908]]
+#define ST_INTERBBSONLY     &Language->BigString[Language->StrOffsets[909]]
+#define ST_GAMENOSTART      &Language->BigString[Language->StrOffsets[910]]
+#define ST_GAMEBEGINS       &Language->BigString[Language->StrOffsets[911]]
+#define ST_SCORE0ASCII      &Language->BigString[Language->StrOffsets[912]]
+#define ST_SCORE0ANSI       &Language->BigString[Language->StrOffsets[913]]
+#define ST_SCORE1ASCII      &Language->BigString[Language->StrOffsets[914]]
+#define ST_SCORE1ANSI       &Language->BigString[Language->StrOffsets[915]]
+#define ST_SCORE2ASCII      &Language->BigString[Language->StrOffsets[916]]
+#define ST_SCORE3ASCII      &Language->BigString[Language->StrOffsets[917]]
+#define ST_SCORE4ASCII      &Language->BigString[Language->StrOffsets[918]]
+#define ST_SCORE5ASCII      &Language->BigString[Language->StrOffsets[919]]
+#define ST_SCORE2ANSI       &Language->BigString[Language->StrOffsets[920]]
+#define ST_SCORE3ANSI       &Language->BigString[Language->StrOffsets[921]]
+#define ST_SCORE4ANSI       &Language->BigString[Language->StrOffsets[922]]
+#define ST_SCORE5ANSI       &Language->BigString[Language->StrOffsets[923]]
+#define ST_LEVELUP          &Language->BigString[Language->StrOffsets[924]]
+#define ST_SCORE6ASCII      &Language->BigString[Language->StrOffsets[925]]
+#define ST_SCORE6ANSI       &Language->BigString[Language->StrOffsets[926]]
+#define ST_NEWPCFILE        &Language->BigString[Language->StrOffsets[927]]
+#define ST_USERONLINE       &Language->BigString[Language->StrOffsets[928]]
+#define ST_NOWORLDNDX       &Language->BigString[Language->StrOffsets[929]]
+
+
+#define ST_MINEOP0          &Language->BigString[Language->StrOffsets[930]]
+#define ST_MINEOP1          &Language->BigString[Language->StrOffsets[931]]
+#define ST_MINEOP2          &Language->BigString[Language->StrOffsets[932]]
+#define ST_MINEOP3          &Language->BigString[Language->StrOffsets[933]]
+#define ST_MINEOP4          &Language->BigString[Language->StrOffsets[934]]
+#define ST_MINEOP5          &Language->BigString[Language->StrOffsets[935]]
+#define ST_MINEOP6          &Language->BigString[Language->StrOffsets[936]]
+#define ST_MINEOP7          &Language->BigString[Language->StrOffsets[937]]
+#define ST_MINEOP8          &Language->BigString[Language->StrOffsets[938]]
+#define ST_MINEOP9          &Language->BigString[Language->StrOffsets[939]]
+
+#define ST_REGMSG0          &Language->BigString[Language->StrOffsets[940]]
+#define ST_REGMSG1          &Language->BigString[Language->StrOffsets[941]]
+#define ST_REGMSG2          &Language->BigString[Language->StrOffsets[942]]
+#define ST_REGMSG3          &Language->BigString[Language->StrOffsets[943]]
+#define ST_REGMSG4          &Language->BigString[Language->StrOffsets[944]]
+#define ST_REGMSG5          &Language->BigString[Language->StrOffsets[945]]
+#define ST_REGMSG6          &Language->BigString[Language->StrOffsets[946]]
+#define ST_REGMSG7          &Language->BigString[Language->StrOffsets[947]]
+#define ST_HELPPARM         &Language->BigString[Language->StrOffsets[948]]
+#define ST_NEEDREGISTER     &Language->BigString[Language->StrOffsets[949]]
+
+#define ST_MAINOP0          &Language->BigString[Language->StrOffsets[950]]
+#define ST_MAINOP1          &Language->BigString[Language->StrOffsets[951]]
+#define ST_MAINOP2          &Language->BigString[Language->StrOffsets[952]]
+#define ST_MAINOP3          &Language->BigString[Language->StrOffsets[953]]
+#define ST_MAINOP4          &Language->BigString[Language->StrOffsets[954]]
+#define ST_MAINOP5          &Language->BigString[Language->StrOffsets[955]]
+#define ST_MAINOP6          &Language->BigString[Language->StrOffsets[956]]
+#define ST_MAINOP7          &Language->BigString[Language->StrOffsets[957]]
+#define ST_MAINOP8          &Language->BigString[Language->StrOffsets[958]]
+#define ST_MAINOP9          &Language->BigString[Language->StrOffsets[959]]
+#define ST_MAINOP10         &Language->BigString[Language->StrOffsets[960]]
+#define ST_MAINOP10         &Language->BigString[Language->StrOffsets[960]]
+
+#define ST_ADVERT1          &Language->BigString[Language->StrOffsets[962]]
+#define ST_ADVERT2          &Language->BigString[Language->StrOffsets[963]]
+#define ST_ADVERT3          &Language->BigString[Language->StrOffsets[964]]
+#define ST_ADVERT4          &Language->BigString[Language->StrOffsets[965]]
+#define ST_ADVERT5          &Language->BigString[Language->StrOffsets[966]]
+#define ST_ADVERT6          &Language->BigString[Language->StrOffsets[967]]
+#define ST_ADVERT7          &Language->BigString[Language->StrOffsets[968]]
+
+#define ST_STREETOP0        &Language->BigString[Language->StrOffsets[970]]
+#define ST_STREETOP1        &Language->BigString[Language->StrOffsets[971]]
+#define ST_STREETOP2        &Language->BigString[Language->StrOffsets[972]]
+#define ST_STREETOP3        &Language->BigString[Language->StrOffsets[973]]
+#define ST_STREETOP4        &Language->BigString[Language->StrOffsets[974]]
+#define ST_STREETOP5        &Language->BigString[Language->StrOffsets[975]]
+#define ST_STREETOP6        &Language->BigString[Language->StrOffsets[976]]
+#define ST_STREETOP7        &Language->BigString[Language->StrOffsets[977]]
+#define ST_STREETOP8        &Language->BigString[Language->StrOffsets[978]]
+#define ST_STREETOP9        &Language->BigString[Language->StrOffsets[979]]
+#define ST_STREETOP10       &Language->BigString[Language->StrOffsets[980]]
+#define ST_STREETOP11       &Language->BigString[Language->StrOffsets[981]]
+#define ST_STREETOP12       &Language->BigString[Language->StrOffsets[982]]
+#define ST_CHATVILLAGERS    &Language->BigString[Language->StrOffsets[983]]
+#define ST_STREETOP14       &Language->BigString[Language->StrOffsets[984]]
+#define ST_STREETOP15       &Language->BigString[Language->StrOffsets[985]]
+#define ST_STREETOP16       &Language->BigString[Language->StrOffsets[986]]
+#define ST_STREETOP17       &Language->BigString[Language->StrOffsets[987]]
+#define ST_STREETOP18       &Language->BigString[Language->StrOffsets[988]]
+#define ST_STREETOP19       &Language->BigString[Language->StrOffsets[989]]
+
+#define ST_WORLDOP0         &Language->BigString[Language->StrOffsets[990]]
+#define ST_WORLDOP1         &Language->BigString[Language->StrOffsets[991]]
+#define ST_WORLDOP2         &Language->BigString[Language->StrOffsets[992]]
+#define ST_WORLDOP3         &Language->BigString[Language->StrOffsets[993]]
+#define ST_WORLDOP4         &Language->BigString[Language->StrOffsets[994]]
+#define ST_WORLDOP5         &Language->BigString[Language->StrOffsets[995]]
+#define ST_WORLDOP6         &Language->BigString[Language->StrOffsets[996]]
+
+#define ST_AMENU0           &Language->BigString[Language->StrOffsets[1020]]
+#define ST_AMENU1           &Language->BigString[Language->StrOffsets[1021]]
+#define ST_AMENU2           &Language->BigString[Language->StrOffsets[1022]]
+#define ST_MAKEALLIANCEQ    &Language->BigString[Language->StrOffsets[1023]]
+#define ST_CANTBUILD        &Language->BigString[Language->StrOffsets[1024]]
+#define ST_HALLPWORD        &Language->BigString[Language->StrOffsets[1025]]
+#define ST_HALLWRONGPWORD   &Language->BigString[Language->StrOffsets[1026]]
+#define ST_CREATEALLIANCE   &Language->BigString[Language->StrOffsets[1027]]
+#define ST_HALL3            &Language->BigString[Language->StrOffsets[1028]]
+#define ST_AMENU4           &Language->BigString[Language->StrOffsets[1029]]
+#define ST_HALL5            &Language->BigString[Language->StrOffsets[1030]]
+#define ST_HALL6            &Language->BigString[Language->StrOffsets[1031]]
+#define ST_HALL7            &Language->BigString[Language->StrOffsets[1032]]
+#define ST_HALL8            &Language->BigString[Language->StrOffsets[1033]]
+#define ST_HALL9            &Language->BigString[Language->StrOffsets[1034]]
+#define ST_HALL10           &Language->BigString[Language->StrOffsets[1035]]
+#define ST_HALL11           &Language->BigString[Language->StrOffsets[1036]]
+#define ST_HALL12           &Language->BigString[Language->StrOffsets[1037]]
+#define ST_HALL13           &Language->BigString[Language->StrOffsets[1038]]
+
+#define ST_ITEMROOM0        &Language->BigString[Language->StrOffsets[1091]]
+
+#define ST_MENUSHLP         &Language->BigString[Language->StrOffsets[1150]]
+#define ST_RACESHLP         &Language->BigString[Language->StrOffsets[1151]]
+#define ST_VILLHLP          &Language->BigString[Language->StrOffsets[1152]]
+#define ST_ITEMHLP          &Language->BigString[Language->StrOffsets[1153]]
+#define ST_BULLHLP          &Language->BigString[Language->StrOffsets[1154]]
+#define ST_FORTHLP          &Language->BigString[Language->StrOffsets[1155]]
+#define ST_COMBATHLP        &Language->BigString[Language->StrOffsets[1156]]
+#define ST_STATSHLP         &Language->BigString[Language->StrOffsets[1157]]
+#define ST_STRATHLP         &Language->BigString[Language->StrOffsets[1158]]
+#define ST_SPELLHLP         &Language->BigString[Language->StrOffsets[1159]]
+#define ST_CITIZENHLP       &Language->BigString[Language->StrOffsets[1160]]
+#define ST_WARHLP           &Language->BigString[Language->StrOffsets[1161]]
+#define ST_EMPIREHLP        &Language->BigString[Language->StrOffsets[1162]]
+#define ST_ARMYHLP          &Language->BigString[Language->StrOffsets[1163]]
+
+#define ST_STATLINE0        &Language->BigString[Language->StrOffsets[1200]]
+#define ST_STATLINE1        &Language->BigString[Language->StrOffsets[1201]]
+#define ST_STATLINE2        &Language->BigString[Language->StrOffsets[1202]]
+#define ST_STATLINE3        &Language->BigString[Language->StrOffsets[1203]]
+#define ST_STATLINE4        &Language->BigString[Language->StrOffsets[1204]]
+
+//
+#define ST_WARMSJ0          &Language->BigString[Language->StrOffsets[1350]]
+#define ST_WARMSJ1          &Language->BigString[Language->StrOffsets[1351]]
+#define ST_WARMSJ2          &Language->BigString[Language->StrOffsets[1352]]
+#define ST_WARMSJ3          &Language->BigString[Language->StrOffsets[1353]]
+#define ST_WAR0             &Language->BigString[Language->StrOffsets[1354]]
+#define ST_WAR1             &Language->BigString[Language->StrOffsets[1355]]
+#define ST_WAR2             &Language->BigString[Language->StrOffsets[1356]]
+#define ST_WAR3             &Language->BigString[Language->StrOffsets[1357]]
+#define ST_WAR4             &Language->BigString[Language->StrOffsets[1358]]
+
+#define ST_BMENU30          &Language->BigString[Language->StrOffsets[1380]]
+#define ST_BMENU31          &Language->BigString[Language->StrOffsets[1381]]
+#define ST_BMENU32          &Language->BigString[Language->StrOffsets[1382]]
+#define ST_BMENU33          &Language->BigString[Language->StrOffsets[1383]]
+#define ST_BMENU34          &Language->BigString[Language->StrOffsets[1384]]
+#define ST_BMENU35          &Language->BigString[Language->StrOffsets[1385]]
+#define ST_BMENU36          &Language->BigString[Language->StrOffsets[1386]]
+#define ST_BMENU37          &Language->BigString[Language->StrOffsets[1387]]
+#define ST_BMENU38          &Language->BigString[Language->StrOffsets[1388]]
+#define ST_BMENU39          &Language->BigString[Language->StrOffsets[1389]]
+#define ST_BMENU40          &Language->BigString[Language->StrOffsets[1390]]
+#define ST_BMENU41          &Language->BigString[Language->StrOffsets[1391]]
+#define ST_BMENU42          &Language->BigString[Language->StrOffsets[1392]]
+#define ST_BMENU43          &Language->BigString[Language->StrOffsets[1393]]
+#define ST_BMENU44          &Language->BigString[Language->StrOffsets[1394]]
+#define ST_BMENU45          &Language->BigString[Language->StrOffsets[1395]]
+#define ST_BMENU46          &Language->BigString[Language->StrOffsets[1396]]
+#define ST_BMENU47          &Language->BigString[Language->StrOffsets[1397]]
+#define ST_BMENU48          &Language->BigString[Language->StrOffsets[1398]]
+#define ST_BMENU49          &Language->BigString[Language->StrOffsets[1399]]
+#define ST_BMENU50          &Language->BigString[Language->StrOffsets[1400]]
+#define ST_BMENU51          &Language->BigString[Language->StrOffsets[1401]]
+#define ST_BMENU52          &Language->BigString[Language->StrOffsets[1402]]
+#define ST_BMENU53          &Language->BigString[Language->StrOffsets[1403]]
+#define ST_BMENU54          &Language->BigString[Language->StrOffsets[1404]]
+
+#define ST_WIZ0             &Language->BigString[Language->StrOffsets[1420]]
+#define ST_WIZ1             &Language->BigString[Language->StrOffsets[1421]]
+#define ST_WIZ2             &Language->BigString[Language->StrOffsets[1422]]
+#define ST_WIZ3             &Language->BigString[Language->StrOffsets[1423]]
+#define ST_WIZ4             &Language->BigString[Language->StrOffsets[1424]]
+#define ST_WIZHLP           &Language->BigString[Language->StrOffsets[1425]]
+
+#define ST_MEMPIRE0         &Language->BigString[Language->StrOffsets[1440]]
+#define ST_MEMPIRE1         &Language->BigString[Language->StrOffsets[1441]]
+#define ST_MEMPIRE2         &Language->BigString[Language->StrOffsets[1442]]
+#define ST_MEMPIRE3         &Language->BigString[Language->StrOffsets[1443]]
+#define ST_MEMPIRE4         &Language->BigString[Language->StrOffsets[1444]]
+#define ST_MEMPIRE5         &Language->BigString[Language->StrOffsets[1445]]
+#define ST_MEMPIRE6         &Language->BigString[Language->StrOffsets[1446]]
+#define ST_MEMPIRE7         &Language->BigString[Language->StrOffsets[1447]]
+#define ST_MEMPIRE8         &Language->BigString[Language->StrOffsets[1448]]
+#define ST_MEMPIRE9         &Language->BigString[Language->StrOffsets[1449]]
+
+#define ST_MEMPIRE10        &Language->BigString[Language->StrOffsets[1470]]
+#define ST_MEMPIRE11        &Language->BigString[Language->StrOffsets[1471]]
+#define ST_MEMPIRE12        &Language->BigString[Language->StrOffsets[1472]]
+#define ST_MEMPIRE13        &Language->BigString[Language->StrOffsets[1473]]
+#define ST_MEMPIRE14        &Language->BigString[Language->StrOffsets[1474]]
+#define ST_MEMPIRE15        &Language->BigString[Language->StrOffsets[1475]]
+#define ST_MEMPIRE16        &Language->BigString[Language->StrOffsets[1476]]
+#define ST_MEMPIRE17        &Language->BigString[Language->StrOffsets[1477]]
+#define ST_MEMPIRE18        &Language->BigString[Language->StrOffsets[1478]]
+#define ST_MEMPIRE19        &Language->BigString[Language->StrOffsets[1479]]
+#define ST_MEMPIRE20        &Language->BigString[Language->StrOffsets[1480]]
+#define ST_MEMPIRE21        &Language->BigString[Language->StrOffsets[1481]]
+#define ST_MEMPIRE22        &Language->BigString[Language->StrOffsets[1482]]
+#define ST_MEMPIRE23        &Language->BigString[Language->StrOffsets[1483]]
+#define ST_MEMPIRE24        &Language->BigString[Language->StrOffsets[1484]]
+#define ST_MEMPIRE25        &Language->BigString[Language->StrOffsets[1485]]
+#define ST_MEMPIRE26        &Language->BigString[Language->StrOffsets[1486]]
+#define ST_MEMPIRE27        &Language->BigString[Language->StrOffsets[1487]]
+#define ST_MEMPIRE28        &Language->BigString[Language->StrOffsets[1488]]
+#define ST_MEMPIRE29        &Language->BigString[Language->StrOffsets[1489]]
+#define ST_MEMPIRE30        &Language->BigString[Language->StrOffsets[1490]]
+#define ST_MEMPIRE31        &Language->BigString[Language->StrOffsets[1491]]
+#define ST_MEMPIRE32        &Language->BigString[Language->StrOffsets[1492]]
+#define ST_MEMPIRE33        &Language->BigString[Language->StrOffsets[1493]]
+#define ST_MEMPIRE34        &Language->BigString[Language->StrOffsets[1494]]
+
+#define ST_DEMPIRE0         &Language->BigString[Language->StrOffsets[1500]]
+#define ST_DEMPIRE1         &Language->BigString[Language->StrOffsets[1501]]
+#define ST_DEMPIRE2         &Language->BigString[Language->StrOffsets[1502]]
+#define ST_DEMPIRE3         &Language->BigString[Language->StrOffsets[1503]]
+#define ST_DEMPIRE4         &Language->BigString[Language->StrOffsets[1504]]
+#define ST_DEMPIRE5         &Language->BigString[Language->StrOffsets[1505]]
+#define ST_DEMPIRE6         &Language->BigString[Language->StrOffsets[1506]]
+#define ST_DEMPIRE7         &Language->BigString[Language->StrOffsets[1507]]
+#define ST_DEMPIRE8         &Language->BigString[Language->StrOffsets[1508]]
+#define ST_DEMPIRE9         &Language->BigString[Language->StrOffsets[1509]]
+#define ST_DEMPIRE10        &Language->BigString[Language->StrOffsets[1510]]
+#define ST_DEMPIRE11        &Language->BigString[Language->StrOffsets[1511]]
+#define ST_DEMPIRE12        &Language->BigString[Language->StrOffsets[1512]]
+#define ST_DEMPIRE13        &Language->BigString[Language->StrOffsets[1513]]
+#define ST_DEMPIRE14        &Language->BigString[Language->StrOffsets[1514]]
+#define ST_DEMPIRE15        &Language->BigString[Language->StrOffsets[1515]]
+#define ST_DEMPIRE16        &Language->BigString[Language->StrOffsets[1516]]
+#define ST_DEMPIRE17        &Language->BigString[Language->StrOffsets[1517]]
+#define ST_DEMPIRE18        &Language->BigString[Language->StrOffsets[1518]]
+#define ST_DEMPIRE19        &Language->BigString[Language->StrOffsets[1519]]
+#define ST_DEMPIRE20        &Language->BigString[Language->StrOffsets[1520]]
+#define ST_DEMPIRE21        &Language->BigString[Language->StrOffsets[1521]]
+#define ST_DEMPIRE22        &Language->BigString[Language->StrOffsets[1522]]
+#define ST_DEMPIRE23        &Language->BigString[Language->StrOffsets[1523]]
+
+#define ST_DEVLAND0         &Language->BigString[Language->StrOffsets[1530]]
+#define ST_DEVLAND1         &Language->BigString[Language->StrOffsets[1531]]
+#define ST_DEVLAND2         &Language->BigString[Language->StrOffsets[1532]]
+
+#define ST_PAR0             &Language->BigString[Language->StrOffsets[1550]]
+#define ST_PAR1             &Language->BigString[Language->StrOffsets[1551]]
+#define ST_PAR2             &Language->BigString[Language->StrOffsets[1552]]
+#define ST_PAR3             &Language->BigString[Language->StrOffsets[1553]]
+#define ST_PAR4             &Language->BigString[Language->StrOffsets[1554]]
+
+#define ST_WEMPIRE0         &Language->BigString[Language->StrOffsets[1580]]
+#define ST_WEMPIRE1         &Language->BigString[Language->StrOffsets[1581]]
+#define ST_WEMPIRE2         &Language->BigString[Language->StrOffsets[1582]]
+#define ST_WEMPIRE3         &Language->BigString[Language->StrOffsets[1583]]
+#define ST_WEMPIRE4         &Language->BigString[Language->StrOffsets[1584]]
+#define ST_WEMPIRE5         &Language->BigString[Language->StrOffsets[1585]]
+#define ST_WEMPIRE6         &Language->BigString[Language->StrOffsets[1586]]
+
+#define ST_GTROOPS0         &Language->BigString[Language->StrOffsets[1590]]
+#define ST_GTROOPS1         &Language->BigString[Language->StrOffsets[1591]]
+#define ST_GTROOPS2         &Language->BigString[Language->StrOffsets[1592]]
+#define ST_GTROOPS3         &Language->BigString[Language->StrOffsets[1593]]
+#define ST_GTROOPS4         &Language->BigString[Language->StrOffsets[1594]]
+#define ST_GTROOPS5         &Language->BigString[Language->StrOffsets[1595]]
+#define ST_GTROOPS6         &Language->BigString[Language->StrOffsets[1596]]
+
+#define ST_WRESULTS0        &Language->BigString[Language->StrOffsets[1600]]
+#define ST_WRESULTS1        &Language->BigString[Language->StrOffsets[1601]]
+#define ST_WRESULTS2        &Language->BigString[Language->StrOffsets[1602]]
+#define ST_WRESULTS3        &Language->BigString[Language->StrOffsets[1603]]
+#define ST_WRESULTS4        &Language->BigString[Language->StrOffsets[1604]]
+#define ST_WRESULTS5        &Language->BigString[Language->StrOffsets[1605]]
+#define ST_WRESULTS6        &Language->BigString[Language->StrOffsets[1606]]
+#define ST_WRESULTS7        &Language->BigString[Language->StrOffsets[1607]]
+#define ST_WRESULTS8        &Language->BigString[Language->StrOffsets[1608]]
+#define ST_WRESULTS9        &Language->BigString[Language->StrOffsets[1609]]
+#define ST_WRESULTS10       &Language->BigString[Language->StrOffsets[1610]]
+#define ST_WRESULTS11       &Language->BigString[Language->StrOffsets[1611]]
+#define ST_WRESULTS12       &Language->BigString[Language->StrOffsets[1612]]
+#define ST_WRESULTS13       &Language->BigString[Language->StrOffsets[1613]]
+
+#define ST_SPY0             &Language->BigString[Language->StrOffsets[1630]]
+#define ST_SPY1             &Language->BigString[Language->StrOffsets[1631]]
+#define ST_SPY2             &Language->BigString[Language->StrOffsets[1632]]
+#define ST_SPY3             &Language->BigString[Language->StrOffsets[1633]]
+#define ST_SPY4             &Language->BigString[Language->StrOffsets[1634]]
+#define ST_SPY5             &Language->BigString[Language->StrOffsets[1635]]
+#define ST_SPY6             &Language->BigString[Language->StrOffsets[1636]]
+#define ST_SPY7             &Language->BigString[Language->StrOffsets[1637]]
+
+#define ST_PAWN0            &Language->BigString[Language->StrOffsets[1650]]
+#define ST_PAWN1            &Language->BigString[Language->StrOffsets[1651]]
+#define ST_PAWN2            &Language->BigString[Language->StrOffsets[1652]]
+#define ST_PAWN3            &Language->BigString[Language->StrOffsets[1653]]
+#define ST_PAWN4            &Language->BigString[Language->StrOffsets[1654]]
+#define ST_PAWN5            &Language->BigString[Language->StrOffsets[1655]]
+#define ST_PAWN6            &Language->BigString[Language->StrOffsets[1656]]
+#define ST_PAWN7            &Language->BigString[Language->StrOffsets[1657]]
+#define ST_PAWN8            &Language->BigString[Language->StrOffsets[1658]]
+#define ST_PAWN9            &Language->BigString[Language->StrOffsets[1659]]
+#define ST_PAWN10           &Language->BigString[Language->StrOffsets[1660]]
+#define ST_PAWN11           &Language->BigString[Language->StrOffsets[1661]]
+#define ST_PAWN12           &Language->BigString[Language->StrOffsets[1662]]
+#define ST_PAWN13           &Language->BigString[Language->StrOffsets[1663]]
+
+#define ST_TREASURE0        &Language->BigString[Language->StrOffsets[1675]]
+
+#define ST_WNEWS0           &Language->BigString[Language->StrOffsets[1680]]
+#define ST_WNEWS1           &Language->BigString[Language->StrOffsets[1681]]
+#define ST_WNEWS2           &Language->BigString[Language->StrOffsets[1682]]
+#define ST_WNEWS3           &Language->BigString[Language->StrOffsets[1683]]
+#define ST_WNEWS4           &Language->BigString[Language->StrOffsets[1684]]
+#define ST_WNEWS5           &Language->BigString[Language->StrOffsets[1685]]
+#define ST_WNEWS6           &Language->BigString[Language->StrOffsets[1686]]
+#define ST_WNEWS7           &Language->BigString[Language->StrOffsets[1687]]
+#define ST_WNEWS8           &Language->BigString[Language->StrOffsets[1688]]
+#define ST_WNEWS9           &Language->BigString[Language->StrOffsets[1689]]
+#define ST_WNEWS10          &Language->BigString[Language->StrOffsets[1690]]
+#define ST_WNEWS11          &Language->BigString[Language->StrOffsets[1691]]
+#define ST_WNEWS12          &Language->BigString[Language->StrOffsets[1692]]
+#define ST_WNEWS13          &Language->BigString[Language->StrOffsets[1693]]
+#define ST_WNEWS14          &Language->BigString[Language->StrOffsets[1694]]
+#define ST_WNEWS15          &Language->BigString[Language->StrOffsets[1695]]
+#define ST_WNEWS16          &Language->BigString[Language->StrOffsets[1696]]
+#define ST_WNEWS17          &Language->BigString[Language->StrOffsets[1697]]
+#define ST_WNEWS18          &Language->BigString[Language->StrOffsets[1698]]
+#define ST_WNEWS19          &Language->BigString[Language->StrOffsets[1699]]
+#define ST_WNEWS20          &Language->BigString[Language->StrOffsets[1700]]
+#define ST_WNEWS21          &Language->BigString[Language->StrOffsets[1701]]
+
+#define ST_NEWS0            &Language->BigString[Language->StrOffsets[1710]]
+#define ST_NEWS1            &Language->BigString[Language->StrOffsets[1711]]
+#define ST_NEWS2            &Language->BigString[Language->StrOffsets[1712]]
+#define ST_NEWS3            &Language->BigString[Language->StrOffsets[1713]]
+#define ST_NEWS4            &Language->BigString[Language->StrOffsets[1714]]
+
+#define ST_TMENUSTAT7       &Language->BigString[Language->StrOffsets[1715]]
+#define ST_TMENUSTAT8       &Language->BigString[Language->StrOffsets[1716]]
+#define ST_TMENUSTAT9       &Language->BigString[Language->StrOffsets[1717]]
+#define ST_TMENU19          &Language->BigString[Language->StrOffsets[1718]]
+#define ST_TMENU20          &Language->BigString[Language->StrOffsets[1719]]
+#define ST_TMENU21          &Language->BigString[Language->StrOffsets[1720]]
+#define ST_NEWS5            &Language->BigString[Language->StrOffsets[1721]]
+#define ST_NEWS6            &Language->BigString[Language->StrOffsets[1722]]
+#define ST_TMENU22          &Language->BigString[Language->StrOffsets[1723]]
+#define ST_TMENU23          &Language->BigString[Language->StrOffsets[1724]]
+#define ST_TMENU24          &Language->BigString[Language->StrOffsets[1725]]
+#define ST_TMENUSTAT10      &Language->BigString[Language->StrOffsets[1726]]
+
+#define ST_ESTATS0          &Language->BigString[Language->StrOffsets[1730]]
+#define ST_ESTATS1          &Language->BigString[Language->StrOffsets[1731]]
+#define ST_ESTATS2          &Language->BigString[Language->StrOffsets[1732]]
+#define ST_ESTATS3          &Language->BigString[Language->StrOffsets[1733]]
+#define ST_ESTATS4          &Language->BigString[Language->StrOffsets[1734]]
+#define ST_ESTATS5          &Language->BigString[Language->StrOffsets[1735]]
+#define ST_ESTATS6          &Language->BigString[Language->StrOffsets[1736]]
+#define ST_ESTATS7          &Language->BigString[Language->StrOffsets[1737]]
+#define ST_ESTATS8          &Language->BigString[Language->StrOffsets[1738]]
+#define ST_ESTATS9          &Language->BigString[Language->StrOffsets[1739]]
+#define ST_ESTATS10         &Language->BigString[Language->StrOffsets[1740]]
+#define ST_ESTATS11         &Language->BigString[Language->StrOffsets[1741]]
+#define ST_ESTATS12         &Language->BigString[Language->StrOffsets[1742]]
+#define ST_ESTATS13         &Language->BigString[Language->StrOffsets[1743]]
+#define ST_ESTATS14         &Language->BigString[Language->StrOffsets[1744]]
+#define ST_ESTATS15         &Language->BigString[Language->StrOffsets[1745]]
+#define ST_ESTATS16         &Language->BigString[Language->StrOffsets[1746]]
+#define ST_ESTATS17         &Language->BigString[Language->StrOffsets[1747]]
+#define ST_ESTATS18         &Language->BigString[Language->StrOffsets[1748]]
+
+#define ST_GSETTINGS0       &Language->BigString[Language->StrOffsets[1760]]
+#define ST_GSETTINGS1       &Language->BigString[Language->StrOffsets[1761]]
+#define ST_GSETTINGS2       &Language->BigString[Language->StrOffsets[1762]]
+#define ST_GSETTINGS3       &Language->BigString[Language->StrOffsets[1763]]
+#define ST_GSETTINGS4       &Language->BigString[Language->StrOffsets[1764]]
+#define ST_GSETTINGS5       &Language->BigString[Language->StrOffsets[1765]]
+#define ST_GSETTINGS6       &Language->BigString[Language->StrOffsets[1766]]
+#define ST_GSETTINGS7       &Language->BigString[Language->StrOffsets[1767]]
+
+#define ST_LSCORES0         &Language->BigString[Language->StrOffsets[1770]]
+#define ST_LSCORES1         &Language->BigString[Language->StrOffsets[1771]]
+#define ST_LSCORES2         &Language->BigString[Language->StrOffsets[1772]]
+#define ST_LSCORES3         &Language->BigString[Language->StrOffsets[1773]]
+
+#define ST_DEFACTION0       &Language->BigString[Language->StrOffsets[1780]]
+#define ST_DEFACTION1       &Language->BigString[Language->StrOffsets[1781]]
+#define ST_DEFACTION2       &Language->BigString[Language->StrOffsets[1782]]
+
+#define ST_P2STATS0         &Language->BigString[Language->StrOffsets[1800]]
+#define ST_P2STATS1         &Language->BigString[Language->StrOffsets[1801]]
+#define ST_P2STATS2         &Language->BigString[Language->StrOffsets[1802]]
+#define ST_P2STATS3         &Language->BigString[Language->StrOffsets[1803]]
+#define ST_P2STATS4         &Language->BigString[Language->StrOffsets[1804]]
+#define ST_P2STATS5         &Language->BigString[Language->StrOffsets[1805]]
+#define ST_P2STATS6         &Language->BigString[Language->StrOffsets[1806]]
+#define ST_P2STATS7         &Language->BigString[Language->StrOffsets[1807]]
+#define ST_P2STATS8         &Language->BigString[Language->StrOffsets[1808]]
+#define ST_P2STATS9         &Language->BigString[Language->StrOffsets[1809]]
+#define ST_P2STATS10        &Language->BigString[Language->StrOffsets[1810]]
+#define ST_P2STATS11        &Language->BigString[Language->StrOffsets[1811]]
+#define ST_P2STATS12        &Language->BigString[Language->StrOffsets[1812]]
+#define ST_P2STATS13        &Language->BigString[Language->StrOffsets[1813]]
+#define ST_P2STATS14        &Language->BigString[Language->StrOffsets[1814]]
+
+#define ST_SECRET2          &Language->BigString[Language->StrOffsets[1832]]
+#define ST_SECRET5          &Language->BigString[Language->StrOffsets[1835]]
+
+#define ST_IBBSONLY         &Language->BigString[Language->StrOffsets[1836]]
diff --git a/src/doors/clans-src/myibbs.c b/src/doors/clans-src/myibbs.c
new file mode 100644
index 0000000000000000000000000000000000000000..003fb97f7df0db88b626cbabffdbd4aba99ce59e
--- /dev/null
+++ b/src/doors/clans-src/myibbs.c
@@ -0,0 +1,712 @@
+
+/*
+ * This code is taken from the OpenDoors sample IBBS code by Brian Pirie.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#ifndef _MSC_VER
+# include <dir.h>
+#else
+# include <share.h>
+#endif
+#include <io.h>
+#include <dos.h>
+#endif
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "structs.h"
+#include <OpenDoor.h>
+#include "interbbs.h"
+#include "video.h"
+
+#define MAIL_OTHER      0
+#define MAIL_BINKLEY    1
+
+
+extern struct config *Config;
+
+
+
+char aszShortMonthName[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+void RidPath(char *pszFileName, char  *pszFileNameNoPath);
+
+tBool DirExists(const char *pszDirName)
+   {
+   char szDirFileName[PATH_CHARS + 1];
+#if !defined(_WIN32) & !defined(__unix__)
+   struct ffblk DirEntry;
+#else
+   struct stat file_stats;
+#endif
+
+   assert(pszDirName != NULL);
+   assert(strlen(pszDirName) <= PATH_CHARS);
+
+   strcpy(szDirFileName, pszDirName);
+
+   /* Remove any trailing backslash from directory name */
+   if(szDirFileName[strlen(szDirFileName) - 1] == '/' || szDirFileName[strlen(szDirFileName) - 1] == '\\')
+      {
+      szDirFileName[strlen(szDirFileName) - 1] = '\0';
+      }
+
+   /* Return true iff file exists and it is a directory */
+#if !defined(_WIN32) & !defined(__unix__)
+   return(findfirst(szDirFileName, &DirEntry, FA_ARCH|FA_DIREC) == 0 &&
+             (DirEntry.ff_attrib & FA_DIREC));
+#else
+   if (stat(szDirFileName, &file_stats) == 0)
+	   if (file_stats.st_mode & S_IFDIR)
+		   return TRUE;
+
+   return FALSE;
+#endif
+   }
+
+
+void MakeFilename(const char *pszPath, const char *pszFilename, char *pszOut)
+   {
+   /* Validate parameters in debug mode */
+   assert(pszPath != NULL);
+   assert(pszFilename != NULL);
+   assert(pszOut != NULL);
+   assert(pszPath != pszOut);
+   assert(pszFilename != pszOut);
+
+   /* Copy path to output filename */
+   strcpy(pszOut, pszPath);
+
+   /* Ensure there is a trailing backslash */
+   if(pszOut[strlen(pszOut) - 1] != '\\' && pszOut[strlen(pszOut) - 1] != '/')
+      {
+      strcat(pszOut, "/");
+      }
+
+   /* Append base filename */
+   strcat(pszOut, pszFilename);
+   }
+
+_INT16 GetMaximumEncodedLength(_INT16 nUnEncodedLength)
+   {
+   _INT16 nEncodedLength;
+
+   /* The current encoding algorithm uses two characters to represent   */
+   /* each byte of data, plus 1 byte per MAX_LINE_LENGTH characters for */
+   /* the carriage return character.                                    */
+
+   nEncodedLength = nUnEncodedLength * 2;
+
+   return(nEncodedLength + (nEncodedLength / MAX_LINE_LENGTH - 1) + 1);
+   }
+
+
+DWORD GetNextMSGID(void)
+   {
+   /* MSGID should be unique for every message, for as long as possible.   */
+   /* This technique adds the current time, in seconds since midnight on   */
+   /* January 1st, 1970 to a psuedo-random number. The random generator    */
+   /* is not seeded, as the application may have already seeded it for its */
+   /* own purposes. Even if not seeded, the inclusion of the current time  */
+   /* will cause the MSGID to almost always be different.                  */
+   return((DWORD)time(NULL) + (DWORD)rand());
+   }
+
+
+tBool CreateMessage(char *pszMessageDir, tMessageHeader *pHeader,
+                    char *pszText)
+   {
+   DWORD lwNewMsgNum;
+
+   /* Get new message number */
+   lwNewMsgNum = GetFirstUnusedMsgNum(pszMessageDir);
+
+   /* Use WriteMessage() to create new message */
+   return(WriteMessage(pszMessageDir, lwNewMsgNum, pHeader, pszText));
+   }
+
+
+void GetMessageFilename(char *pszMessageDir, DWORD lwMessageNum,
+                        char *pszOut)
+   {
+   char szFileName[FILENAME_CHARS + 1];
+
+   sprintf(szFileName, "%ld.msg", lwMessageNum);
+   MakeFilename(pszMessageDir, szFileName, pszOut);
+   }
+
+
+tBool WriteMessage(char *pszMessageDir, DWORD lwMessageNum,
+                   tMessageHeader *pHeader, char *pszText)
+   {
+   char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
+   _INT16 hFile;
+   size_t nTextSize;
+
+   /* Get fully qualified filename of message to write */
+   GetMessageFilename(pszMessageDir, lwMessageNum, szFileName);
+
+   /* Open message file */
+#ifdef __unix__
+   hFile = open(szFileName, O_WRONLY|O_BINARY|O_CREAT,
+                S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+#elif defined(_WIN32)
+   hFile = sopen(szFileName, O_WRONLY|O_BINARY|O_CREAT,SH_DENYRW,
+	            S_IREAD|S_IWRITE);
+#else
+   hFile = open(szFileName, O_WRONLY|O_BINARY|O_CREAT|O_DENYALL,
+                S_IREAD|S_IWRITE);
+#endif
+
+   /* If open failed, return FALSE */
+   if(hFile == -1) return(FALSE);
+
+   /* Attempt to write header */
+   if(write(hFile, pHeader, sizeof(tMessageHeader)) != sizeof(tMessageHeader))
+      {
+      /* On failure, close file, erase file, and return FALSE */
+      close(hFile);
+      unlink(szFileName);
+      return(FALSE);
+      }
+
+   /* Determine size of message text, including string terminator */
+   nTextSize = strlen(pszText) + 1;
+   // nTextSize = strlen(pszText);
+
+   /* Attempt to write message text */
+   if((unsigned)write(hFile, pszText, nTextSize) != nTextSize)
+      {
+      /* On failure, close file, erase file, and return FALSE */
+      close(hFile);
+      unlink(szFileName);
+      return(FALSE);
+      }
+
+   /* Close message file */
+   close(hFile);
+
+   /* Return with success */
+   return(TRUE);
+   }
+
+
+tBool ReadMessage(char *pszMessageDir, DWORD lwMessageNum,
+                  tMessageHeader *pHeader, char **ppszText)
+   {
+   char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
+   _INT16 hFile;
+   size_t nTextSize;
+
+   /* Get fully qualified filename of message to read */
+   GetMessageFilename(pszMessageDir, lwMessageNum, szFileName);
+
+   DisplayStr("> ");
+   DisplayStr(szFileName);
+   DisplayStr("     \r");
+
+   /* Open message file */
+#ifdef __unix__
+   hFile = open(szFileName, O_RDONLY|O_BINARY);
+#elif defined(_WIN32)
+   hFile = sopen(szFileName, O_RDONLY|O_BINARY,SH_DENYWR);
+#else
+   hFile = open(szFileName, O_RDONLY|O_BINARY|O_DENYWRITE);
+#endif
+
+   /* If open failed, return FALSE */
+   if(hFile == -1) return(FALSE);
+
+   /* Determine size of message body */
+   nTextSize = (size_t)filelength(hFile) - sizeof(tMessageHeader);
+
+   /* Attempt to allocate space for message body, plus character for added */
+   /* string terminator.                                                   */
+   if((*ppszText = malloc(nTextSize + 1)) == NULL)
+      {
+      /* On failure, close file and return FALSE */
+      close(hFile);
+      return(FALSE);
+      }
+
+   /* Attempt to read header */
+   if(read(hFile, pHeader, sizeof(tMessageHeader)) != sizeof(tMessageHeader))
+      {
+      /* On failure, close file, deallocate message buffer and return FALSE */
+      close(hFile);
+      free(*ppszText);
+      return(FALSE);
+      }
+
+   /* Attempt to read message text */
+   if((unsigned)read(hFile, *ppszText, nTextSize) != nTextSize)
+      {
+      /* On failure, close file, deallocate message buffer and return FALSE */
+      close(hFile);
+      free(*ppszText);
+      return(FALSE);
+      }
+
+   /* Ensure that message buffer is NULL-terminated */
+   (*ppszText)[nTextSize + 1] = '\0';
+
+   /* Close message file */
+   close(hFile);
+
+   /* Return with success */
+   return(TRUE);
+   }
+
+
+DWORD GetFirstUnusedMsgNum(char *pszMessageDir)
+   {
+   DWORD lwHighestMsgNum = 0;
+   DWORD lwCurrentMsgNum;
+#ifndef _WIN32
+   struct ffblk DirEntry;
+#else
+   struct _finddata_t find_data;
+   long find_handle;
+#endif
+   char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
+
+   MakeFilename(pszMessageDir, "*.msg", szFileName);
+
+#ifndef _WIN32
+   if(findfirst(szFileName, &DirEntry, FA_ARCH) == 0)
+      {
+      do
+         {
+         lwCurrentMsgNum = atol(DirEntry.ff_name);
+         if(lwCurrentMsgNum > lwHighestMsgNum)
+            {
+            lwHighestMsgNum = lwCurrentMsgNum;
+            }
+         } while(findnext(&DirEntry) == 0);
+      }
+#else
+   find_handle = _findfirst(szFileName, &find_data);
+   if (find_handle)
+   {
+	   do {
+		   lwCurrentMsgNum = atol(find_data.name);
+		   if (lwCurrentMsgNum > lwHighestMsgNum)
+		   {
+			   lwHighestMsgNum = lwCurrentMsgNum;
+		   }
+	   } while (_findnext(find_handle, &find_data) == 0);
+	   _findclose(find_handle);
+   }
+#endif
+
+   return(lwHighestMsgNum + 1);
+   }
+
+
+tIBResult ValidateInfoStruct(tIBInfo *pInfo)
+   {
+   if(pInfo == NULL) return(eBadParameter);
+
+   if(!DirExists(pInfo->szNetmailDir)) return(eMissingDir);
+
+   if(strlen(pInfo->szProgName) == 0) return(eBadParameter);
+
+   return(eSuccess);
+   }
+
+void ConvertStringToAddress(tFidoNode *pNode, const char *pszSource)
+   {
+   pNode->wZone = 0;
+   pNode->wNet = 0;
+   pNode->wNode = 0;
+   pNode->wPoint = 0;
+   sscanf(pszSource, "%u:%u/%u.%u", (unsigned int *)&(pNode->wZone), 
+          (unsigned int *) &(pNode->wNet),(unsigned int *)&(pNode->wNode),
+          (unsigned int *) &(pNode->wPoint));
+   }
+
+
+#define NUM_KEYWORDS       10
+
+#define KEYWORD_ADDRESS    0
+#define KEYWORD_USER_NAME  1
+#define KEYWORD_MAIL_DIR   2
+#define KEYWORD_CRASH      3
+#define KEYWORD_HOLD       4
+#define KEYWORD_KILL_SENT  5
+#define KEYWORD_KILL_RCVD  6
+#define KEYWORD_LINK_WITH  7
+#define KEYWORD_LINK_NAME  8
+#define KEYWORD_LINK_LOC   9
+
+tIBResult IBSendFileAttach(tIBInfo *pInfo, char *pszDestNode, char *pszFileName)
+   {
+   tIBResult ToReturn;
+   tMessageHeader MessageHeader;
+   time_t lnSecondsSince1970;
+   struct tm *pTimeInfo;
+   char szTOPT[13];
+   char szFMPT[13];
+   char szINTL[43];
+   char szMSGID[42];
+   _INT16 nKludgeSize;
+   _INT16 nTextSize, iTemp;
+   char *pszMessageText;
+   tFidoNode DestNode;
+   tFidoNode OrigNode;
+   char szFileNameNoPath[50];
+
+   if(pszDestNode == NULL) return(eBadParameter);
+   if(pszFileName == NULL) return(eBadParameter);
+
+   /* Validate information structure */
+   ToReturn = ValidateInfoStruct(pInfo);
+   if(ToReturn != eSuccess) return(ToReturn);
+
+   /* Get destination node address from string */
+   ConvertStringToAddress(&DestNode, pszDestNode);
+
+   /* Get origin address from string */
+   ConvertStringToAddress(&OrigNode, pInfo->szThisNodeAddress);
+
+   /* Construct message header */
+   /* Construct to, from and subject information */
+   strncpy(MessageHeader.szFromUserName, pInfo->szProgName, 36);
+   strncpy(MessageHeader.szToUserName, pInfo->szProgName, 36);
+   // strcpy(MessageHeader.szSubject, MESSAGE_SUBJECT);
+
+/* file attach addition */
+
+    /* figure out filename if no path in it */
+   // FIXME: In future remove this code
+//   RidPath(pszFileName, szFileNameNoPath);
+   strcpy(szFileNameNoPath, pszFileName);
+
+   if (Config->MailerType == MAIL_BINKLEY)
+   {
+       MessageHeader.szSubject[0] = '^';    /* delete file when sent */
+       strncpy(&MessageHeader.szSubject[1], szFileNameNoPath, 72);
+   }
+   else
+       strncpy(MessageHeader.szSubject, szFileNameNoPath, 72);
+
+   /* Construct date and time information */
+   lnSecondsSince1970 = time(NULL);
+   pTimeInfo = localtime(&lnSecondsSince1970);
+   sprintf(MessageHeader.szDateTime, "%2.2d %s %2.2d  %2.2d:%2.2d:%2.2d",
+           pTimeInfo->tm_mday,
+           aszShortMonthName[pTimeInfo->tm_mon],
+           pTimeInfo->tm_year,
+           pTimeInfo->tm_hour,
+           pTimeInfo->tm_min,
+           pTimeInfo->tm_sec);
+
+   /* Construct misc. information */
+   MessageHeader.wTimesRead = 0;
+   MessageHeader.wCost = 0;
+   MessageHeader.wReplyTo = 0;
+   MessageHeader.wNextReply = 0;
+
+   /* Construct destination address */
+   MessageHeader.wDestZone = DestNode.wZone;
+   MessageHeader.wDestNet = DestNode.wNet;
+   MessageHeader.wDestNode = DestNode.wNode;
+   MessageHeader.wDestPoint = DestNode.wPoint;
+
+   /* Construct origin address */
+   MessageHeader.wOrigZone = OrigNode.wZone;
+   MessageHeader.wOrigNet = OrigNode.wNet;
+   MessageHeader.wOrigNode = OrigNode.wNode;
+   MessageHeader.wOrigPoint = OrigNode.wPoint;
+
+   /* Construct message attributes */
+   MessageHeader.wAttribute = ATTRIB_PRIVATE | ATTRIB_LOCAL;
+   if(pInfo->bCrash) MessageHeader.wAttribute |= ATTRIB_CRASH;
+   if(pInfo->bHold) MessageHeader.wAttribute |= ATTRIB_HOLD;
+   if(pInfo->bEraseOnSend) MessageHeader.wAttribute |= ATTRIB_KILL_SENT;
+
+/* file attach additions */
+   MessageHeader.wAttribute |= ATTRIB_FILE_ATTACH;
+
+   /* Create message control (kludge) lines */
+   /* Create TOPT kludge line if destination point is non-zero */
+   if(DestNode.wPoint != 0)
+      {
+     sprintf(szTOPT, "\1TOPT %u\r", DestNode.wPoint);
+      }
+   else
+      {
+      strcpy(szTOPT, "");
+      }
+
+   /* Create FMPT kludge line if origin point is non-zero */
+   if(OrigNode.wPoint != 0)
+      {
+      sprintf(szFMPT, "\1FMPT %u\r", OrigNode.wPoint);
+      }
+   else
+      {
+      strcpy(szFMPT, "");
+      }
+
+   /* Create INTL kludge line if origin and destination zone addresses differ */
+   // FIXME: always use intl?
+   if(DestNode.wZone != OrigNode.wZone || TRUE)
+      {
+      sprintf(szINTL, "\1INTL %u:%u/%u %u:%u/%u\r",
+              DestNode.wZone,
+              DestNode.wNet,
+              DestNode.wNode,
+              OrigNode.wZone,
+              OrigNode.wNet,
+              OrigNode.wNode);
+      }
+   else
+      {
+      strcpy(szINTL, "");
+      }
+
+   /* Create MSGID kludge line, including point if non-zero */
+   if(OrigNode.wPoint != 0)
+      {
+      sprintf(szMSGID, "\1MSGID: %u:%u/%u.%u %lx\r",
+              OrigNode.wZone,
+              OrigNode.wNet,
+              OrigNode.wNode,
+              OrigNode.wPoint,
+              GetNextMSGID());
+      }
+   else
+      {
+      sprintf(szMSGID, "\1MSGID: %u:%u/%u %lx\r",
+              OrigNode.wZone,
+              OrigNode.wNet,
+              OrigNode.wNode,
+              GetNextMSGID());
+      }
+
+   /* Determine total size of kludge lines */
+   nKludgeSize = strlen(szTOPT)
+                + strlen(szFMPT)
+                + strlen(szINTL)
+                + strlen(szMSGID)
+                + strlen(MESSAGE_PID);
+
+   /* Determine total size of message text */
+   nTextSize = nKludgeSize + 1;
+
+   if (Config->MailerType != MAIL_BINKLEY)
+      nTextSize += (strlen("FLAGS KFS")+1);
+
+   /* Attempt to allocate space for message text */
+   if((pszMessageText = malloc(nTextSize)) == NULL)
+      {
+      return(eNoMemory);
+      }
+
+   /* Construct message text */
+   strcpy(pszMessageText, szTOPT);
+   strcat(pszMessageText, szFMPT);
+   strcat(pszMessageText, szINTL);
+   strcat(pszMessageText, szMSGID);
+   strcat(pszMessageText, MESSAGE_PID);
+   if (Config->MailerType != MAIL_BINKLEY)
+   {
+      iTemp = strlen(pszMessageText);
+      strcpy(pszMessageText+iTemp, "FLAGS KFS");
+/*      pszMessageText[ iTemp ] = '';
+      pszMessageText[ iTemp+1 ] = 'F';
+      pszMessageText[ iTemp+2 ] = 'L';
+      pszMessageText[ iTemp+3 ] = 'A';
+      pszMessageText[ iTemp+4 ] = 'G';
+      pszMessageText[ iTemp+5 ] = 'S';
+      pszMessageText[ iTemp+6 ] = ' ';
+      pszMessageText[ iTemp+7 ] = 'K';
+      pszMessageText[ iTemp+8 ] = 'F';
+      pszMessageText[ iTemp+9 ] = 'S';
+      pszMessageText[ iTemp+10 ] = '\0';    */
+   }
+
+   /* Attempt to send the message */
+   if(CreateMessage(pInfo->szNetmailDir, &MessageHeader, pszMessageText))
+      {
+      ToReturn = eSuccess;
+      }
+   else
+      {
+      ToReturn = eGeneralFailure;
+      }
+
+   /* Deallocate message text buffer */
+   free(pszMessageText);
+
+   /* Return appropriate value */
+   return(ToReturn);
+   }
+
+tIBResult IBGetFile(tIBInfo *pInfo, char *szAttachFile)
+   {
+   tIBResult ToReturn;
+#ifndef _WIN32
+   struct ffblk DirEntry;
+#else
+   struct _finddata_t find_data;
+   long find_handle;
+#endif
+   DWORD lwCurrentMsgNum;
+   tMessageHeader MessageHeader;
+   char szFileName[PATH_CHARS + FILENAME_CHARS + 2];
+   char *pszText;
+   tFidoNode ThisNode;
+   char szFileNameNoPath[50], szTemp[50];
+
+   /* Validate information structure */
+   ToReturn = ValidateInfoStruct(pInfo);
+   if(ToReturn != eSuccess) return(ToReturn);
+
+   /* Get this node's address from string */
+   ConvertStringToAddress(&ThisNode, pInfo->szThisNodeAddress);
+
+   MakeFilename(pInfo->szNetmailDir, "*.msg", szFileName);
+
+   /* Seach through each message file in the netmail directory, in no */
+   /* particular order.                                               */
+#ifndef _WIN32
+   if(findfirst(szFileName, &DirEntry, FA_ARCH) == 0)
+#else
+   find_handle = _findfirst(szFileName, &find_data);
+   if (find_handle)
+#endif
+      {
+      do
+         {
+#ifndef _WIN32
+         lwCurrentMsgNum = atol(DirEntry.ff_name);
+#else
+		 lwCurrentMsgNum = atol(find_data.name);
+#endif
+
+         /* If able to read message */
+         if(ReadMessage(pInfo->szNetmailDir, lwCurrentMsgNum, &MessageHeader,
+            &pszText))
+            {
+            /* If message is for us, and hasn't be read yet */
+            if(strcmp(MessageHeader.szToUserName, pInfo->szProgName) == 0
+               && ThisNode.wZone == MessageHeader.wDestZone
+               && ThisNode.wNet == MessageHeader.wDestNet
+               && ThisNode.wNode == MessageHeader.wDestNode
+               && ThisNode.wPoint == MessageHeader.wDestPoint
+               && !(MessageHeader.wAttribute & ATTRIB_RECEIVED))
+               {
+
+                /* strcpy inbounddir to filename */
+                /* strcat the subject of message -- actual filename */
+                // FIXME: problems later on?!
+                strcpy(szAttachFile, Config->szInboundDir);
+
+                // remove the ^ and path if it is first char
+
+                // problem here since in local league, we don't need the ^
+                // char and since we "send" each other packets and receive them
+                // with the same filename as we got them, in real life, a packet
+                // would be sent and received with no path to open it, so we
+                // assume we use the inbound path and open the file from that
+
+                // remove ^ char
+                if (MessageHeader.szSubject[0] == '^')
+                    strcat(szTemp, &MessageHeader.szSubject[1]);
+                else
+                    strcpy(szTemp, MessageHeader.szSubject);
+
+                // dude: remove path if it exists -- local leagues only
+                RidPath(MessageHeader.szSubject, szFileNameNoPath);
+
+                //printf("headersubject: %s\n", szTemp);
+                //printf("filename nopath: %s\n", szFileNameNoPath);
+                strcat(szAttachFile, szFileNameNoPath);
+
+                //printf("inbound File found:  %s\n", szAttachFile);
+
+               /* If received messages should be deleted */
+               if(pInfo->bEraseOnReceive)
+                  {
+                  /* Determine filename of message to erase */
+                  GetMessageFilename(pInfo->szNetmailDir, lwCurrentMsgNum,
+                                     szFileName);
+
+                  /* Attempt to erase file */
+                  if(unlink(szFileName) == -1)
+                     {
+                     ToReturn = eGeneralFailure;
+                     }
+                  else
+                     {
+                     ToReturn = eSuccess;
+                     }
+                  }
+
+               /* If received messages should not be deleted */
+               else /* if(!pInfo->bEraseOnReceive) */
+                  {
+                  /* Mark message as read */
+                  MessageHeader.wAttribute |= ATTRIB_RECEIVED;
+                  ++MessageHeader.wTimesRead;
+
+                  /* Attempt to rewrite message */
+                  if(!WriteMessage(pInfo->szNetmailDir, lwCurrentMsgNum,
+                   &MessageHeader, pszText))
+                     {
+                     ToReturn = eGeneralFailure;
+                     }
+                  else
+                     {
+                     ToReturn = eSuccess;
+                     }
+                  }
+
+               /* Deallocate message text buffer */
+               free(pszText);
+
+               /* Return appropriate value */
+               return(ToReturn);
+               }
+            free(pszText);
+            }
+#ifndef _WIN32
+         } while(findnext(&DirEntry) == 0);
+#else
+		 } while(_findnext(find_handle, &find_data) == 0);
+         _findclose(find_handle);
+#endif
+      }
+
+   /* If no new messages were found */
+   return(eNoMoreMessages);
+   }
+
+void RidPath(char *pszFileName, char  *pszFileNameNoPath)
+{
+    _INT16 CurChar;
+
+    for (CurChar = strlen(pszFileName); CurChar > 0; CurChar--)
+    {
+        /* is this a '\' char?  If so, break; */
+        if (pszFileName[CurChar] == '\\' || pszFileName[CurChar] == '/')
+        {
+            CurChar++;  // skip the \ char
+            break;
+        }
+    }
+    strcpy(pszFileNameNoPath, &pszFileName[CurChar]);
+}
diff --git a/src/doors/clans-src/myibbs.h b/src/doors/clans-src/myibbs.h
new file mode 100644
index 0000000000000000000000000000000000000000..47d9b0eefd51d9b688ef929ef50d69034a3e4b58
--- /dev/null
+++ b/src/doors/clans-src/myibbs.h
@@ -0,0 +1 @@
+tIBResult IBGetFile(tIBInfo *pInfo, char *szAttachFile);
diff --git a/src/doors/clans-src/myopen.c b/src/doors/clans-src/myopen.c
new file mode 100644
index 0000000000000000000000000000000000000000..936e4e072ff0bbb9a087acfd7bf08e0b7ef8261e
--- /dev/null
+++ b/src/doors/clans-src/myopen.c
@@ -0,0 +1,213 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * "File opening" calls.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#include <dos.h>
+#endif
+
+#include "defines.h"
+#include "myopen.h"
+#include "video.h"
+#include "language.h"
+#include "system.h"
+
+void cipher (void *, void *, size_t, unsigned char);
+
+  void MyOpen( char *szFileName, char *szMode, struct FileHeader *FileHeader )
+    /*
+     * This function opens the file specified and sees if it is a .PAKfile
+     * file or a regular DOS file.
+     */
+  {
+    FILE *fp;
+    BOOL FoundFile = FALSE;
+    char szPakFileName[50], szModFileName[50], *pc;
+
+    strcpy(szModFileName, szFileName);
+
+    if (szFileName[0] == '@')
+    {
+      // different .PAK file
+      strcpy(szPakFileName, &szFileName[1]);
+
+      // find the '/' char and put a null there
+
+      pc = szPakFileName;
+
+      while (*pc)
+      {
+        if (*pc == '/')
+        {
+          strcpy(szModFileName, pc);
+
+          *pc = 0;
+          break;
+        }
+        pc++;
+      }
+
+    }
+    else
+    {
+      strcpy(szPakFileName, "clans.pak");
+    }
+
+    // if file starts with / then it is in pakfile
+    FileHeader->fp = NULL;
+    if (szModFileName[0] == '/')
+    {
+      // look for the file
+      // fp = _fsopen(szPakFileName, "rb", SH_DENYWR);
+      fp = fopen(szPakFileName, "rb");
+
+		if (! fp)  {
+	      System_Error("Can't open CLANS.PAK file.\n");
+		}
+
+      for (;;)
+      {
+        if (fread(FileHeader, sizeof(struct FileHeader), 1, fp) == 0)
+          break;
+
+        // od_printf("read in %s\n\r", FileHeader->szFileName);
+
+        if (stricmp(FileHeader->szFileName, szModFileName) == 0)
+        {
+          FoundFile = TRUE;
+          break;
+        }
+        else  // go onto next file
+          fseek(fp, FileHeader->lFileSize, SEEK_CUR);
+      }
+
+      // found file and at start of it, close file, reopen with szMode
+      fclose(fp);
+
+      if (FoundFile)
+      {
+        FileHeader->fp = fopen(szPakFileName, szMode);
+        fseek(FileHeader->fp, FileHeader->lStart, SEEK_SET);
+      }
+      else
+	  {
+	      // open file from dos
+    	  fp = _fsopen(szModFileName, szMode, SH_DENYWR);
+	      if (!fp) return;
+
+    	  // read in file stats
+	      FileHeader->lStart = 0;
+
+    	  fseek(fp, 0L, SEEK_END);
+	      FileHeader->lEnd = FileHeader->lFileSize = ftell(fp);
+    	  fseek(fp, 0L, SEEK_SET);
+
+	      FileHeader->fp = fp;
+	  }
+      return;
+    }
+    else
+    {
+      // open file from dos
+      fp = _fsopen(szModFileName, szMode, SH_DENYWR);
+      if (!fp) return;
+
+      // read in file stats
+      FileHeader->lStart = 0;
+
+      fseek(fp, 0L, SEEK_END);
+      FileHeader->lEnd = FileHeader->lFileSize = ftell(fp);
+      fseek(fp, 0L, SEEK_SET);
+
+      FileHeader->fp = fp;
+
+      return;
+    }
+  }
+
+  void EncryptWrite ( void *Data, long DataSize, FILE *fp, char XorValue )
+  {
+    char *EncryptedData;
+
+    if (DataSize == 0)
+    {
+      System_Error("EncryptWrite() called with 0 bytes\n");
+    }
+
+    //printf("EncryptWrite(): Data size is %d\n", (_INT16)DataSize);
+    EncryptedData = malloc((_INT16)DataSize);
+    CheckMem(EncryptedData);
+
+/*  -- Removed the original Encrypt() function for simplicity
+    Encrypt(EncryptedData, (char *)Data, DataSize, XorValue);*/
+	cipher (EncryptedData, Data, DataSize, (unsigned char)XorValue);
+
+    fwrite(EncryptedData, (_INT16)DataSize, 1, fp);
+
+    free(EncryptedData);
+  }
+
+  _INT16 EncryptRead ( void *Data, long DataSize, FILE *fp, char XorValue )
+  {
+    char *EncryptedData;
+    _INT16 Result;
+
+    if (DataSize == 0)
+    {
+      System_Error("EncryptRead() called with 0 bytes\n");
+    }
+
+    EncryptedData = malloc(DataSize);
+    CheckMem(EncryptedData);
+
+    Result = fread(EncryptedData, 1, DataSize, fp);
+
+/*  -- Removed the original Decrypt() function for simplicity  
+	Decrypt((char *)Data, EncryptedData, DataSize, XorValue);*/
+	if (Result)
+		cipher(Data, EncryptedData, DataSize, (unsigned char)XorValue);
+
+    free(EncryptedData);
+
+    return Result;
+  }
+
+/* -- Replacement Encrypt/Decrypt function, reduces redundant code */
+  void cipher (void *dest, void *src, size_t len, unsigned char xor_val)
+  {
+	if (!dest || !src || !len || !xor_val)
+		System_Error ("Invalid Parameters to cipher");
+
+	while (len--)
+	{
+		*(char *)dest = *(char *)src ^ xor_val;
+		dest = (char *)dest + 1;
+		src = (char *)src + 1;
+	}
+  }
diff --git a/src/doors/clans-src/myopen.h b/src/doors/clans-src/myopen.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b9cf2d0001fe2fa9a49939bd10314e2a2932526
--- /dev/null
+++ b/src/doors/clans-src/myopen.h
@@ -0,0 +1,21 @@
+/*
+ * MyOpen ADT
+ */
+
+  struct PACKED FileHeader {
+    FILE *fp;     // used only when reading the file in
+    char szFileName[30];
+    long lStart, lEnd, lFileSize;
+  } PACKED;
+
+  void MyOpen( char *szFileName, char *szMode, struct FileHeader *FileHeader );
+    /*
+     * This function opens the file specified and sees if it is a .PAKfile
+     * file or a regular DOS file.
+     */
+
+  void EncryptWrite ( void *Data, long DataSize, FILE *fp, char XorValue );
+  _INT16 EncryptRead ( void *Data, long DataSize, FILE *fp, char XorValue );
+
+
+#define EXTRABYTES      10L
diff --git a/src/doors/clans-src/news.c b/src/doors/clans-src/news.c
new file mode 100644
index 0000000000000000000000000000000000000000..28345066eb42f142f64897b7922743c76511bf00
--- /dev/null
+++ b/src/doors/clans-src/news.c
@@ -0,0 +1,144 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "door.h"
+#include "language.h"
+#include "mstrings.h"
+
+extern struct Language *Language;
+extern struct system System;
+
+  void News_AddNews(char *szString)
+  {
+    FILE *fpNewsFile;
+
+    /* open news file */
+
+    /* add to it */
+
+    fpNewsFile = _fsopen("today.asc", "at", SH_DENYWR);
+
+    fputs(szString, fpNewsFile);
+
+    fclose(fpNewsFile);
+  }
+
+  void News_ReadNews( BOOL Today )
+  {
+    _INT16 CurLine = 0, NumLines, cTemp;
+    FILE *fp;
+    char *Lines[30];
+
+    /* now display it according to the type of file it is */
+
+    if (Today)
+      fp = _fsopen ("today.asc", "r", SH_DENYWR);
+    else
+      fp = _fsopen ("yest.asc", "r", SH_DENYWR);
+    if (!fp)
+    {
+      rputs("No news to report.\n\n%P");
+      return;
+    }
+
+    /* init mem */
+    for (cTemp = 0; cTemp < 30; cTemp++)
+    {
+      Lines[cTemp] = malloc(255);
+      CheckMem(Lines[cTemp]);
+    }
+
+    for (;;)
+    {
+      /* get SCREEN_LENGTH-4 lines if possible */
+      for (cTemp = 0; cTemp < (od_control.user_screen_length-4); cTemp++)
+      {
+        fgets(Lines[cTemp], 255, fp);
+        if (feof(fp))
+          break;
+      }
+      NumLines = cTemp;
+
+      /* display them all */
+      for (CurLine = 0; CurLine < NumLines; CurLine++)
+          rputs(Lines[CurLine]);
+
+      /* pause if SCREEN_LENGTH-4 lines */
+      if (CurLine == (od_control.user_screen_length-4) && Door_AllowScreenPause ())
+      {
+        rputs(ST_MORE);
+        od_sleep(0);
+          if (toupper(od_get_key(TRUE)) == 'N')
+        {
+          rputs("\r                       \r");
+          break;
+        }
+        rputs("\r                       \r");
+
+        CurLine = 0;
+      }
+      else if (Door_AllowScreenPause() == FALSE)
+        CurLine = 0;
+
+        /* see if end of file, if so, exit */
+      if (feof(fp))
+        break;
+
+      /* see if key hit */
+      if (od_get_key(FALSE)) break;
+      }
+
+    /* de-init mem */
+      for (cTemp = 0; cTemp < 30; cTemp++)
+      {
+        free(Lines[cTemp]);
+        Lines[cTemp] = NULL;
+      }
+
+    fclose(fp);
+
+    door_pause();
+
+  }
+
+  void News_CreateTodayNews  ( void )
+  {
+    /* this initializes the TODAY.ASC file */
+
+    char szString[128];
+
+    sprintf(szString, ST_NEWSFOR, System.szTodaysDate);
+    News_AddNews(szString);
+
+    /* give other info like increase in cost of etc. */
+  }
+
diff --git a/src/doors/clans-src/news.h b/src/doors/clans-src/news.h
new file mode 100644
index 0000000000000000000000000000000000000000..f38d82e1b9fce24068475fdc8aaa1caa2f544011
--- /dev/null
+++ b/src/doors/clans-src/news.h
@@ -0,0 +1,4 @@
+
+  void News_AddNews(char *szString);
+  void News_ReadNews( __BOOL Today );
+  void News_CreateTodayNews  ( void );
diff --git a/src/doors/clans-src/npc.c b/src/doors/clans-src/npc.c
new file mode 100644
index 0000000000000000000000000000000000000000..b0017265666fa141a8b7cff44c22ad44296b06e3
--- /dev/null
+++ b/src/doors/clans-src/npc.c
@@ -0,0 +1,667 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1998-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * NPCs ADT
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "quests.h"
+#include "myopen.h"
+#include "video.h"
+#include "language.h"
+#include "mstrings.h"
+#include "door.h"
+#include "news.h"
+#include "input.h"
+#include "user.h"
+#include "fight.h"
+
+
+extern char Quests_TFlags[8];
+extern struct IniFile IniFile;
+extern struct clan *PClan;
+extern struct Language *Language;
+extern struct game Game;
+
+// ------------------------------------------------------------------------- //
+
+  void NPC_GetNPCNdx ( struct NPCInfo *NPCInfo, struct NPCNdx *NPCNdx )
+  {
+    /* gets NPC stats from .NPX file if available, else goes to .NPC file */
+
+    char *NPXFile = "clans.npx";
+    FILE *fpNPX;
+    BOOL Found = FALSE;
+
+    fpNPX = fopen(NPXFile, "rb");
+    if (fpNPX)
+    {
+      for (;;)
+      {
+        if (!fread(NPCNdx, sizeof(struct NPCNdx), 1, fpNPX))
+          break;
+
+        // found it!
+        if (stricmp(NPCNdx->szIndex, NPCInfo->szIndex) == 0)
+        {
+          Found = TRUE;
+          break;
+        }
+      }
+
+      fclose(fpNPX);
+    }
+
+    if (!Found)
+    {
+      // couldn't find NDX in the NPX for that particular NPC
+
+      strcpy(NPCNdx->szIndex, NPCInfo->szIndex);
+      NPCNdx->InClan = FALSE;
+      NPCNdx->ClanID[0] = -1;
+      NPCNdx->ClanID[1] = -1;
+      NPCNdx->Status = NPCS_NOTHERE;
+      NPCNdx->WhereWander = NPCInfo->WhereWander;
+    }
+  }
+
+  void NPC_UpdateNPCNdx ( char *szIndex, struct NPCNdx *NPCNdx )
+  {
+    /* Function to update status of an NPC to .NPX file */
+    char *NPXFile = "clans.npx";
+    FILE *fpNPX;
+    long Offset;
+    struct NPCNdx TmpNdx;
+
+    fpNPX = fopen(NPXFile, "r+b");
+    if (fpNPX)
+    {
+      for (;;)
+      {
+        Offset = ftell(fpNPX);
+
+        if (!fread(&TmpNdx, sizeof(struct NPCNdx), 1, fpNPX))
+          break;
+
+        // found it!
+        if (stricmp(TmpNdx.szIndex, szIndex) == 0)
+        {
+          fseek(fpNPX, Offset, SEEK_SET);
+          break;
+        }
+      }
+    }
+
+    fwrite(NPCNdx, sizeof(struct NPCNdx), 1, fpNPX);
+
+    fclose(fpNPX);
+  }
+
+  void NPC_Maint ( void )
+  {
+    FILE *fpNPX;
+    _INT16 CurNPCFile;
+    struct FileHeader FileHeader;
+    struct NPCInfo *NPCInfo;
+    struct NPCNdx NPCNdx;
+    char *szClansNPX = "clans.npx";
+    _INT16 iTemp;
+
+    DisplayStr("* NPC Maint\n");
+
+    NPCInfo = malloc(sizeof(struct NPCInfo));
+    CheckMem(NPCInfo);
+
+    // delete old CLANS.NPX file
+    unlink(szClansNPX);
+
+    fpNPX = fopen(szClansNPX, "wb");
+
+    for (iTemp = 0; iTemp < MAX_NPCFILES; iTemp++)
+    {
+      if (IniFile.pszNPCFileName[iTemp] == NULL) break;
+
+      MyOpen(IniFile.pszNPCFileName[iTemp], "rb", &FileHeader);
+
+      if (!FileHeader.fp)
+        continue;
+
+      for (;;)
+      {
+        if (ftell(FileHeader.fp) >= FileHeader.lEnd)
+          break;
+
+        fread(NPCInfo, sizeof(struct NPCInfo), 1, FileHeader.fp);
+
+        // is he a wandering type?
+        if (NPCInfo->WhereWander == WN_NONE)
+          continue;   // no, not wanderer, skip him
+
+        // printf("Testing %s\n", NPCInfo->szName);
+
+        // prepare to write to NPX file
+        strcpy(NPCNdx.szIndex, NPCInfo->szIndex);
+        NPCNdx.WhereWander = NPCInfo->WhereWander;
+        NPCNdx.InClan = FALSE;
+        NPCNdx.ClanID[0] = -1;
+        NPCNdx.ClanID[1] = -1;
+        NPCNdx.Status = NPCS_NOTHERE;
+
+        // yes, he is a wanderer, see if appears in town today
+        if (RANDOM(100) < NPCInfo->OddsOfSeeing)
+        {
+          // printf("%s is in town\n", NPCInfo->szName);
+
+          // he appears in town today
+          NPCNdx.Status = NPCS_HERE;
+
+          // write to news
+          if (NPCInfo->szHereNews[0])
+          {
+            News_AddNews(NPCInfo->szHereNews);
+            News_AddNews("\n\n");
+          }
+        }
+
+        // write to NPX file
+        fwrite(&NPCNdx, sizeof(struct NPCNdx), 1, fpNPX);
+      }
+
+      fclose(FileHeader.fp);
+    }
+
+    fclose(fpNPX);
+
+    free(NPCInfo);
+	(void)CurNPCFile;
+  }
+
+  void NPC_ChatNPC ( char *szIndex )
+  {
+    /* for now, this is the chatnpc function */
+
+    /* for now, just use the knight as the NPC to chat with */
+    struct NPCInfo *NPCInfo;
+    _INT16 iTemp, NumTopicsKnown, WhichTopic, QuoteIndex[MAX_TOPICS],
+      CurFile, CurNPC, UserInput;
+    char *szString, szKeys[26 + 3], *pszTopics[MAX_TOPICS],
+      szPrompt[128];
+    struct clan *EnemyClan;
+    struct FileHeader FileHeader;
+      struct NPCNdx NPCNdx;
+    long Offset;
+    BOOL FoundNPC;
+
+    szString = MakeStr(255);
+
+    EnemyClan = NULL;
+
+    NPCInfo = malloc(sizeof(struct NPCInfo));
+    CheckMem(NPCInfo);
+
+    FoundNPC = FALSE;
+    for (CurFile = 0; CurFile < MAX_NPCS; CurFile++)
+    {
+      // if out of files, break
+      if (IniFile.pszNPCFileName[CurFile] == NULL)
+        break;
+
+      MyOpen(IniFile.pszNPCFileName[CurFile], "rb", &FileHeader);
+
+      if (!FileHeader.fp)  break;
+
+      /* find him in the file */
+      for (CurNPC = 0;; CurNPC++)
+      {
+        Offset = (long)CurNPC * (long)sizeof(struct NPCInfo) + FileHeader.lStart;
+
+        // reach end
+        if (Offset >= FileHeader.lEnd)
+          break;
+
+        if (fseek(FileHeader.fp, Offset, SEEK_SET))
+          break;
+
+        if (fread(NPCInfo, sizeof(struct NPCInfo), 1, FileHeader.fp) == 0)
+          break;
+
+        // one we want?
+        if (stricmp(NPCInfo->szIndex, szIndex) == 0)
+        {
+          // yes
+          FoundNPC = TRUE;
+          break;
+        }
+      }
+      fclose(FileHeader.fp);
+
+      if (FoundNPC)  break;
+    }
+
+    if (FoundNPC == FALSE)
+    {
+      rputs("NPC not found\n\r");
+      free(szString);
+      free(NPCInfo);
+      return;
+    }
+
+    // clear temp flags
+    ClearFlags(Quests_TFlags);
+
+    // run intro topic
+    if (NPCInfo->IntroTopic.Active)
+    {
+      if (RunEvent(TRUE, NPCInfo->szQuoteFile,
+        NPCInfo->IntroTopic.szFileName, NPCInfo, szIndex) == TRUE)
+      {
+        free(NPCInfo);
+        free(szString);
+        return;
+      }
+      door_pause();
+    }
+
+    /* now the topic stuff */
+
+    for (;;)
+    {
+      sprintf(szString, "\n |0AYou are chatting with |0B%s\n", NPCInfo->szName);
+      rputs(szString);
+
+      // get topics known
+      NumTopicsKnown = 0;
+      for (iTemp = 0; iTemp < MAX_TOPICS; iTemp++)
+      {
+        if (NPCInfo->Topics[iTemp].Active && NPCInfo->Topics[iTemp].Known)
+        {
+          pszTopics[ NumTopicsKnown ] = NPCInfo->Topics[iTemp].szName;
+          QuoteIndex[ NumTopicsKnown ] = iTemp;
+          NumTopicsKnown++;
+        }
+      }
+
+      // see how many quotes left
+      if (NPCInfo->MaxTopics != -1)
+      {
+        sprintf(szPrompt, "|0A You may discuss |0B%d |0Atopics.  ",
+          NPCInfo->MaxTopics);
+      }
+      else szPrompt[0] = 0;
+
+      strcat(szPrompt, "|0GEnter a Topic or press enter to quit\n|0E> |07");
+
+      // chose one
+      GetStringChoice(pszTopics, NumTopicsKnown, szPrompt, &UserInput,
+        TRUE, DT_LONG, TRUE);
+
+      if (UserInput == -1)
+        break;
+
+      if (NPCInfo->MaxTopics != -1)
+        NPCInfo->MaxTopics--;
+
+      // get topic's actual index
+      WhichTopic = QuoteIndex[ UserInput ];
+
+      // if quote is of type ClanInfo, tell user info
+      if (NPCInfo->Topics[WhichTopic].ClanInfo)
+      {
+        rputs("|03Here's some info on the clan I'm in.\n%P");
+
+        NPC_GetNPCNdx(NPCInfo, &NPCNdx);
+
+        EnemyClan = malloc(sizeof(struct clan));
+        CheckMem(EnemyClan);
+
+        GetClan(NPCNdx.ClanID, EnemyClan);
+
+        // Clan_Extract(EnemyClan, NPCNdx.ClanID);
+        ClanStats(EnemyClan, FALSE);
+        FreeClan(EnemyClan);
+
+        continue;
+      }
+
+      // otherwise, "run" that quote in the NPCQUOTE.Q file
+      if (RunEvent(TRUE, NPCInfo->szQuoteFile,
+        NPCInfo->Topics[WhichTopic].szFileName, NPCInfo, szIndex) == TRUE)
+      {
+        // player killed while fighting, quit
+        break;
+      }
+      else door_pause();
+
+      if (NPCInfo->MaxTopics == 0)
+      {
+        rputs("|0BYou have spent enough time chatting.  You end the discussion.\n%P");
+        break;
+      }
+    }
+
+    free(NPCInfo);
+    free(szString);
+	(void)szKeys;
+  }
+
+  void ChatVillagers ( _INT16 WhichMenu )
+  {
+    struct NPCInfo *NPCInfo;
+    char *pszNPCIndex[MAX_NPCS], szString[80];
+    char *pszNPCNames[MAX_NPCS], cInput, szKeys[MAX_NPCS + 4];
+    _INT16 CurNPC, NPCsFound = 0, CurFile;
+    long Offset;
+    struct FileHeader FileHeader;
+    struct NPCNdx NPCNdx;
+
+    /* if all guys dead, tell guy can't fight */
+    if (NumMembers(PClan, TRUE) == 0)
+    {
+      rputs(ST_FIGHT0);
+      return;
+    }
+
+    // this function will allow the player to chat with NPCs which are in the
+    // game or whatever
+
+    // init names to NULL
+    for (CurNPC = 0; CurNPC < MAX_NPCS; CurNPC++)
+    {
+      pszNPCNames[CurNPC] = NULL;
+      pszNPCIndex[CurNPC] = NULL;
+    }
+
+    NPCInfo = malloc(sizeof(struct NPCInfo));
+    CheckMem(NPCInfo);
+
+    // go through each NPC file
+    for (CurFile = 0; CurFile < MAX_NPCFILES; CurFile++)
+    {
+      if (IniFile.pszNPCFileName[CurFile] == NULL)
+        break;
+
+      // get NPCs from npcs.dat, create index table of index numbers
+      MyOpen(IniFile.pszNPCFileName[CurFile], "rb", &FileHeader);
+      if (!FileHeader.fp)  break;      // couldn't open file, break
+
+      for (CurNPC = 0;; CurNPC++)
+      {
+        Offset = (long)CurNPC*sizeof(struct NPCInfo) + FileHeader.lStart;
+
+        if (Offset >= FileHeader.lEnd)
+          break;
+
+        if (fseek(FileHeader.fp, Offset, SEEK_SET))
+          break;  // no more NPCs to read
+
+        if (fread(NPCInfo, sizeof(struct NPCInfo), 1, FileHeader.fp) == 0)
+          break;  // no more NPCs in file
+
+        // get his index
+        NPC_GetNPCNdx(NPCInfo, &NPCNdx);
+
+        // is he in town? AND in this menu?
+        if (NPCNdx.Status != NPCS_HERE || NPCNdx.WhereWander != WhichMenu)
+          continue; // no, not here
+
+        // in future -- is this town same town as the NPC?
+
+        // yes, he is in this menu, add to index
+        pszNPCIndex[ NPCsFound ] = MakeStr( strlen(NPCInfo->szIndex) + 1);
+        strcpy(pszNPCIndex[ NPCsFound ], NPCInfo->szIndex);
+        pszNPCNames[ NPCsFound ] = MakeStr(strlen(NPCInfo->szName) + 1);
+        strcpy(pszNPCNames[ NPCsFound ], NPCInfo->szName);
+        NPCsFound++;
+      }
+      fclose(FileHeader.fp);
+
+      if (NPCsFound == MAX_NPCS)
+        break;
+    }
+
+    free(NPCInfo);
+
+    if (NPCsFound == 0)
+    {
+      rputs("|07You found no villagers in the area.\n%P");
+      return;
+    }
+
+    for (;;)
+    {
+      rputs("\n |0BYou scan the area for villagers . . .\n");
+      rputs(ST_LONGDIVIDER);
+      for (CurNPC = 0; CurNPC < NPCsFound; CurNPC++)
+      {
+        sprintf(szString, " |0A(|0B%c|0A) |0C%s\n", CurNPC + 'A', pszNPCNames[ CurNPC ]);
+        rputs(szString);
+        szKeys[CurNPC] = CurNPC + 'A';
+      }
+      szKeys[CurNPC] = 'Q';
+      szKeys[CurNPC + 1] = '\r';
+      szKeys[CurNPC + 2] = '\n';
+      szKeys[CurNPC + 3] = 0;
+
+      rputs(" |0A(|0BQ|0A) |0CQuit\n\n");
+      sprintf(szString, " |0B%d |0Achat(s) left\n", MAX_CHATSPERDAY - PClan->ChatsToday);
+      rputs(szString);
+      rputs(ST_LONGDIVIDER);
+      rputs(" |0GChoose one|0E> |0FQuit");
+
+      // show them to player, allow him to choose one until [Q] Quit
+
+      cInput = od_get_answer(szKeys);
+
+      if (cInput == 'Q' || cInput == '\r' || cInput == '\n')
+      {
+        rputs("\n\n");
+        break;  // done
+      }
+
+      sprintf(szString, "\b\b\b\b    \b\b\b\b%s\n\n", pszNPCNames[ cInput - 'A']);
+      rputs(szString);
+
+      // if not enough chats, don't let him chat
+      if (PClan->ChatsToday == MAX_CHATSPERDAY)
+      {
+        rputs("\n|15You have chatted enough already today.\n%P");
+        continue;
+      }
+
+      // chat with him using index value
+      NPC_ChatNPC(pszNPCIndex[ cInput - 'A' ]);
+
+      // decrease chats today
+      PClan->ChatsToday++;
+    }
+
+    // free up name memory used
+    for (CurNPC = 0; CurNPC < MAX_NPCS; CurNPC++)
+    {
+      if (pszNPCNames[CurNPC])
+        free(pszNPCNames[CurNPC]);
+
+      if (pszNPCIndex[CurNPC])
+        free(pszNPCIndex[CurNPC]);
+    }
+  }
+
+  void NPC_ResetNPCClan ( struct clan *NPCClan )
+  {
+    _INT16 iTemp;
+
+    // free up enemies found
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      if (NPCClan->Member[iTemp])
+      {
+        free(NPCClan->Member[iTemp]);
+        NPCClan->Member[iTemp] = NULL;
+      }
+
+    NPCClan->szName[0] = 0;
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      NPCClan->Member[iTemp] = NULL;
+
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+      NPCClan->Items[iTemp].Available = FALSE;
+  }
+
+  void NPC_GetNPC( struct pc *NPC, char *szFileName, _INT16 WhichNPC )
+  {
+    long Offset;
+    struct FileHeader FileHeader;
+
+    MyOpen(szFileName, "rb", &FileHeader);
+    if (!FileHeader.fp)
+    {
+      DisplayStr("Error finding NPC file.\n");
+      return;
+    }
+    Offset = (long)WhichNPC * (long)sizeof(struct pc) + (long)sizeof(_INT16)*MAX_MONSTERS +
+      FileHeader.lStart;
+    fseek(FileHeader.fp, Offset, SEEK_SET);
+    fread(NPC, sizeof(struct pc), 1, FileHeader.fp);
+    fclose(FileHeader.fp);
+  }
+
+
+  void NPC_AddNPCMember ( char *szIndex )
+  {
+    struct pc *TmpPC;
+    struct NPCInfo *NPCInfo;
+    struct NPCNdx NPCNdx;
+    _INT16 EmptySlot, CurFile, CurNPC, iTemp, WhichNPC;
+    BOOL FoundNPC = FALSE;
+      FILE *fpNPCDat, *fpNPCNdx;
+    long Offset, SeekOffset;
+      struct FileHeader FileHeader, PCFile;
+
+    // This function ASSUMES the user has an empty slot already!!
+
+    // find empty slot first
+    for (iTemp = Game.Data->MaxPermanentMembers; iTemp < 6; iTemp++)
+      if (PClan->Member[iTemp] == NULL)
+        break;
+
+    EmptySlot = iTemp;
+
+    NPCInfo = malloc(sizeof(struct NPCInfo));
+    CheckMem(NPCInfo);
+
+    // go into NPC.DAT file, get npc index in the npc.pc file
+    // set npc as a member of this clan
+    // add npc to this clan's memberlist
+
+    // first, find NPC in file somewhere
+    for (CurFile = 0; CurFile < MAX_NPCFILES; CurFile++)
+    {
+      if (!IniFile.pszNPCFileName[CurFile]) break;
+
+      MyOpen(IniFile.pszNPCFileName[CurFile], "rb", &FileHeader);
+      if (!FileHeader.fp)  continue;
+
+      /* find him in the file */
+      for (CurNPC = 0; ; CurNPC++)
+      {
+        SeekOffset = (long)CurNPC * (long)sizeof(struct NPCInfo) +
+          FileHeader.lStart;
+
+        if (SeekOffset >= FileHeader.lEnd)
+          break;
+
+        if (fseek(FileHeader.fp, SeekOffset, SEEK_SET))
+          break;
+
+        // save offset for later
+        Offset = ftell(FileHeader.fp);
+
+        fread(NPCInfo, sizeof(struct NPCInfo), 1, FileHeader.fp);
+
+        // one we want?
+        if (stricmp(NPCInfo->szIndex, szIndex) == 0)
+        {
+          // yes
+          FoundNPC = TRUE;
+          break;
+        }
+      }
+      fclose(FileHeader.fp);
+
+      if (FoundNPC)  break;
+    }
+
+    if (FoundNPC == FALSE)
+    {
+      rputs("NPC not found\n");
+      free(NPCInfo);
+      return;
+    }
+
+    NPC_GetNPCNdx(NPCInfo, &NPCNdx);
+
+    NPCNdx.InClan = TRUE;
+    NPCNdx.ClanID[0] = PClan->ClanID[0];
+    NPCNdx.ClanID[1] = PClan->ClanID[1];
+
+    NPC_UpdateNPCNdx(NPCInfo->szIndex, &NPCNdx);
+
+    MyOpen(NPCInfo->szMonFile, "rb", &PCFile);
+    if (!PCFile.fp)
+    {
+  //      rputs("Error finding NPC.\n");
+      free(NPCInfo);
+      return;
+    }
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+    // seek to it but make sure you skip the monster index at start of pc file
+    SeekOffset = (long)NPCInfo->NPCPCIndex * (long)sizeof(struct pc) + (long)sizeof(_INT16)*MAX_MONSTERS
+      + PCFile.lStart;
+    fseek(PCFile.fp, SeekOffset, SEEK_SET);
+
+    fread(TmpPC, sizeof(struct pc), 1, PCFile.fp);
+    fclose(PCFile.fp);
+
+    PClan->Member[EmptySlot] = malloc(sizeof(struct pc));
+    CheckMem(PClan->Member[EmptySlot]);
+    // CopyPC(PClan->Member[EmptySlot], TmpPC);
+    *PClan->Member[EmptySlot] = *TmpPC;
+    PClan->Member[EmptySlot]->MyClan = PClan;
+    free(TmpPC);
+    free(NPCInfo);
+	(void)WhichNPC;
+	(void)fpNPCDat;
+	(void)fpNPCNdx;
+  }
+
diff --git a/src/doors/clans-src/npc.h b/src/doors/clans-src/npc.h
new file mode 100644
index 0000000000000000000000000000000000000000..8ad40a2875be9d10b1379d471c6b5f7dac4b3da0
--- /dev/null
+++ b/src/doors/clans-src/npc.h
@@ -0,0 +1,10 @@
+
+  void NPC_AddNPCMember ( char *szIndex );
+  void NPC_UpdateNPCNdx ( char *szIndex, struct NPCNdx *NPCNdx );
+  void NPC_GetNPCNdx ( struct NPCInfo *NPCInfo, struct NPCNdx *NPCNdx );
+  void NPC_GetNPC( struct pc *NPC, char *szFileName, _INT16 WhichNPC );
+  void NPC_ChatNPC ( char *szIndex );
+  void NPC_ResetNPCClan ( struct clan *NPCClan );
+
+  void NPC_Maint ( void );
+  void ChatVillagers ( _INT16 WhichMenu );
diff --git a/src/doors/clans-src/packet.h b/src/doors/clans-src/packet.h
new file mode 100644
index 0000000000000000000000000000000000000000..e1855c969e01a5adebb6b1cfb7dc078d5a6a7243
--- /dev/null
+++ b/src/doors/clans-src/packet.h
@@ -0,0 +1,21 @@
+/* packet types */
+#define PT_CLANMOVE     0
+#define PT_DATAOK       1
+#define PT_RESET        2
+#define PT_GOTRESET     3
+#define PT_RECON        4
+#define PT_GOTRECON     5
+#define PT_NEWUSER      6
+#define PT_DELUSER      7
+#define PT_ADDUSER      8
+#define PT_SUBUSER      9           // subtract user, opposite of add user :)
+#define PT_COMEBACK     10          // come back option
+#define PT_MSJ          11          // message posted
+#define PT_ATTACK       12          // InterBBS attack -- yeah!
+#define PT_ATTACKRESULT 13
+#define PT_SPY          14
+#define PT_SPYRESULT    15
+#define PT_SCOREDATA    16
+#define PT_SCORELIST    17
+#define PT_NEWNDX       18
+#define PT_ULIST        19
diff --git a/src/doors/clans-src/parsing.c b/src/doors/clans-src/parsing.c
new file mode 100644
index 0000000000000000000000000000000000000000..059ec5d3b8ccb8c77e86e986375f6252b4853999
--- /dev/null
+++ b/src/doors/clans-src/parsing.c
@@ -0,0 +1,239 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Parsing functions
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+
+#include "defines.h"
+#include "language.h"
+
+// ------------------------------------------------------------------------- //
+
+  void Strip ( char *szString )
+    /*
+     * This function will strip any leading and trailing spaces from the
+     * string.
+     */
+  {
+    char NewString[400], *pcCh;
+
+    pcCh = szString;
+
+    /* get rid of spacing */
+    while ( isspace(*pcCh))
+      pcCh++;
+
+    strcpy(NewString, pcCh);
+
+    /* get rid of trailing spaces */
+    pcCh = &NewString[ strlen(NewString) - 1];
+
+    while (isspace(*pcCh))
+      pcCh--;
+
+    pcCh++;
+    *pcCh = 0;
+
+    strcpy(szString, NewString);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void ParseLine ( char *szString)
+    /*
+     * This function will take a string and remove comments (#'s and ;'s) and
+     * then remove leading and trailing whitespaces.  Anything in quotes is
+     * ignored.
+     */
+  {
+    char *pcCurrentPos;
+    BOOL MetQuote = FALSE;
+
+    pcCurrentPos = szString;
+
+    while(*pcCurrentPos)
+    {
+      if (*pcCurrentPos == '"')
+        MetQuote = !MetQuote;
+
+      if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r' || *pcCurrentPos==';'
+        || *pcCurrentPos == '#')
+      {
+        if (MetQuote == FALSE)
+        {
+          *pcCurrentPos='\0';
+          break;
+        }
+      }
+      ++pcCurrentPos;
+    }
+
+    pcCurrentPos = szString;
+    while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+    strcpy(szString, pcCurrentPos);
+
+    // parse second time to get rid of comment's end
+    Strip(szString);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void GetToken ( char *szString, char *szToken )
+    /*
+     * From the string, this gets the next available token and removes it
+     * from the string so that the string begins with the NEXT token.
+     */
+  {
+    char *pcCurrentPos;
+    unsigned _INT16 uCount;
+
+    /* Ignore all of line after comments or CR/LF char */
+    pcCurrentPos=(char *)szString;
+    while(*pcCurrentPos)
+    {
+      if(*pcCurrentPos=='\n' || *pcCurrentPos=='\r')
+      {
+        *pcCurrentPos='\0';
+        break;
+      }
+      ++pcCurrentPos;
+    }
+
+    /* Search for beginning of first token on line */
+    pcCurrentPos = (char *)szString;
+    while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+    /* If no token was found, proceed to process the next line */
+    if(!*pcCurrentPos)
+    {
+      szToken[0] = 0;
+      szString[0] = 0;
+      return;
+    }
+
+    /* Get first token from line */
+    uCount=0;
+    while(*pcCurrentPos && !isspace(*pcCurrentPos))
+    {
+      if(uCount<MAX_TOKEN_CHARS) szToken[uCount++]=*pcCurrentPos;
+      ++pcCurrentPos;
+    }
+    if(uCount<=MAX_TOKEN_CHARS)
+      szToken[uCount]='\0';
+    else
+      szToken[MAX_TOKEN_CHARS]='\0';
+
+    /* Find beginning of configuration option parameters */
+    while(*pcCurrentPos && isspace(*pcCurrentPos)) ++pcCurrentPos;
+
+    /* Trim trailing spaces from setting string */
+	if (strlen(pcCurrentPos)>0)  {
+      for(uCount=strlen(pcCurrentPos)-1;uCount>0;--uCount)
+      {
+        if(isspace(pcCurrentPos[uCount]))
+        {
+          pcCurrentPos[uCount]='\0';
+        }
+        else
+        {
+          break;
+        }
+      }
+	}
+
+    strcpy(szString, pcCurrentPos);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  BOOL iscodechar( char c )
+    /*
+     * Returns TRUE if the character is a digit or within 'A' and 'F'
+     * (Used mainly to see if it is a valid char for `xx codes.
+     *
+     */
+  {
+    if (  (c <= 'F' && c >= 'A')  ||  (isdigit(c) && isascii(c)) )
+      return TRUE;
+    else
+      return FALSE;
+  }
+
+
+  void RemovePipes( char *pszSrc, char *pszDest)
+    /*
+     * This function removes any colour codes from the string and outputs the
+     * result to the destination.
+     *
+     */
+  {
+    while (*pszSrc)
+    {
+      if (*pszSrc == '|' && isdigit(*(pszSrc+1)) && isalnum(*(pszSrc+2)))
+        pszSrc += 3;
+      else if (*pszSrc == '`' && iscodechar(*(pszSrc+1)) && iscodechar(*(pszSrc+2)) )
+        pszSrc += 3;
+      else
+      {
+        /* else is normal */
+        *pszDest = *pszSrc;
+        ++pszSrc;
+        ++pszDest;
+      }
+    }
+    *pszDest = 0;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void PadString ( char *szString, _INT16 PadLength )
+    /*
+     * This takes the string and pads it with spaces.
+     */
+  {
+    _INT16 iTemp;
+    char szTemp[255], *pc;
+
+    RemovePipes(szString, szTemp);
+
+    pc = strchr(szString, 0);
+
+    // if less than the required length, pad
+    if ((signed)strlen(szTemp) < PadLength)
+    {
+      for (iTemp = 0; iTemp < PadLength - ((signed)strlen(szTemp)); iTemp++)
+      {
+        *pc = ' ';
+        pc++;
+      }
+
+      *pc = 0;
+    }
+  }
+
diff --git a/src/doors/clans-src/parsing.h b/src/doors/clans-src/parsing.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0959eba18fb0ba6ff2ce9536707921668df35b9
--- /dev/null
+++ b/src/doors/clans-src/parsing.h
@@ -0,0 +1,38 @@
+
+  void Strip ( char *szString );
+    /*
+     * This function will strip any leading and trailing spaces from the
+     * string.
+     */
+
+  void ParseLine ( char *szString );
+    /*
+     * This function will take a string and remove comments (#'s and ;'s) and
+     * then remove leading and trailing whitespaces.  Anything in quotes is
+     * ignored.
+     */
+
+  void GetToken ( char *szString, char *szToken );
+    /*
+     * From the string, this gets the next available token and removes it
+     * from the string so that the string begins with the NEXT token.
+     */
+
+  void RemovePipes( char *pszSrc, char *pszDest);
+    /*
+     * This function removes any colour codes from the string and outputs the
+     * result to the destination.
+     *
+     */
+
+  void PadString ( char *szString, _INT16 PadLength );
+    /*
+     * This takes the string and pads it with spaces.
+     */
+
+  __BOOL iscodechar( char c );
+    /*
+     * Returns TRUE if the character is a digit or within 'A' and 'F'
+     * (Used mainly to see if it is a valid char for `xx codes.
+     *
+     */
diff --git a/src/doors/clans-src/pawn.c b/src/doors/clans-src/pawn.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff4699f50508e71ba0d053d0e896308938480cab
--- /dev/null
+++ b/src/doors/clans-src/pawn.c
@@ -0,0 +1,522 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Pawn Shop ADT
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+
+#include "structs.h"
+#include "input.h"
+#include "door.h"
+#include "language.h"
+#include "mstrings.h"
+#include "misc.h"
+#include "help.h"
+#include "myopen.h"
+#include "items.h"
+#include "user.h"
+#include "video.h"
+
+#define MAX_PSITEMS 	100
+#define MAX_PSITEMAGE	2
+
+extern struct Language *Language;
+extern struct clan *PClan;
+extern struct village Village;
+extern struct system System;
+
+
+  _INT16 PS_GetOpenItemSlot ( struct clan *Clan )
+  {
+    // return -1 if no more open slots
+
+    _INT16 iTemp;
+
+    // see if he has room to carry it
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+    {
+      if (Clan->Items[iTemp].Available == FALSE)
+        break;
+    }
+    if (iTemp == MAX_ITEMS_HELD)
+    {
+      /* no more room in inventory */
+      return -1;
+    }
+    else
+      return iTemp;
+  }
+
+  void PS_Init( struct item_data **PS_Items)
+  {
+    _INT16 iTemp, CurItem;
+    FILE *fp;
+
+    for (iTemp = 0; iTemp < MAX_PSITEMS; iTemp++)
+    {
+      PS_Items[iTemp] = NULL;
+    }
+
+    fp = _fsopen("pawn.dat", "rb", SH_DENYWR);
+    if (!fp)
+    {
+      return;
+    }
+
+    for (CurItem = 0; CurItem < MAX_PSITEMS; CurItem++)
+    {
+      PS_Items[CurItem] = malloc(sizeof(struct item_data));
+      CheckMem(PS_Items[CurItem]);
+
+      if (!EncryptRead(PS_Items[CurItem], sizeof(struct item_data), fp, XOR_ITEMS))
+      {
+        free(PS_Items[CurItem]);
+        PS_Items[CurItem] = NULL;
+        break;
+      }
+    }
+
+    fclose(fp);
+  }
+
+  void PS_Close( struct item_data **PS_Items)
+  {
+    FILE *fp;
+    _INT16 CurItem;
+
+    // write to PAWN.DAT only those items which exist
+    fp = _fsopen("pawn.dat", "wb", SH_DENYWR);
+
+    if (fp)
+    {
+      for (CurItem = 0; CurItem < MAX_PSITEMS; CurItem++)
+      {
+        if (PS_Items[CurItem])
+          EncryptWrite(PS_Items[CurItem], sizeof(struct item_data), fp, XOR_ITEMS);
+      }
+      fclose(fp);
+    }
+
+    for (CurItem = 0; CurItem < MAX_PSITEMS; CurItem++)
+    {
+      if (PS_Items[CurItem])
+      {
+        free(PS_Items[CurItem]);
+        PS_Items[CurItem] = NULL;
+      }
+    }
+  }
+
+  void PS_List(struct item_data *PS_Items[MAX_PSITEMS], _INT16 ItemType)
+  {
+    // list items of a specified type -- in future use type
+
+    _INT16 CurItem, ItemsShown = 0;
+    char szString[128];
+
+    for (CurItem = 0; CurItem < MAX_PSITEMS; CurItem++)
+    {
+      if (PS_Items[CurItem])
+      {
+        sprintf(szString, ST_PAWN6,
+          CurItem+1, PS_Items[CurItem]->szName);
+        rputs(szString);
+
+        if (ItemsShown == 60)
+          rputs("\n%P");
+
+        ItemsShown++;
+      }
+      else
+        continue;
+
+      if (ItemsShown%3 == 0)
+        rputs("\n");
+    }
+
+    if (ItemsShown == 0)
+      rputs(ST_PAWN13);
+    else if (ItemsShown%3 != 0)
+      rputs("\n");
+  }
+
+
+  void PS_Buy( struct item_data *PS_Items[MAX_PSITEMS], _INT16 ItemType )
+  {
+    BOOL Done;
+    char cKey;
+    _INT16 ItemIndex;
+    long lCost;
+    char *szTheOptions[5], szString[50];
+    _INT16 iTemp, EmptySlot;
+
+    LoadStrings(1190, 5, szTheOptions);
+
+    Done = FALSE;
+    while (!Done)
+    {
+      switch(GetChoice("", ST_PAWN0, szTheOptions, "LQBX?", 'Q', FALSE))
+      {
+        case 'Q' :
+          Done = TRUE;
+          break;
+
+        case 'L' :  // list items
+          PS_List(PS_Items, ItemType);
+          break;
+
+        case 'X' :  // examine item
+          ItemIndex = GetLong(ST_PAWN1, 0, MAX_PSITEMS);
+
+          if (ItemIndex == 0) break;
+
+          ItemIndex--;
+
+          if (PS_Items[ItemIndex] == NULL)
+          {
+            rputs(ST_INVALIDITEM);
+            break;
+          }
+
+          // show item
+          ShowItemStats(PS_Items[ItemIndex], NULL);
+          break;
+        case 'B' :  // buy an item
+          // find open slot
+          EmptySlot = PS_GetOpenItemSlot ( PClan );
+
+          if (EmptySlot == -1)
+          {
+            rputs(ST_PAWN2);
+            break;
+          }
+
+          ItemIndex = GetLong(ST_PAWN3, 0, MAX_PSITEMS);
+
+          if (ItemIndex == 0) break;
+
+          ItemIndex--;
+
+          if (PS_Items[ItemIndex] == NULL)
+          {
+            rputs(ST_INVALIDITEM);
+            break;
+          }
+
+          // show item
+          ShowItemStats(PS_Items[ItemIndex], NULL);
+
+          lCost = PS_Items[ItemIndex]->lCost -
+            (PS_Items[ItemIndex]->lCost*10)/100L +
+            (PS_Items[ItemIndex]->lCost*RANDOM(10))/100L;
+
+          sprintf(szString, ST_PAWN4, lCost);
+
+          if (YesNo(szString) == NO)  break;
+
+          // see if enough gold
+          if (PClan->Empire.VaultGold < lCost)
+          {
+            rputs(ST_PAWN5);
+            break;
+          }
+
+          // else add to items, remove cash
+          PClan->Empire.VaultGold -= lCost;
+
+          PClan->Items[EmptySlot] = *PS_Items[ItemIndex];
+
+          free(PS_Items[ItemIndex]);
+          PS_Items[ItemIndex] = NULL;
+          break;
+      }
+    }
+
+    // use B key to buy an item
+      // if no more room in inventory, tell user
+      // prompt user for item #
+			// make sure it's legal
+			// show stats of item
+			// ask if user wants to buy for sure
+			// if so, add item to user's inventory
+			//	 remove from PS_Items[] by freeing up that memory
+	(void)cKey;
+	(void)iTemp;
+  }
+
+  void PS_Sell( struct item_data *PS_Items[MAX_PSITEMS] )
+  {
+    // allow user to sell an item he owns
+
+    // allow user to list his own items, examine them, etc.
+
+    // use S key to buy an item
+      // if no more room in inventory, tell user they aren't buying
+      // prompt user for item #
+        // make sure it's legal -- if it's in use, tell him he to unequip it
+        // show stats of item, show how much he'll buy it for
+        // ask if user wants to sell it for sure
+        // if so, add item to PS_Items[] (find NULL and get mem for it)
+        //   remove from user's item list, make Item->Date = Today;
+
+
+    BOOL Done;
+    char cKey;
+    _INT16 ItemIndex, iTemp, ItemSlot, CurItem;
+    long lCost;
+    char *szTheOptions[6], szString[128];
+
+    LoadStrings(1195, 5, szTheOptions);
+    szTheOptions[5] = "Sell All";
+
+    sprintf(szString, "|0CAt its current level, this shop can take in up to |0B%d |0Citems.\n\n",
+      20*Village.Data->PawnLevel);
+    rputs(szString);
+
+    Done = FALSE;
+    while (!Done)
+    {
+      switch(GetChoice("", ST_PAWN7, szTheOptions, "LQSX?A", 'Q', FALSE))
+      {
+        case 'Q' :
+          Done = TRUE;
+          break;
+
+        case 'L' :  // list items
+          ListItems(PClan);
+          break;
+
+        case 'X' :  // examine item
+          ItemIndex = GetLong(ST_PAWN8, 0, 30);
+
+          if (ItemIndex == 0) break;
+
+          ItemIndex--;
+
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_INVALIDITEM);
+            break;
+          }
+
+          // show item
+          ShowItemStats(&PClan->Items[ItemIndex], PClan);
+          break;
+
+        case 'S' :  // sell item
+          // find index of next item slot open
+          for (CurItem = 0; CurItem < 20*Village.Data->PawnLevel; CurItem++)
+          {
+            if (PS_Items[CurItem] == NULL)  break;
+          }
+
+          if (CurItem == 20*Village.Data->PawnLevel)
+          {
+            //sprintf(szString, "I'm sorry, we cannot accept any more items.\n\r");
+            rputs(ST_PAWN9);
+            break;
+          }
+          ItemSlot = CurItem;
+
+          ItemIndex = GetLong(ST_PAWN10, 0, 30);
+
+          if (ItemIndex == 0) break;
+
+          ItemIndex--;
+
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_INVALIDITEM);
+            break;
+          }
+
+          // show item
+          ShowItemStats(&PClan->Items[ItemIndex], PClan);
+
+          // if in use, tell him
+          if (PClan->Items[ItemIndex].UsedBy != 0)
+          {
+            rputs(ST_PAWN11);
+            break;
+          }
+
+          lCost = (PClan->Items[ItemIndex].lCost*3L)/4L +
+            (PClan->Items[ItemIndex].lCost*(long)RANDOM(15))/100L;
+
+          sprintf(szString, ST_PAWN12, lCost);
+
+          if (YesNo(szString) == NO) break;
+
+          // give him gold
+          PClan->Empire.VaultGold += lCost;
+
+          // get mem for it
+          PS_Items[ItemSlot] = malloc(sizeof(struct item_data));
+          CheckMem(PS_Items[ItemSlot]);
+
+          *PS_Items[ItemSlot] = PClan->Items[ItemIndex];
+
+          PS_Items[ItemSlot]->ItemDate = DaysSince1970(System.szTodaysDate);
+
+          // remove from user's item list
+          PClan->Items[ItemIndex].Available = FALSE;
+          break;
+        case 'A' :  // sell all
+          for (ItemIndex = 0; ItemIndex < MAX_ITEMS_HELD; ItemIndex++)
+          {
+            // skip this item if not available or in use
+            if (PClan->Items[ItemIndex].Available == FALSE ||
+              PClan->Items[ItemIndex].UsedBy)
+            {
+              continue;
+            }
+
+            // find index of next item slot open
+            for (CurItem = 0; CurItem < 20*Village.Data->PawnLevel; CurItem++)
+            {
+              if (PS_Items[CurItem] == NULL)  break;
+            }
+
+            if (CurItem == 20*Village.Data->PawnLevel)
+            {
+              // od_printf("I'm sorry, we cannot accept any more items.\n\r");
+              rputs(ST_PAWN9);
+              break;
+            }
+            ItemSlot = CurItem;
+
+            // show item
+            ShowItemStats(&PClan->Items[ItemIndex], PClan);
+
+            lCost = (PClan->Items[ItemIndex].lCost*3L)/4L +
+              (PClan->Items[ItemIndex].lCost*(long)RANDOM(15))/100L;
+
+            sprintf(szString, ST_PAWN12, lCost);
+
+            if (YesNo(szString) == NO) continue;
+
+            // give him gold
+            PClan->Empire.VaultGold += lCost;
+
+            // get mem for it
+            PS_Items[ItemSlot] = malloc(sizeof(struct item_data));
+            CheckMem(PS_Items[ItemSlot]);
+
+            *PS_Items[ItemSlot] = PClan->Items[ItemIndex];
+
+            PS_Items[ItemSlot]->ItemDate = DaysSince1970(System.szTodaysDate);
+
+            // remove from user's item list
+            PClan->Items[ItemIndex].Available = FALSE;
+          }
+          break;
+      }
+    }
+	(void)cKey;
+	(void)iTemp;
+  }
+
+  void PS_Maint ( void )
+  {
+    struct item_data *PS_Items[MAX_PSITEMS];
+    _INT16 CurItem;
+
+    DisplayStr("* PS_Maint()\n");
+
+    PS_Init(PS_Items);
+
+    // remove those items which are older than X days
+    for (CurItem = 0; CurItem < MAX_PSITEMS; CurItem++)
+    {
+      if (PS_Items[CurItem])
+      {
+        if ((DaysSince1970(System.szTodaysDate) - PS_Items[CurItem]->ItemDate) >= MAX_PSITEMAGE)
+        {
+          free(PS_Items[CurItem]);
+          PS_Items[CurItem] = NULL;
+        }
+      }
+    }
+
+    PS_Close(PS_Items);
+  }
+
+
+  // Pawn Shop Stuff goes here
+  void PawnShop ( void )
+  {
+    struct item_data *PS_Items[MAX_PSITEMS];
+    char *szTheOptions[5];
+    _INT16 iTemp;
+
+    LoadStrings(1180, 5, szTheOptions);
+
+    if (!PClan->PawnHelp)
+    {
+      PClan->PawnHelp = TRUE;
+      Help("Pawn Shop", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    // if no pawn shop, tell him
+    if (Village.Data->PawnLevel == 0)
+    {
+      rputs("\n|07There is currently no pawn shop in the village.\n%P");
+      return;
+    }
+
+    // load pawn shop data -- can't use
+    PS_Init(PS_Items);
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+      switch(GetChoice("Pawn Menu", ST_ENTEROPTION, szTheOptions, "BSVQ?", 'Q', TRUE))
+      {
+        case 'B' :    /* buy */
+          PS_Buy(PS_Items, 0);
+          break;
+        case 'S' :    /* sell items */
+          PS_Sell(PS_Items);
+          break;
+        case 'Q' :    /* return to previous menu */
+          PS_Close(PS_Items);
+          return;
+        case '?' :    /* redisplay options */
+          break;
+        case 'V' :    /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+      }
+    }
+	(void)iTemp;
+  }
diff --git a/src/doors/clans-src/pawn.h b/src/doors/clans-src/pawn.h
new file mode 100644
index 0000000000000000000000000000000000000000..6b5549c1e403250a831dab5a68e55371a7f2d3f1
--- /dev/null
+++ b/src/doors/clans-src/pawn.h
@@ -0,0 +1,4 @@
+
+  void PawnShop ( void );
+
+  void PS_Maint ( void );
diff --git a/src/doors/clans-src/pcedit.c b/src/doors/clans-src/pcedit.c
new file mode 100644
index 0000000000000000000000000000000000000000..1bca3345724efb21a912abcaced00aa169f6bb78
--- /dev/null
+++ b/src/doors/clans-src/pcedit.c
@@ -0,0 +1,988 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+// Player Editor for The Clans -- no promises that this works! 01/09/2002 au
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#if defined(_WIN32) || defined(DOS)
+# include <conio.h> /* Defines getch */
+#endif
+#endif /* !__FreeBSD__ */
+#ifdef __unix__
+#include "unix_wrappers.h"
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+/*#include <OpenDoor.h>*/
+#include "structs.h"
+#include "myopen.h"
+
+struct village Village;
+struct game Game;
+size_t entry_size = 0;
+
+void InitVillage ( void );
+void UpdateVillage ( void );
+void CheckMem ( void *Test );
+void RejectTrade ( struct TradeData *TradeData );
+void GetAlliances( struct Alliance *Alliances[MAX_ALLIANCES]);
+void UpdateAlliances( struct Alliance *Alliances[MAX_ALLIANCES]);
+void RemoveFromIPScores ( _INT16 ClanID[2] );
+BOOL ClanIDInList( _INT16 ClanID[2] );
+void RemoveFromUList(_INT16 ClanID[2]);
+void FreeClan( struct clan *Clan );
+BOOL GetClan ( _INT16 ClanID[2], struct clan *TmpClan );
+void DeleteClan (_INT16 ClanID[2]);
+void UpdateClan( struct clan *Clan );
+void InitGame ( void );
+#ifdef __unix__
+char getch(void);
+#endif
+
+
+#define TRUE_ENTRY_SIZE(x) \
+	(sizeof(struct clan) + ((x) * sizeof(struct pc)))
+
+#define GAME_DATAFILE "game.dat"
+#define VILLAGE_DATAFILE "village.dat"
+#define PLAYER_DATAFILE "clans.pc"
+#define NEW_PLAYER_DATAFILE "new.pc"
+#define ALLIANCE_DATAFILE "ally.dat"
+#define TEMP_FILENAME "tmp.$$$"
+#define TRADES_DATAFILE "trades.dat"
+#define MESSAGE_DATAFILE "clans.msj"
+#define USERLIST_DATAFILE "userlist.dat"
+#define IPSCORES_DATAFILE "ipscores.dat"
+
+
+int main ( void )
+{
+    FILE *fpPC;
+    long FileSize;
+    _INT16 NumClans, CurClan;
+    char cKey;
+    struct clan Clan;
+
+    system("stty raw");
+    system("stty opost onlcr");
+    printf(".PC (Player Clans) Editor for The Clans.  v0.10\n");
+    printf("\nThis PC editor should only be used on local games and only when\n");
+    printf("no one is currently playing.\n\n");
+    printf("Continue? [Yes]: ");
+    fflush(stdout);
+
+    do {
+        cKey = toupper(getch());
+    } while (!strchr("YN\n\r", cKey));
+
+    if (cKey == 'N')
+    {
+        printf("No\n\nProgram Aborted\n");
+        exit(0);
+    }
+    else
+        printf("Yes\n\n");
+
+    // WARNING:  Do not use while player is online!!
+
+    // if no PC file, boot to DOS
+
+    fpPC = fopen(PLAYER_DATAFILE,"rb");
+
+    if (!fpPC)
+    {
+        printf("No " PLAYER_DATAFILE " file!\n");
+        exit(0);
+    }
+
+    // open Village Data
+    InitVillage();
+
+	// open Game Data
+	InitGame();
+
+	entry_size = TRUE_ENTRY_SIZE(Game.Data->MaxPermanentMembers);
+
+    // otherwise, open file, get filesize
+    fseek(fpPC, 0L, SEEK_END);
+    FileSize = ftell(fpPC);
+    NumClans = FileSize / entry_size;
+
+    CurClan = 0;
+
+    for (;;)
+    {
+        if (fseek(fpPC, (CurClan * entry_size), SEEK_SET))
+        {
+            printf("fseek error\n");
+            break;
+        }
+
+        // get curuser from file
+		if (!EncryptRead(&Clan, sizeof(struct clan), fpPC, XOR_PC))
+        {
+            printf("Couldn't read any players\n");
+            break;
+        }
+
+        // display user stats
+        printf("ClanID  : %02d|%02d\n", Clan.ClanID[0], Clan.ClanID[1]);
+        printf("Clan    : %s\n", Clan.szName);
+        printf("User    : %s\n", Clan.szUserName);
+        printf("LastPlay: %s\n", Clan.szDateOfLastGame);
+
+        printf("\n\n ] next\n [ previous\n ! delete clan\n Q quit\n---------------------\n# ");
+	fflush(stdout);
+
+        // get key
+        do {
+            cKey = getch();
+        } while (!strchr("[]q!", cKey));
+
+        if (cKey == 'q')
+        {
+            printf("Quit\n\n");
+            break;
+        }
+        else if (cKey == '[')
+        {
+            printf("Previous Clan\n\n");
+
+            if (CurClan > 0)
+                CurClan--;
+            else
+            {
+                CurClan = NumClans-1;
+            }
+        }
+        else if (cKey == ']')
+        {
+            printf("Next Clan\n\n");
+
+            if (CurClan < NumClans-1)
+                CurClan++;
+            else
+                CurClan = 0;
+        }
+        else if (cKey == '!')
+        {
+            printf("Delete Clan\n\n");
+
+            fclose(fpPC);
+
+            printf("Deleting %s\n", Clan.szName);
+
+            DeleteClan(Clan.ClanID);
+
+            fpPC = fopen("clans.pc","r+b");
+
+            if (!fpPC)
+            {
+                printf("No CLANS.PC file!\n");
+                exit(0);
+            }
+
+            // otherwise, open file, get filesize
+            fseek(fpPC, 0L, SEEK_END);
+            FileSize = ftell(fpPC);
+            NumClans = FileSize / entry_size;
+
+            if (NumClans == 0)
+            {
+                printf("All players deleted\n");
+                break;
+            }
+
+            CurClan = 0;
+
+            UpdateVillage();
+        }
+
+        // [ = back one user
+            // if at user #1, figure out last user using FileSize/sizeof()
+            // choose that user as one to edit
+            // else if > #1, CurUser--
+
+        // ] = forward a user
+            // if already at end, CurUser = 0
+            // else
+
+        // ! = delete user
+            // close .PC file
+            // run DeleteClan
+            // reload file and get stats once more
+            // update village info now in case crash occurs later
+
+    }
+
+    fclose(fpPC);
+
+    // Update Village Data
+    UpdateVillage();
+
+	if (Village.Data)
+		free(Village.Data);
+	if (Game.Data)
+		free(Game.Data);
+	return 0;
+}
+
+void DeleteClan ( _INT16 ClanID[2])
+{
+	FILE *fpOldPC, *fpNewPC, *OldMessage, *NewMessage;
+	FILE *fpTradeFile;
+	long OldOffset;
+	char szFileName[40]/*, szString[128]*/;
+    _INT16 CurTradeData, iTemp, CurAlliance, CurMember;
+	struct TradeData TradeData;
+	struct clan *TmpClan;
+	struct Message Message;
+	BOOL FoundInPCFile = FALSE; 	// set to true if he was ever on this board
+	BOOL FoundNewCreator;
+	struct Alliance *Alliances[MAX_ALLIANCES];
+
+	// if this is the ruler of town, remove him
+	if (ClanID[0] == Village.Data->RulingClanId[0] &&
+		ClanID[1] == Village.Data->RulingClanId[1])
+	{
+		Village.Data->RulingClanId[0] = -1;
+		Village.Data->RulingClanId[1] = -1;
+		Village.Data->RulingDays = 0;
+        Village.Data->GovtSystem = GS_DEMOCRACY;
+
+		Village.Data->szRulingClan[0] = 0;
+
+		UpdateVillage();
+	}
+
+	// go through PC file
+    fpOldPC = fopen(PLAYER_DATAFILE, "rb");
+	if (fpOldPC)
+	{
+        fpNewPC = fopen(NEW_PLAYER_DATAFILE, "w+b");
+		if (!fpNewPC)
+		{
+            printf("Can't write to " NEW_PLAYER_DATAFILE "!\n");
+			exit(0);
+		}
+
+		/* allocate memory */
+		TmpClan = (struct clan *) malloc(sizeof(struct clan));
+		CheckMem(TmpClan);
+
+		for (;;)
+		{
+			/* go through each clan and write his info to new file and
+			   skip the clan in question if he is found */
+
+			if (EncryptRead(TmpClan, sizeof(struct clan), fpOldPC, XOR_PC) == 0)
+				break;
+
+			/* if this is him */
+			if (TmpClan->ClanID[0] == ClanID[0] &&
+				TmpClan->ClanID[1] == ClanID[1])
+			{
+                FoundInPCFile = TRUE;
+
+                fseek(fpOldPC, Game.Data->MaxPermanentMembers*sizeof(struct pc), SEEK_CUR);
+                continue;
+			}
+
+			// read in 6 members
+			for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+			{
+				TmpClan->Member[iTemp] = malloc(sizeof(struct pc));
+				EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fpOldPC, XOR_PC);
+			}
+
+			//=== modifications go here
+            // make it so that he is NOT voted for
+            if (TmpClan->ClanRulerVote[0] == ClanID[0] &&
+                TmpClan->ClanRulerVote[1] == ClanID[1])
+            {
+                TmpClan->ClanRulerVote[0] = TmpClan->ClanRulerVote[1] = -1;
+            }
+
+
+			// IN FUTURE: if ruler of an alliance, set new ruler if another
+			// member was found.  if none, remove alliance from list
+
+			//===
+
+			/* write new stuff to new file */
+			EncryptWrite(TmpClan, sizeof(struct clan), fpNewPC, XOR_PC);
+
+			for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+			{
+				EncryptWrite(TmpClan->Member[iTemp], sizeof(struct pc), fpNewPC, XOR_PC);
+				free(TmpClan->Member[iTemp]);
+			}
+		}
+
+		/* deallocate memory for PCs */
+		free(TmpClan);
+
+		fclose(fpOldPC);
+		fclose(fpNewPC);
+
+		/* delete old file, rename new one */
+        unlink(PLAYER_DATAFILE);
+        rename(NEW_PLAYER_DATAFILE, PLAYER_DATAFILE);
+	}
+
+	// go through msg file, set all his mail (to/from him) as deleted
+
+    strcpy(szFileName, MESSAGE_DATAFILE);
+
+	OldMessage = fopen(szFileName, "rb");
+	if (OldMessage) 		// MSJ file exists, so go on
+	{
+		NewMessage = fopen(TEMP_FILENAME, "wb");
+		if (!NewMessage)
+		{
+			return;
+		}
+
+		for (;;)
+		{
+			if (!EncryptRead(&Message, sizeof(struct Message), OldMessage, XOR_MSG))
+				break;
+
+			if ((Message.FromClanID[0] == ClanID[0] &&
+				 Message.FromClanID[1] == ClanID[1]) ||
+				(Message.ToClanID[0] == ClanID[0] &&
+				 Message.ToClanID[1] == ClanID[1]) )
+			{
+				// delete this message by skipping over it
+				fseek(OldMessage, Message.Data.Length, SEEK_CUR);
+			}
+			else
+			{
+				Message.Data.MsgTxt = malloc(Message.Data.Length);
+				CheckMem(Message.Data.MsgTxt);
+
+				// write it to new file
+				EncryptRead(Message.Data.MsgTxt, Message.Data.Length, OldMessage, XOR_MSG);
+
+				EncryptWrite(&Message, sizeof(Message), NewMessage, XOR_MSG);
+				EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, NewMessage, XOR_MSG);
+
+				free(Message.Data.MsgTxt);
+			}
+		}
+
+		fclose(NewMessage);
+		fclose(OldMessage);
+
+		// delete old, and rename new
+		unlink(szFileName);
+		rename(TEMP_FILENAME, szFileName);
+	}
+
+	// go through trades.dat, for each trade struct, see if trade is headed
+	// for him, if so, set trade as aborted, return goods to user sending
+
+	fpTradeFile = fopen(TRADES_DATAFILE, "r+b");
+
+	if (fpTradeFile)
+	{
+		for (CurTradeData = 0;;CurTradeData++)
+		{
+			if (fseek(fpTradeFile, (long)(CurTradeData * sizeof(struct TradeData)), SEEK_SET))
+				break;
+
+			OldOffset = ftell(fpTradeFile);
+
+			if (EncryptRead(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE) == 0)
+				break;
+
+			/* see if active */
+			if (TradeData.Active == FALSE)
+				continue;
+
+            if (TradeData.ToClanID[0] == ClanID[0] &&
+				TradeData.ToClanID[1] == ClanID[1])
+			{
+				// it's for this deleted player, so, rejecttrade
+                RejectTrade(&TradeData);
+
+				// write it to file
+				fseek(fpTradeFile, OldOffset, SEEK_SET);
+				EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+			}
+            else if (TradeData.FromClanID[0] == ClanID[0] &&
+				TradeData.FromClanID[1] == ClanID[1])
+			{
+				// trade is coming from this player, remove it
+				TradeData.Active = FALSE;
+				fseek(fpTradeFile, OldOffset, SEEK_SET);
+				EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+			}
+		}
+
+		fclose(fpTradeFile);
+	}
+
+
+    // remove from ALLY.DAT
+    GetAlliances(Alliances);
+
+	// see if this clan is the creator of an alliance
+	for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+	{
+		if (Alliances[CurAlliance] &&
+			Alliances[CurAlliance]->CreatorID[0] == ClanID[0] &&
+			Alliances[CurAlliance]->CreatorID[1] == ClanID[1])
+		{
+			// find a new "leader"
+			FoundNewCreator = FALSE;
+			for (CurMember = 0; CurMember < MAX_ALLIANCEMEMBERS; CurMember++)
+			{
+				// if this is an actual member AND it's not the deleted clan,
+				// see if
+				if ((Alliances[CurAlliance]->Member[CurMember][0] != -1 &&
+					 Alliances[CurAlliance]->Member[CurMember][1] != -1) &&
+					!(Alliances[CurAlliance]->Member[CurMember][0] == ClanID[0] &&
+					 Alliances[CurAlliance]->Member[CurMember][1] == ClanID[1]))
+				{
+					FoundNewCreator = TRUE;
+					Alliances[CurAlliance]->CreatorID[0] = Alliances[CurAlliance]->Member[CurMember][0];
+					Alliances[CurAlliance]->CreatorID[1] = Alliances[CurAlliance]->Member[CurMember][1];
+
+					// FIXME: write him a message in future?
+				}
+			}
+
+			if (FoundNewCreator == FALSE)
+			{
+				// delete this alliance since no new ruler
+				free(Alliances[CurAlliance]);
+				Alliances[CurAlliance] = NULL;
+			}
+		}
+	}
+
+	// remove from any and all alliances he was in
+	for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+	{
+		if (Alliances[CurAlliance])
+		{
+			for (CurMember = 0; CurMember < MAX_ALLIANCEMEMBERS; CurMember++)
+			{
+				if (Alliances[CurAlliance]->Member[CurMember][0] == ClanID[0] &&
+					Alliances[CurAlliance]->Member[CurMember][1] == ClanID[1])
+				{
+					Alliances[CurAlliance]->Member[CurMember][0] = -1;
+					Alliances[CurAlliance]->Member[CurMember][1] = -1;
+				}
+			}
+		}
+	}
+
+	// deinit alliances and update to file
+    UpdateAlliances(Alliances);
+
+	// free up mem used by alliances
+	for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+		if (Alliances[CurAlliance])
+			free(Alliances[CurAlliance]);
+
+	// remove from list of clan names, remove from list of user names
+    RemoveFromUList(ClanID);
+
+    // remove from high scores list
+    RemoveFromIPScores(ClanID);
+}
+
+void InitVillage ( void )
+{
+	FILE *fpVillage;
+/*    char ColorScheme[23] = {
+            6,14, 7, 5, 13,7, 5, 8, 3, 8,     5, 14,6, 4, 12,   4,12,3,
+            6,0,0,  1, 9};
+	char FlagScheme[3] = { 12, 15, 9 }; */
+/*	_INT16 iTemp;*/
+
+	Village.Data = (struct village_data *) malloc (sizeof(struct village_data));
+	CheckMem(Village.Data);
+
+	/* try opening it for share */
+    fpVillage = fopen(VILLAGE_DATAFILE, "rb");
+	if (!fpVillage)
+	{
+        printf("Error opening " VILLAGE_DATAFILE "!\n");
+        exit(0);
+	}
+	else
+		EncryptRead(Village.Data, (long)sizeof(struct village_data), fpVillage, XOR_VILLAGE);
+
+	fclose(fpVillage);
+}
+
+void UpdateVillage ( void )
+{
+	FILE *fpVillage;
+
+	/* NOTE: Village data held in memory (global) is NOT accurate if this game
+	   is played in multinode since the other node could write new info to
+	   the village.dat.  Only use Village struct for reference and update it
+	   if you want to display info */
+
+	/* try opening it for share */
+    fpVillage = fopen(VILLAGE_DATAFILE, "wb");
+	if (!fpVillage)
+	{
+        printf("Error opening " VILLAGE_DATAFILE "!\n");
+        exit(0);
+	}
+
+	EncryptWrite(Village.Data, (long)sizeof(struct village_data), fpVillage, XOR_VILLAGE);
+
+	fclose(fpVillage);
+}
+
+void CheckMem ( void *Test )
+{
+	if (Test == NULL)
+	{
+        printf("\aCheckmem Failed!\n");
+		exit(-1);
+	}
+}
+
+void RejectTrade ( struct TradeData *TradeData )
+{
+    struct clan *TmpClan;
+
+    TradeData->Active = FALSE;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    GetClan(TradeData->FromClanID, TmpClan);
+
+    TmpClan->Empire.VaultGold += TradeData->Giving.Gold;
+    TmpClan->Empire.Army.Followers += TradeData->Giving.Followers;
+    TmpClan->Empire.Army.Footmen += TradeData->Giving.Footmen;
+    TmpClan->Empire.Army.Axemen += TradeData->Giving.Axemen;
+    TmpClan->Empire.Army.Knights += TradeData->Giving.Knights;
+
+    /* this ensures the file is zeroed for cheaters -- improve later */
+    TradeData->Giving.Gold = 0L;
+    TradeData->Giving.Followers = 0L;
+    TradeData->Giving.Footmen = 0L;
+    TradeData->Giving.Axemen = 0L;
+    TradeData->Giving.Knights = 0L;
+    TradeData->Giving.Catapults = 0L;
+
+    UpdateClan(TmpClan);
+
+    FreeClan(TmpClan);
+}
+
+void GetAlliances( struct Alliance *Alliances[MAX_ALLIANCES])
+{
+	FILE *fp;
+	_INT16 iTemp;
+
+	// init alliances as NULLs
+	for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		Alliances[iTemp] = NULL;
+
+	fp = fopen(ALLIANCE_DATAFILE, "rb");
+	if (fp)
+	{
+		for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		{
+			Alliances[iTemp] = malloc(sizeof(struct Alliance));
+			CheckMem(Alliances[iTemp]);
+
+			if (EncryptRead(Alliances[iTemp], sizeof(struct Alliance), fp, XOR_ALLIES) == 0)
+			{
+				// no more alliances to read in
+				free(Alliances[iTemp]);
+				Alliances[iTemp] = NULL;
+				break;
+			}
+		}
+		fclose(fp);
+	}
+}
+
+void UpdateAlliances( struct Alliance *Alliances[MAX_ALLIANCES])
+{
+	FILE *fp;
+	_INT16 iTemp;
+
+	fp = fopen(ALLIANCE_DATAFILE, "wb");
+	if (fp)
+	{
+		for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		{
+			if (Alliances[iTemp] == NULL)
+				continue;
+
+			EncryptWrite(Alliances[iTemp], sizeof(struct Alliance), fp, XOR_ALLIES);
+		}
+		fclose(fp);
+	}
+}
+
+void RemoveFromUList(_INT16 ClanID[2])
+{
+    // open file for r+b
+    // scan file for ClanID
+    // set user as deleted
+    // close file
+
+    FILE *fpOldUList, *fpNewUList;
+    struct UserInfo User;
+
+    // if this guy is NOT in our list, then we don't need to do this
+    if (ClanIDInList(ClanID) == FALSE)
+        return;
+
+    // open user file
+    fpOldUList = fopen(USERLIST_DATAFILE, "rb");
+    if (!fpOldUList)    // no user list at all
+        return;
+
+    fpNewUList = fopen(TEMP_FILENAME, "wb");
+    // FIXME: assume file is opened
+
+    for (;;)
+    {
+		if (EncryptRead(&User, sizeof(struct UserInfo), fpOldUList, XOR_USER) == 0)
+            break;
+
+//        printf("Read in %s\n", User.szName);
+
+        // for each user in file, see if same as ClanID
+        if (User.ClanID[0] == ClanID[0] && User.ClanID[1] == ClanID[1])
+        {
+            //printf("skipping over %s\n", User.szName);
+            // same, skip over him
+            continue;
+        }
+
+        // otherwise, don't skip him, write him to new file
+		EncryptWrite(&User, sizeof(struct UserInfo), fpNewUList, XOR_USER);
+    }
+
+    // close file
+    fclose(fpOldUList);
+    fclose(fpNewUList);
+
+    // rename file
+    unlink(USERLIST_DATAFILE);
+    rename(TEMP_FILENAME, USERLIST_DATAFILE);
+}
+
+BOOL ClanIDInList( _INT16 ClanID[2] )
+{
+    FILE *fpUList;
+    BOOL Found = FALSE;
+    struct UserInfo User;
+
+    fpUList = fopen(USERLIST_DATAFILE, "rb");
+    if (!fpUList)
+    {
+        // no user list found, assume not in list then
+        return FALSE;
+    }
+
+    // scan through file until end
+    for (;;)
+    {
+		if (EncryptRead(&User, sizeof(struct UserInfo), fpUList, XOR_USER) == 0)
+            break;
+
+        // see if this user's name is same as one we're looking for
+        if (User.ClanID[0] == ClanID[0] &&
+            User.ClanID[1] == ClanID[1])
+        {
+                Found = TRUE;
+                break;
+        }
+    }
+
+    fclose(fpUList);
+
+    return Found;
+}
+
+void RemoveFromIPScores ( _INT16 ClanID[2] )
+{
+    struct UserScore **ScoreList;
+    _INT16 iTemp, UsersFound = 0;
+    char ScoreDate[11];
+    FILE *fp;
+
+    fp = fopen(IPSCORES_DATAFILE, "rb");
+
+    if (!fp)
+    {
+        return;
+    }
+
+    // initialize the score data
+    ScoreList = malloc(sizeof(struct UserScore *)*MAX_USERS);
+    CheckMem(ScoreList);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+        ScoreList[iTemp] = NULL;
+
+    // read date
+	EncryptRead(ScoreDate, 11, fp, XOR_IPS);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+    {
+        ScoreList[iTemp] = malloc(sizeof(struct UserScore));
+        CheckMem(ScoreList[iTemp]);
+		if (!EncryptRead(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_IPS))
+        {
+            free(ScoreList[iTemp]);
+            ScoreList[iTemp] = NULL;
+            break;
+        }
+
+        // if this is the user we wanted, remove him from the list
+        if (ScoreList[iTemp]->ClanID[0] == ClanID[0] &&
+            ScoreList[iTemp]->ClanID[1] == ClanID[1])
+        {
+            free(ScoreList[iTemp]);
+            ScoreList[iTemp] = NULL;
+        }
+    }
+    UsersFound = iTemp;
+    fclose(fp);
+
+    fp = fopen(IPSCORES_DATAFILE, "wb");
+
+    // write date
+	EncryptWrite(ScoreDate, 11, fp, XOR_IPS);
+
+    // write them to file now and free them at the same time
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+        if (ScoreList[iTemp])
+        {
+			EncryptWrite(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_IPS);
+            free(ScoreList[iTemp]);
+        }
+
+    free(ScoreList);
+
+    fclose(fp);
+}
+
+void FreeClan( struct clan *Clan )
+{
+	_INT16 CurMember;
+
+	// free members first
+	for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+	{
+		if (Clan->Member[CurMember])
+		{
+			free(Clan->Member[CurMember]);
+			Clan->Member[CurMember] = NULL;
+		}
+	}
+
+	free(Clan);
+	Clan = NULL;
+}
+
+BOOL GetClan ( _INT16 ClanID[2], struct clan *TmpClan )
+{
+	FILE *fpPlayerFile;
+	_INT16 ClanNum, iTemp;
+	char szFileName[50];
+
+    // make them all NULLs for safety
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+        TmpClan->Member[iTemp] = NULL;
+
+    strcpy(szFileName, PLAYER_DATAFILE);
+
+	/* find guy in file */
+	fpPlayerFile = fopen(szFileName, "rb");
+	if (!fpPlayerFile)
+	{
+        return FALSE;     /* means failed to find clan */
+	}
+
+	for (ClanNum = 0;; ClanNum++)
+	{
+        if (fseek(fpPlayerFile, (long)ClanNum * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET))
+		{
+            // couldn't find clan in file
+			fclose(fpPlayerFile);
+            return FALSE;
+		}
+		if (!EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_PC))
+        {
+			fclose(fpPlayerFile);
+            return FALSE;
+        }
+
+        // make them all NULLs for safety
+        for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+            TmpClan->Member[iTemp] = NULL;
+
+		if (TmpClan->ClanID[0] == ClanID[0] &&
+			TmpClan->ClanID[1] == ClanID[1])
+		{
+			/* found it */
+			/* read in PCs */
+			for (iTemp = 0; iTemp < 6; iTemp++)
+			{
+				TmpClan->Member[iTemp] = malloc(sizeof(struct pc));
+                CheckMem(TmpClan->Member[iTemp]);
+				EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fpPlayerFile, XOR_PC);
+
+                /* skip those members which are non-existant */
+                if (TmpClan->Member[iTemp]->szName[0] == 0)
+                {
+                    free(TmpClan->Member[iTemp]);
+                    TmpClan->Member[iTemp] = NULL;
+                }
+                else
+                    TmpClan->Member[iTemp]->MyClan = TmpClan;
+			}
+			break;
+		}
+	}
+	fclose(fpPlayerFile);
+
+    return TRUE;
+}
+
+void UpdateClan ( struct clan *Clan )
+{
+    FILE *fpPlayerFile;
+/*    char szFileName[50];*/
+    _INT16 CurClan, iTemp;
+    long OldOffset, Offset;
+    struct clan *TmpClan;
+    struct pc *TmpPC;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+    fpPlayerFile = fopen(PLAYER_DATAFILE, "r+b");
+    if (!fpPlayerFile)
+    {
+        printf("Couldn't open " PLAYER_DATAFILE "\n");
+        free(TmpClan);
+        free(TmpPC);
+        return;  /* failed to find clan */
+    }
+
+    for (CurClan = 0;; CurClan++)
+    {
+        /* go through file till you find clan he wants */
+
+        Offset = (long)CurClan * (sizeof(struct clan) + Game.Data->MaxPermanentMembers*sizeof(struct pc));
+        if (fseek(fpPlayerFile, Offset, SEEK_SET))
+        {
+			break;	/* couldn't fseek, so exit */
+        }
+
+        OldOffset = ftell(fpPlayerFile);
+
+		if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_PC) == 0)
+			break;	/* stop reading if no more players found */
+
+        /* skip if deleted clan */
+        if (TmpClan->ClanID[0] == -1)
+            continue;
+
+        /* if same Ids, seek back and write to file */
+        if (TmpClan->ClanID[0] == Clan->ClanID[0] &&
+            TmpClan->ClanID[1] == Clan->ClanID[1])
+        {
+            fseek(fpPlayerFile, OldOffset, SEEK_SET);
+			EncryptWrite(Clan, sizeof(struct clan), fpPlayerFile, XOR_PC);
+
+            // fwrite players
+            TmpPC->szName[0] = 0;
+            for (iTemp = 0; iTemp < 6; iTemp++)
+            {
+                if (Clan->Member[iTemp] && Clan->Member[iTemp]->Undead == FALSE)
+					EncryptWrite(Clan->Member[iTemp], sizeof(struct pc), fpPlayerFile, XOR_PC);
+                else
+					EncryptWrite(TmpPC, sizeof(struct pc), fpPlayerFile, XOR_PC);
+            }
+        }
+    }
+    fclose(fpPlayerFile);
+
+    free(TmpPC);
+    free(TmpClan);
+}
+
+void System_Error(char *szErrorMsg)
+{
+	fprintf (stderr, "System Error: %s\n", szErrorMsg);
+	fflush (stderr);
+	exit (1);
+}
+
+void InitGame( void )
+{
+	FILE *fpGame;
+
+	/* Open Game Datafile */
+	fpGame = fopen(GAME_DATAFILE, "rb");
+	if (!fpGame)
+	{
+		System_Error ("Failure to open " GAME_DATAFILE);
+	}
+
+	Game.Data = (struct game_data *) malloc (sizeof(struct game_data));
+	CheckMem(Game.Data);
+
+	if (!EncryptRead(Game.Data, (long)sizeof(struct game_data), fpGame, XOR_GAME))
+	{
+		System_Error ("Unable to read the " GAME_DATAFILE " information!");
+	}
+
+	fclose(fpGame);
+}
+
+#ifdef __unix__
+char
+getch()  {
+	fd_set fds;
+	FD_ZERO(&fds);
+	FD_SET(fileno(stdin),&fds);
+
+	select(fileno(stdin)+1, &fds, NULL, NULL, NULL);
+	return (char)getchar();
+}
+#endif
diff --git a/src/doors/clans-src/pcedit.dsp b/src/doors/clans-src/pcedit.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..3b25af9bc140a7b4a34abffb5bc33b3b3481077a
--- /dev/null
+++ b/src/doors/clans-src/pcedit.dsp
@@ -0,0 +1,113 @@
+# Microsoft Developer Studio Project File - Name="pcedit" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=pcedit - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "pcedit.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "pcedit.mak" CFG="pcedit - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "pcedit - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "pcedit - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "pcedit - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "pcedit___Win32_Release"
+# PROP BASE Intermediate_Dir "pcedit___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Win32_Release"
+# PROP Intermediate_Dir "Win32_Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Zp1 /MD /W3 /GX- /Ox /Ot /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# SUBTRACT CPP /Os /Fr
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# SUBTRACT LINK32 /map
+
+!ELSEIF  "$(CFG)" == "pcedit - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "pcedit___Win32_Debug"
+# PROP BASE Intermediate_Dir "pcedit___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Win32_Debug"
+# PROP Intermediate_Dir "Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c
+# ADD CPP /nologo /Zp1 /MDd /W3 /Gm /GX- /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ  /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib  kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /debugtype:both /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "pcedit - Win32 Release"
+# Name "pcedit - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\MYOPEN.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\PCEDIT.C
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\MYOPEN.H
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/src/doors/clans-src/quests.c b/src/doors/clans-src/quests.c
new file mode 100644
index 0000000000000000000000000000000000000000..9de0eca8e13de8e881e831deaa43c0e214f1cb53
--- /dev/null
+++ b/src/doors/clans-src/quests.c
@@ -0,0 +1,1514 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Quests/Event ADT
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "parsing.h"
+#include "help.h"
+#include "reg.h"
+#include "door.h"
+#include "video.h"
+#include "myopen.h"
+#include "fight.h"
+#include "input.h"
+#include "items.h"
+#include "user.h"
+#include "news.h"
+#include "npc.h"
+#include "k_quests.h"
+#include "quests.h"
+
+#define CD_OR                   1
+#define CD_AND                  2
+
+struct PACKED EventHeader {
+	char szName[30];
+	long EventSize;
+	__BOOL Event; 			// 1 = Event, 0 = Result
+} PACKED;
+
+struct Quest Quests[MAX_QUESTS];
+
+extern struct village Village;
+char Quests_TFlags[8];          // temp. flags
+extern struct config *Config;
+extern struct clan *PClan;
+extern struct Language *Language;
+BOOL QuestsInitialized = FALSE;
+extern __BOOL Verbose;
+
+// ------------------------------------------------------------------------- //
+
+  void Quests_Init ( void )
+  {
+    /* read in quests file and allocate memory for quest names */
+    _INT16 iTemp, CurQuest;
+    FILE *fp;
+    char szLine[128], *pcCurrentPos;
+    char szToken[MAX_TOKEN_CHARS + 1];
+    unsigned _INT16 uCount;
+    _INT16 iKeyWord;
+
+    if (Verbose)
+    {
+      DisplayStr("> Quests_Init()\n");
+      delay(500);
+    }
+
+
+    // init quest names
+    for (iTemp = 0; iTemp < MAX_QUESTS; iTemp++)
+    {
+      Quests[iTemp].Active = FALSE;
+      Quests[iTemp].pszQuestName = NULL;
+      Quests[iTemp].pszQuestIndex = NULL;
+      Quests[iTemp].pszQuestFile = NULL;
+      Quests[iTemp].Known = FALSE;
+    }
+
+    fp = fopen("quests.ini", "r");
+    if (!fp)
+    {
+      DisplayStr("NO QUESTS FILE!!\n");
+      return;
+    }
+
+    /* read in all lines and get event names */
+    CurQuest = -1;
+    for (;;)
+    {
+      /* read in a line */
+      if (fgets(szLine, 128, fp) == NULL) break;
+
+      /* Ignore all of line after comments or CR/LF char */
+      pcCurrentPos=(char *)szLine;
+
+      ParseLine(pcCurrentPos);
+
+      /* If no token was found, proceed to process the next line */
+      if(!*pcCurrentPos) continue;
+
+      GetToken(pcCurrentPos, szToken);
+
+      if (szToken[0] == '$')
+        break;
+
+      /* Loop through list of keywords */
+      for(iKeyWord = 0; iKeyWord < MAX_QUEST_WORDS; ++iKeyWord)
+      {
+        /* If keyword matches */
+        if(stricmp(szToken, papszQuestKeyWords[iKeyWord]) == 0)
+        {
+          /* Process config token */
+          switch (iKeyWord)
+          {
+            case 0 :  /* name of quest */
+              if (CurQuest == MAX_QUESTS)
+                break;
+
+/* NO MORE REG
+              if (CurQuest == 10 &&
+                (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+                IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE))
+              {
+                // can't load more than 10 in unreg
+                break;
+              }
+*/
+
+              CurQuest++;
+
+              Quests[CurQuest].Active = TRUE;
+              Quests[CurQuest].Known  = FALSE;
+
+              Quests[ CurQuest ].pszQuestName =
+                malloc( strlen(pcCurrentPos) + 1);
+              CheckMem(Quests[ CurQuest ].pszQuestName);
+              strcpy(Quests[ CurQuest ].pszQuestName, pcCurrentPos);
+              break;
+            case 1 :  /* index of quest */
+              /* make room for questname in mem */
+              Quests[ CurQuest ].pszQuestIndex =
+                malloc( strlen(pcCurrentPos) + 1);
+              CheckMem(Quests[ CurQuest ].pszQuestIndex);
+              strcpy(Quests[ CurQuest ].pszQuestIndex, pcCurrentPos);
+              break;
+            case 2 :  /* filename to use */
+              /* make room for questname in mem */
+              Quests[ CurQuest ].pszQuestFile =
+                malloc( strlen(pcCurrentPos) + 1);
+              CheckMem(Quests[ CurQuest ].pszQuestFile);
+              strcpy(Quests[ CurQuest ].pszQuestFile, pcCurrentPos);
+              break;
+            case 3 :  /* known */
+              Quests[CurQuest].Known = TRUE;
+              break;
+          }
+        }
+      }
+    }
+
+    fclose(fp);
+
+    QuestsInitialized = TRUE;
+	(void)uCount;
+  }
+
+  void Quests_Close ( void )
+  {
+    _INT16 iTemp;
+
+    if (!QuestsInitialized) return;
+
+
+    for (iTemp = 0; iTemp < MAX_QUESTS; iTemp++)
+      if (Quests[iTemp].Active)
+      {
+        if (Quests[iTemp].pszQuestName)
+        {
+          free(Quests[iTemp].pszQuestName);
+          Quests[iTemp].pszQuestName = NULL;
+        }
+
+        if (Quests[iTemp].pszQuestFile)
+        {
+          free(Quests[iTemp].pszQuestFile);
+          Quests[iTemp].pszQuestFile = NULL;
+        }
+
+        if (Quests[iTemp].pszQuestIndex)
+        {
+          free(Quests[iTemp].pszQuestIndex);
+          Quests[iTemp].pszQuestIndex = NULL;
+        }
+      }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void ClearFlags ( char *Flags )
+  {
+    _INT16 iTemp;
+
+    for (iTemp = 0; iTemp < 8; iTemp++)
+      Flags[iTemp] = 0;
+  }
+
+  void SetFlag( char *Flags, _INT16 WhichFlag )
+  {
+    Flags[ WhichFlag/8 ] |= (1 << (WhichFlag % 8));
+  }
+
+  void ClearFlag( char *Flags, _INT16 WhichFlag )
+  {
+    if (Flags[ WhichFlag/8 ]  & (1 << (WhichFlag % 8)))
+      Flags[ WhichFlag/8 ] ^= (1 << (WhichFlag % 8));
+  }
+
+  BOOL FlagSet( char *Flags, _INT16 WhichFlag )
+  {
+    if (Flags[ WhichFlag/8 ] & (1 << (WhichFlag % 8)))
+      return TRUE;
+    else
+      return FALSE;
+  }
+
+  BOOL legal ( char *pszAcs, _INT16 *iCharsRead )
+  {
+    BOOL bCurrent = TRUE;   // flag as to whether last pszAcs's were TRUE
+    BOOL UseCurrent = TRUE;
+    BOOL bSoFar = TRUE;
+    BOOL UseNot = FALSE;    // needed to check if we need to switch/NOT
+                  // next ACS flag
+    _INT16 iCharsSkipped;  /* number of characters skipped when calling legal()
+                 from within this function */
+    _INT16 iTemp;
+    _INT16 LastCondition = CD_AND;
+    char szIndex[20];
+    unsigned char c;
+    char *pcCurrentPos;
+    char *pszString;
+    _INT16 iFirstValue, iSecondValue;
+    char pszAcsCopy[50];
+    long GoldAmount;
+
+    strcpy(pszAcsCopy, pszAcs);
+
+    pcCurrentPos = pszAcsCopy;
+
+    while (*pcCurrentPos)
+    {
+      switch( *pcCurrentPos )
+      {
+        case ')' :  /* end bCurrent conditions */
+          pcCurrentPos++;
+          *iCharsRead = pcCurrentPos - pszAcs;
+          return bSoFar;
+        case '(' :  /* start a new set of conditions */
+          pcCurrentPos++;
+          bCurrent = legal(pcCurrentPos, &iCharsSkipped );
+          UseCurrent = TRUE;
+          pcCurrentPos += iCharsSkipped;
+          break;
+        case ' ' :
+          pcCurrentPos++;
+          UseCurrent = FALSE;
+          break;
+        case '&' :
+          LastCondition = CD_AND;
+          pcCurrentPos++;
+          UseCurrent = FALSE;
+          break;
+        case '|' :
+          LastCondition = CD_OR;
+          pcCurrentPos++;
+          UseCurrent = FALSE;
+          break;
+        case '^' :
+          bCurrent = TRUE;
+          UseCurrent = TRUE;
+          pcCurrentPos++;
+          break;
+        case '%' :
+          bCurrent = FALSE;
+          UseCurrent = TRUE;
+          pcCurrentPos++;
+          break;
+        case '!' :
+          UseNot = TRUE;
+          UseCurrent = FALSE;
+          pcCurrentPos++;
+          break;
+        case 'Q' :  // quest done?
+          // get quest num
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+          iTemp = atoi(szIndex) - 1;
+
+          // if this quest done, it's true
+          if (PClan->QuestsDone[ iTemp/8 ] & (char)(1 << (iTemp%8)))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case '$' :  // have this much gold?
+          // get flag num
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+          GoldAmount = atol(szIndex);
+
+          if (PClan->Empire.VaultGold >= GoldAmount)
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'L' :  // level
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+          iTemp = atoi(szIndex);
+
+          if (PClan->MineLevel == iTemp)
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'K' :  // level must be at least this
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+          iTemp = atoi(szIndex);
+
+          if (PClan->MineLevel >= iTemp)
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'R' :  // random
+          // get random value which is highest
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+          iTemp = atoi(szIndex);
+
+          if (RANDOM(100) >= (100-iTemp))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'T' :  // TFlag
+          // get tflag num
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+
+          if (FlagSet(Quests_TFlags, atoi(szIndex)))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+
+          // od_printf("T%d is %s\n\r", atoi(szIndex), bCurrent ? "true" : "false");
+          break;
+        case 'P' :  // PFlag
+          // get flag num
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+
+          if (FlagSet(PClan->PFlags, atoi(szIndex)))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'G' :  // GFlag
+            // get flag num
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+
+          if (FlagSet(Village.Data->GFlags, atoi(szIndex)))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'D' :  // DFlag
+          // get flag num
+          pcCurrentPos++;
+            iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+
+          if (FlagSet(PClan->DFlags, atoi(szIndex)))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+        case 'H' :  // HFlag
+          // get flag num
+          pcCurrentPos++;
+          iTemp = 0;
+          while (isdigit(*pcCurrentPos))
+            szIndex[iTemp++] = *(pcCurrentPos++);
+          szIndex[iTemp] = 0;
+
+          UseCurrent = TRUE;
+
+          if (FlagSet(Village.Data->HFlags, atoi(szIndex)))
+            bCurrent = TRUE;
+          else
+            bCurrent = FALSE;
+          break;
+		default:
+		  pcCurrentPos++;
+      }
+
+      if (UseCurrent)
+      {
+        if (UseNot)
+        {
+          UseNot = FALSE;
+          bCurrent = !bCurrent;
+        }
+
+        if (LastCondition == CD_OR)
+        {
+          if ((bCurrent == TRUE) || (bSoFar == TRUE))
+            bSoFar = TRUE;
+          else
+            bSoFar = FALSE;
+        }
+        else if (LastCondition == CD_AND)
+        {
+          if ((bCurrent==TRUE) && (bSoFar==TRUE))
+            bSoFar = TRUE;
+          else
+            bSoFar = FALSE;
+        }
+      }
+    }
+
+    if (iCharsRead)
+      *iCharsRead = pcCurrentPos - pszAcs;
+	
+	(void)iFirstValue;
+	(void)c;
+	(void)pszString;
+	(void)iSecondValue;
+    return bSoFar;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+
+  void JumpToEvent ( char *szLabel, struct FileHeader *FileHeader)
+  {
+    struct EventHeader EventHeader;
+
+    fseek(FileHeader->fp, FileHeader->lStart, SEEK_SET);
+
+    for (;;)
+    {
+      // if past end of file or at it, break
+      if (ftell(FileHeader->fp) >= FileHeader->lEnd)
+      {
+        printf("Couldn't find event!\n");
+        od_exit(0, FALSE);
+      }
+
+      // find event to run first
+      fread(&EventHeader, sizeof(struct EventHeader), 1, FileHeader->fp);
+
+      if (stricmp(EventHeader.szName, szLabel) == 0)
+        break;
+      else
+      {
+        // see start of next event
+        fseek(FileHeader->fp, EventHeader.EventSize, SEEK_CUR);
+      }
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+  void TellQuest ( char *pszQuestIndex )
+  {
+    _INT16 QuestNum, CurQuest, iTemp;
+    char szString[80];
+
+    // scan for quest in questlist
+    QuestNum = -1;
+    for (CurQuest = 0; CurQuest < MAX_QUESTS; CurQuest++)
+    {
+      if (Quests[CurQuest].Active &&
+        stricmp(pszQuestIndex, Quests[CurQuest].pszQuestIndex) == 0)
+      {
+        // found match
+        QuestNum = CurQuest;
+        break;
+      }
+    }
+    if (QuestNum == -1)
+    {
+      sprintf(szString, "Couldn't find quest %s\n\r", pszQuestIndex);
+      rputs(szString);
+      return;
+    }
+
+    // set bit
+    if (PClan->QuestsKnown[ QuestNum/8 ] & (1<<(QuestNum%8)))
+      return;  // already knew about that quest
+
+    // set it
+    PClan->QuestsKnown[ QuestNum/8 ] |= (1<<(QuestNum%8));
+
+    // tell user
+    sprintf(szString, "\n|0CYour clan now knows of |0B%s|0C.\n",
+      Quests[QuestNum].pszQuestName);
+    rputs(szString);
+	(void)iTemp;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  BOOL RunEvent ( BOOL QuoteToggle, char *szEventFile, char *szEventName,
+    struct NPCInfo *NPCInfo, char *szNPCIndex )
+  {
+    char *szString, *pcBrace, *szLegal, *szLabel;
+    char *szLabel1, *szLabel2, *szLabel3, szClanName[25];
+    struct EventHeader EventHeader;
+    struct FileHeader FileHeader;
+      char szNPCFileName[25], *apszLabels[MAX_OPTIONS];
+    char szText[255];
+    char CommandType, OldCommType = 0, DataLength, cInput, *pcCurrentPos;
+    char *pszOptionNames[MAX_OPTIONS];
+    char szKeys[MAX_OPTIONS+1], Key;      // extra space for '\0'
+    char *Buffer;               // not same as ecomp.c's buffer
+    BOOL Done;
+    _INT16 iTemp, CurOption, WhichEnemy, EventsFound, CurEvent, ChosenEvent,
+      NumOptions, WhichOption;
+    long OldOffset = 0;
+    BOOL QuestDone = FALSE, FoundEvent;
+    struct clan *EnemyClan;
+    BOOL EndedChat = FALSE;
+    _INT16 CurMember, PercentGold, FightResult, EmptySlot;
+    long GoldAmount, XPAmount;
+    struct NPCNdx NPCNdx;
+
+    // reset temp flags
+    if (QuoteToggle == FALSE) // clear flags for event files but not quotes
+      ClearFlags(Quests_TFlags);
+
+    rputs("|0C");
+
+
+    // make strings
+    szString  = MakeStr(255);
+    szLegal   = MakeStr(155);
+    Buffer    = MakeStr(255);
+    szLabel   = MakeStr(31);
+    szLabel1  = MakeStr(31);
+    szLabel2  = MakeStr(31);
+    szLabel3  = MakeStr(31);
+
+    /* initialize file */
+    MyOpen(szEventFile, "rb", &FileHeader);
+    if (FileHeader.fp == NULL)
+    {
+      sprintf(szString, "-> %s\n", szEventFile);
+      rputs(szString);
+      rputs("Error opening event file.\n%P");
+
+      // free strings
+      free(szString);
+      free(szLegal);
+      free(Buffer);
+      free(szLabel);
+      free(szLabel1);
+      free(szLabel2);
+      free(szLabel3);
+
+      return FALSE;
+    }
+
+    if (*szEventName)
+    {
+      JumpToEvent(szEventName, &FileHeader);
+    }
+    else
+    {
+      EventsFound = 0;
+
+      // find out how many events in the file
+      for (;;)
+      {
+        // if at end of file or past it, stop
+        if (ftell(FileHeader.fp) >= FileHeader.lEnd)
+          break;
+
+        if (fread(&EventHeader, sizeof(struct EventHeader), 1, FileHeader.fp) == 0)
+          break;
+
+        if (EventHeader.Event)
+          EventsFound++;
+
+        // seek next event
+        fseek(FileHeader.fp, EventHeader.EventSize, SEEK_CUR);
+      }
+
+      // choose one randomly and seek it
+      ChosenEvent = RANDOM(EventsFound);
+
+      fseek(FileHeader.fp, FileHeader.lStart, SEEK_SET);
+
+      EventsFound = 0;
+      // find out how many events in the file
+      for (;;)
+      {
+        // if at end...
+        if (ftell(FileHeader.fp) >= FileHeader.lEnd)
+          break;
+
+        if (fread(&EventHeader, sizeof(struct EventHeader), 1, FileHeader.fp) == 0)
+          break;
+
+        if (EventHeader.Event && EventsFound == ChosenEvent)
+          break;
+
+        if (EventHeader.Event)
+          EventsFound++;
+
+        // seek next event
+        fseek(FileHeader.fp, EventHeader.EventSize, SEEK_CUR);
+      }
+    }
+
+    /* initialize optionnames */
+    // initialize labels
+    for (iTemp = 0; iTemp < MAX_OPTIONS; iTemp++)
+    {
+      pszOptionNames[iTemp] = NULL;
+      szKeys[iTemp] = 0;
+      apszLabels[iTemp] = NULL;
+    }
+
+    /* initialize enemyclan to fight */
+    EnemyClan = MallocClan();
+    NPC_ResetNPCClan(EnemyClan);
+
+    Done = FALSE;
+    while (!Done)
+    {
+      if (ftell(FileHeader.fp) >= FileHeader.lEnd)
+      {
+        DisplayStr("K-Error\n%P");
+        break;
+      }
+
+      // read in command type
+      fread(&CommandType, sizeof(char), 1, FileHeader.fp);
+
+      // read in szLegal
+      szLegal[0] = 0;
+      fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+      fread(szLegal, DataLength, 1, FileHeader.fp);
+
+      // if not legal, skip
+      if (szLegal[0] && legal(szLegal, NULL) == FALSE)
+      {
+        // skip it
+        fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+        fseek(FileHeader.fp, DataLength, SEEK_CUR);
+        continue;
+      }
+
+      switch (CommandType)
+      {
+        // Following commands take one parameter, a string
+        case 2 :  // Text
+        case 6 :  // Prompt
+        case 10:  // AddNews
+        case 8  : // TellQuest
+        case 13 : // Chat
+        case 14 : // SetFlag
+        case 15 : // ClearFlag
+        case 16 : // Jump
+        case 17 : // Heal
+        case 18 : // TakeGold
+        case 19 : // GiveGold
+        case 20 : // GiveXP
+        case 21 : // GiveItem
+        case 23 : // GiveFight
+        case 24 : // GiveFollowers
+        case 25 : // GivePoints
+        case 28 : // TellTopic
+              case 32 :   // Display
+          // read in text
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+          fread(szText, DataLength, 1, FileHeader.fp);
+
+          switch (CommandType)
+          {
+            case 2 :  // Text
+              if (szText[0])
+                rputs(szText);
+
+              rputs("\n");
+              break;
+            case 6 :  // Prompt
+              rputs(szText);
+              break;
+            case 10:  // AddNews
+              News_AddNews(szText);
+              News_AddNews("\n\n");
+              break;
+            case 8  : // TellQuest
+              TellQuest(szText);
+              break;
+            case 13 : // Chat
+              NPC_ChatNPC( szText );
+              break;
+            case 14 : // SetFlag
+              // first value is the type of flag
+              pcCurrentPos = szText;
+              switch (toupper(*pcCurrentPos))
+              {
+                case 'D' :
+                  SetFlag(PClan->DFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'P' :
+                  SetFlag(PClan->PFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'T' :
+                  SetFlag(Quests_TFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'G' :
+                  SetFlag(Village.Data->GFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'H' :
+                  SetFlag(Village.Data->HFlags, atoi(pcCurrentPos+1));
+                  break;
+              }
+              break;
+            case 15 : // ClearFlag
+              pcCurrentPos = szText;
+              switch (toupper(*pcCurrentPos))
+              {
+                case 'D' :
+                  ClearFlag(PClan->DFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'P' :
+                  ClearFlag(PClan->PFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'T' :
+                  ClearFlag(Quests_TFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'G' :
+                  ClearFlag(Village.Data->GFlags, atoi(pcCurrentPos+1));
+                  break;
+                case 'H' :
+                  ClearFlag(Village.Data->HFlags, atoi(pcCurrentPos+1));
+                  break;
+              }
+              break;
+            case 16 : // Jump
+              JumpToEvent(szText, &FileHeader);
+              break;
+            case 17 : // Heal
+              for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+              {
+                if (PClan->Member[iTemp])
+                {
+                  if (szText[0] == 0)
+                  {
+                    if (PClan->Member[iTemp]->Status == Here)
+                      PClan->Member[iTemp]->HP =
+                        PClan->Member[iTemp]->MaxHP;
+                  }
+                  else if (stricmp(szText, "SP") == 0)
+                  {
+                    if (PClan->Member[iTemp]->Status == Here)
+                      PClan->Member[iTemp]->SP =
+                        PClan->Member[iTemp]->MaxSP;
+                  }
+                }
+              }
+              break;
+            case 18 : // TakeGold
+              pcCurrentPos = szText;
+              if (*pcCurrentPos == '%')
+              {
+                PercentGold = atoi(&pcCurrentPos[1]);
+                if (PercentGold < 0)
+                  PercentGold = 0;
+                if (PercentGold > 100)
+                  PercentGold = 100;
+
+                GoldAmount = (PClan->Empire.VaultGold*PercentGold)/100L;
+              }
+              else
+                GoldAmount = atol(pcCurrentPos);
+
+              PClan->Empire.VaultGold -= GoldAmount;
+              break;
+            case 19 : // GiveGold
+              GoldAmount = atol(szText);
+              PClan->Empire.VaultGold += GoldAmount;
+              break;
+            case 20 : // GiveXP
+              XPAmount = atol(szText);
+
+              for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+                if (PClan->Member[iTemp] && PClan->Member[iTemp]->Status == Here)
+                  PClan->Member[iTemp]->Experience +=
+                    XPAmount;
+              Fight_CheckLevelUp();
+              break;
+            case 21 : // GiveItem
+              Items_GiveItem(szText);
+              break;
+            case 23 : // GiveFight
+              PClan->FightsLeft += atoi(szText);
+              break;
+            case 24 : // GiveFollowers
+              PClan->Empire.Army.Followers += atol(szText);
+              break;
+            case 25 : // GivePoints
+              PClan->Points += atol(szText);
+              break;
+            case 28 : // TellTopic
+              for (iTemp = 0; iTemp < MAX_TOPICS; iTemp++)
+              {
+                if (NPCInfo->Topics[iTemp].Active == FALSE)
+                  continue;
+
+                if (stricmp(NPCInfo->Topics[iTemp].szFileName,
+                  szText) == 0)
+                {
+                  // found quote, set it to known
+                  NPCInfo->Topics[iTemp].Known = TRUE;
+                  break;
+                }
+              }
+              break;
+                      case 32 :   // Display
+                          Display(szText);
+                          break;
+          }
+          break;
+        case 3 :  // Option keyword
+        case 33 : // GetKey keyword
+
+          // get user input
+
+          for (iTemp = 0; iTemp < MAX_OPTIONS; iTemp++)
+          {
+            if (pszOptionNames[iTemp])
+            {
+              free(pszOptionNames[iTemp]);
+              pszOptionNames[iTemp] = NULL;
+            }
+            szKeys[iTemp] = 0;
+          }
+
+
+          // get first key allowed
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+          fread(Buffer, DataLength, 1, FileHeader.fp);
+          strcpy(szLabel, &Buffer[1]);
+
+          pszOptionNames[0] = malloc(strlen(szLabel) + 1);
+          CheckMem(pszOptionNames[0]);
+          strcpy(pszOptionNames[0], szLabel);
+
+          szKeys[0] = Buffer[0];
+
+          for (CurOption = 1; CurOption < MAX_OPTIONS; )
+          {
+            OldOffset = ftell(FileHeader.fp);
+
+            OldCommType = CommandType;
+
+            // read in command type
+            fread(&CommandType, sizeof(char), 1, FileHeader.fp);
+
+            // if not an Option command, skip back and quit
+            if (CommandType != OldCommType)
+            {
+              break;
+            }
+
+            // read in szLegal
+            szLegal[0] = 0;
+            fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+            fread(szLegal, DataLength, 1, FileHeader.fp);
+
+            // if szLegal do legal() thing later
+            if (szLegal[0] && legal(szLegal, NULL) == FALSE)
+            {
+              // skip it
+              fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+              fseek(FileHeader.fp, DataLength, SEEK_CUR);
+              continue;
+            }
+            else
+            {
+              // else is legal, allow as an option
+
+              // get key and label
+              fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+              fread(Buffer, DataLength, 1, FileHeader.fp);
+              strcpy(szLabel, &Buffer[1]);
+              szKeys[CurOption] = Buffer[0];
+
+              /* get this optionname */
+              pszOptionNames[CurOption] = malloc(strlen(szLabel) + 1);
+              CheckMem(pszOptionNames[CurOption]);
+              strcpy(pszOptionNames[CurOption], szLabel);
+            }
+
+            CurOption++;
+          }
+          szKeys[CurOption] = 0;
+
+          // get input from user
+
+          cInput = toupper(od_get_answer(szKeys));
+
+          if (OldCommType != 33)
+          {
+            sprintf(szString, "%c\n\r", cInput);
+            rputs(szString);
+          }
+
+          /* see which key that was */
+          for (CurOption = 0; CurOption < MAX_OPTIONS; CurOption++)
+          {
+            if (toupper(szKeys[CurOption]) == cInput)
+            {
+              /* found which key */
+              break;
+            }
+          }
+
+          /* if that option has nextline to "jump" to, keep
+             going in same block of data */
+          if (stricmp(pszOptionNames[CurOption], "NextLine") == 0)
+          {
+            fseek(FileHeader.fp, OldOffset, SEEK_SET);
+            break;
+          }
+
+          /* if that option has "STOP" to "jump" to, stop */
+          else if (stricmp(pszOptionNames[CurOption], "Stop") == 0)
+          {
+            Done = TRUE;
+            break;
+          }
+
+          /* else, look for new spot to jump to */
+          JumpToEvent(pszOptionNames[CurOption], &FileHeader);
+          break;
+        case 7  : // Fight
+          // read in 3 labels
+
+          // skip in datalength
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+          fread(szLabel1, DataLength, 1, FileHeader.fp);
+
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+          fread(szLabel2, DataLength, 1, FileHeader.fp);
+
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+          fread(szLabel3, DataLength, 1, FileHeader.fp);
+
+          if (stricmp(szLabel3, "NoRun") == 0)
+            FightResult = Fight_Fight(PClan, EnemyClan, FALSE, FALSE, FALSE);
+          else  // can run
+            FightResult = Fight_Fight(PClan, EnemyClan, FALSE, TRUE, FALSE);
+
+          /* set all spells to 0 */
+          for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+          {
+            if (PClan->Member[CurMember] == NULL)
+              continue;
+
+            for (iTemp = 0; iTemp < 10; iTemp++)
+              PClan->Member[CurMember]->SpellsInEffect[iTemp].SpellNum = -1;
+          }
+
+
+          /* free up memory used by undead */
+          for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+          {
+            if (PClan->Member[iTemp] &&
+              PClan->Member[iTemp]->Undead)
+            {
+              free(PClan->Member[iTemp]);
+              PClan->Member[iTemp] = NULL;
+            }
+          }
+
+          // free up enemies found
+          for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+            if (EnemyClan->Member[iTemp])
+            {
+              free(EnemyClan->Member[iTemp]);
+              EnemyClan->Member[iTemp] = NULL;
+            }
+
+          if (FightResult == FT_WON)
+          {
+            // won
+            strcpy(szString, szLabel1);
+          }
+          else if (FightResult == FT_LOST)
+          {
+            // lost
+            strcpy(szString, szLabel2);
+          }
+          else if (FightResult == FT_RAN)
+          {
+            // ran away
+
+            if (stricmp(szLabel3, "NoRun") == 0)
+              break;
+            else
+              strcpy(szString, szLabel3);
+          }
+
+          // if label is "nextline", stay here
+          if (stricmp(szString, "nextline") == 0)
+            break;
+          // if label is "stop", end scrpt
+          else if (stricmp(szString, "Stop") == 0)
+          {
+            Done = TRUE;
+            break;
+          }
+          else
+            JumpToEvent(szString, &FileHeader);
+          break;
+        case 4  : // End
+        case 9  : // DoneQuest
+        case 22 : // Pause
+        case 29 : // JoinClan
+        case 30 : // EndChat
+          // skip in datalength (0)
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+          if (CommandType == 4)
+            Done = TRUE;
+          else if (CommandType == 9)
+          {
+            rputs("\n|14Quest successfully completed!\n");
+            Done = TRUE;
+            QuestDone = TRUE;
+          }
+          else if (CommandType == 22)
+          {
+            door_pause();
+          }
+          else if (CommandType == 29)
+          {
+            NPC_GetNPCNdx(NPCInfo, &NPCNdx);
+
+            if (NPCNdx.InClan)
+            {
+              if (NPCNdx.ClanID[0] == PClan->ClanID[0] &&
+                NPCNdx.ClanID[1] == PClan->ClanID[1])
+              {
+                rputs("|0BI am in your clan already.\n");
+                break;
+              }
+              if (NPCInfo->Loyalty == 10)
+              {
+                rputs("|0BSorry, I am already in a clan and cannot join yours.\n");
+                break;
+              }
+              else
+              {
+                // add it on as a new topic
+                NPCInfo->Topics[ NPCInfo->KnownTopics ].Active = TRUE;
+                NPCInfo->Topics[ NPCInfo->KnownTopics ].Known = TRUE;
+                NPCInfo->Topics[ NPCInfo->KnownTopics ].ClanInfo = TRUE;
+
+                GetClanNameID(szClanName, NPCNdx.ClanID);
+                strcpy(NPCInfo->Topics[ NPCInfo->KnownTopics ].szName,
+                  szClanName);
+
+                sprintf(szString, "I'm already in a clan called %s.\n\n", szClanName);
+                rputs(szString);
+              }
+            }
+            else
+            {
+              if (NumMembers(PClan, FALSE) == 6)
+              {
+                rputs("Your clan already has the max. amount of members in it.\n\n");
+                break;
+              }
+
+              // set NPC.DAT file so it says he is in a clan
+              // right now and set which clan (this one)
+
+                          NPCNdx.InClan = TRUE;
+                          NPCNdx.ClanID[0] = PClan->ClanID[0];
+                          NPCNdx.ClanID[1] = PClan->ClanID[1];
+
+              NPC_AddNPCMember(szNPCIndex);
+
+              sprintf(szString, "|0B%s |0Cjoins your clan!\n",
+                NPCInfo->szName);
+              rputs(szString);
+
+              NPC_UpdateNPCNdx(szNPCIndex, &NPCNdx);
+            }
+          }
+          else if (CommandType == 30)
+          {
+            Done = TRUE;
+            EndedChat = TRUE;
+          }
+          break;
+        case 11 : // AddEnemy
+          // read in text
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+          fread(Buffer, DataLength, 1, FileHeader.fp);
+          WhichEnemy = Buffer[ DataLength-1 ];
+
+          // find slot in enemy clan
+          for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+            if (EnemyClan->Member[iTemp] == NULL) break;
+
+          EmptySlot = iTemp;
+
+          EnemyClan->Member[EmptySlot] = malloc(sizeof(struct pc));
+          CheckMem(EnemyClan);
+
+          strcpy(szNPCFileName, Buffer);
+
+          NPC_GetNPC(EnemyClan->Member[EmptySlot], szNPCFileName, WhichEnemy);
+          EnemyClan->Member[EmptySlot]->MyClan = EnemyClan;
+          break;
+        case 31 :  // Input keyword
+
+          for (iTemp = 0; iTemp < MAX_OPTIONS; iTemp++)
+          {
+            if (pszOptionNames[iTemp])
+            {
+              free(pszOptionNames[iTemp]);
+              pszOptionNames[iTemp] = NULL;
+            }
+
+            // free labels
+            if (apszLabels[iTemp])
+            {
+              free(apszLabels[iTemp]);
+              apszLabels[iTemp] = NULL;
+            }
+
+          }
+
+          // get first input
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+          // this datalength represents length of label
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+          apszLabels[0] = malloc(DataLength);
+          CheckMem(apszLabels[0]);
+          fread(apszLabels[0], DataLength, 1, FileHeader.fp);
+
+          // this datalength represents length of option
+          fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+          pszOptionNames[0] = malloc(DataLength);
+          CheckMem(pszOptionNames[0]);
+          fread(pszOptionNames[0], DataLength, 1, FileHeader.fp);
+
+          for (CurOption = 1; CurOption < MAX_OPTIONS; )
+          {
+            OldOffset = ftell(FileHeader.fp);
+
+            // read in command type
+            fread(&CommandType, sizeof(char), 1, FileHeader.fp);
+
+            // if not an Input command, skip back and quit
+            if (CommandType != 31)
+            {
+              break;
+            }
+
+            // read in szLegal
+            szLegal[0] = 0;
+            fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+            fread(szLegal, DataLength, 1, FileHeader.fp);
+
+            // see if legal, if not, skip
+            if (szLegal[0] && legal(szLegal, NULL) == FALSE)
+            {
+              // skip it
+              fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+              fseek(FileHeader.fp, DataLength, SEEK_CUR);
+              continue;
+            }
+            else
+            {
+              // else is legal, read in label + option name
+              fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+              // this datalength represents length of label
+              fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+              apszLabels[CurOption] = malloc(DataLength);
+              CheckMem(apszLabels[CurOption]);
+              fread(apszLabels[CurOption], DataLength, 1, FileHeader.fp);
+
+              // this datalength represents length of option
+              fread(&DataLength, sizeof(char), 1, FileHeader.fp);
+
+              pszOptionNames[CurOption] = malloc(DataLength);
+              CheckMem(pszOptionNames[CurOption]);
+              fread(pszOptionNames[CurOption], DataLength, 1, FileHeader.fp);
+
+            }
+
+            CurOption++;
+          }
+          NumOptions = CurOption;
+
+          // get input from user
+          GetStringChoice(pszOptionNames, NumOptions, "|0GChoose one\n|0E> |07", &WhichOption,
+            TRUE, DT_LONG, FALSE);
+
+          /* if that option has nextline to "jump" to, keep
+             going in same block of data */
+          if (stricmp(apszLabels[WhichOption], "NextLine") == 0)
+          {
+            fseek(FileHeader.fp, OldOffset, SEEK_SET);
+            break;
+          }
+
+          /* if that option has "STOP" to "jump" to, stop */
+          else if (stricmp(apszLabels[WhichOption], "Stop") == 0)
+          {
+            Done = TRUE;
+            break;
+          }
+
+          if (WhichOption == -1)
+          {
+            fseek(FileHeader.fp, OldOffset, SEEK_SET);
+            break;
+          }
+
+          /* else, look for new spot to jump to */
+          JumpToEvent(apszLabels[WhichOption], &FileHeader);
+          break;
+        case 26 : // EndQ
+          // no data, just end
+          Done = TRUE;
+          break;
+      }
+    }
+
+    /* free optionnames */
+    /* free labels */
+    for (iTemp = 0; iTemp < MAX_OPTIONS; iTemp++)
+    {
+      if (pszOptionNames[iTemp])
+      {
+        free(pszOptionNames[iTemp]);
+        pszOptionNames[iTemp] = NULL;
+      }
+
+      if (apszLabels[iTemp])
+      {
+        free(apszLabels[iTemp]);
+        apszLabels[iTemp] = NULL;
+      }
+    }
+
+    fclose(FileHeader.fp);
+
+    // free strings
+    free(szString);
+    free(szLegal);
+    free(Buffer);
+    free(szLabel);
+    free(szLabel1);
+    free(szLabel2);
+    free(szLabel3);
+
+    // free up enemies found
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      if (EnemyClan->Member[iTemp])
+      {
+        free(EnemyClan->Member[iTemp]);
+        EnemyClan->Member[iTemp] = NULL;
+      }
+
+    if (EnemyClan)
+    {
+      free(EnemyClan);
+      EnemyClan = NULL;
+    }
+
+
+    // reset health
+
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp] && PClan->Member[iTemp]->Status == Here)
+      {
+        PClan->Member[iTemp]->HP = PClan->Member[iTemp]->MaxHP;
+        PClan->Member[iTemp]->MaxSP = PClan->Member[iTemp]->MaxSP;
+      }
+    }
+
+
+
+    if (QuoteToggle)
+    {
+      if (EndedChat)
+      {
+        door_pause();
+        return TRUE;
+      }
+      else
+        return FALSE;
+    }
+    else
+      return (QuestDone);
+	(void)CurEvent;
+	(void)pcBrace;
+	(void)Key;
+	(void)FoundEvent;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Quests_GoQuest ( void )
+  {
+    _INT16 iTemp, TotalQuests = 0, WhichQuest, NumQuestsDone, QuestIndex[64];
+    BOOL QuestDone, QuestKnown;
+    char KnownBitSet, DoneBitSet;
+    char szString[50], cInput;
+
+    // tell him how many quests he's done right here for now since i'm too lazy
+    for (iTemp = 0, NumQuestsDone = 0; iTemp < MAX_QUESTS; iTemp++)
+    {
+      if (PClan->QuestsDone[ iTemp/8 ] & (1 << (iTemp%8)))
+        NumQuestsDone++;
+    }
+
+    for (;;)
+    {
+      sprintf(szString, " |0CQuests Completed:  |0B%d\n", NumQuestsDone);
+      rputs(szString);
+      rputs(ST_LONGLINE);
+
+      /* List quests known and not completed */
+      /* <pause> where needed */
+      TotalQuests = 0;
+      for (iTemp = 0; iTemp < MAX_QUESTS; iTemp++)
+      {
+        KnownBitSet =
+          (PClan->QuestsKnown[ iTemp/8 ] & (1 << (iTemp%8)) ||
+          (Quests[iTemp].Known && Quests[iTemp].Active));
+        DoneBitSet  = PClan->QuestsDone[ iTemp/8 ] & (1 << (iTemp%8));
+
+        // quest known? AND not complete?
+        if ( KnownBitSet && !DoneBitSet && Quests[iTemp].pszQuestName)
+        {
+          // show quest then
+          sprintf(szString, " |0A(|0B%c|0A) |0C%s\n", TotalQuests + 'A',
+            Quests[iTemp].pszQuestName);
+          rputs(szString);
+          QuestIndex[TotalQuests] = iTemp;
+          TotalQuests++;
+        }
+      }
+
+      if (TotalQuests == 0)
+      {
+        rputs("\n|12You do not know of any quests.\n%P");
+        return;
+      }
+
+      rputs(ST_LONGLINE);
+      rputs(" |0GWhich quest? (Enter=abort)|0E> |0F");
+      /* get choice from user on which quest to complete */
+      for (;;)
+      {
+        cInput = toupper(od_get_key(TRUE));
+
+        if (cInput == '\r' || cInput == '\n')
+        {
+          rputs(ST_ABORTED);
+          return;
+        }
+
+        /* run QUEST.EVT block here */
+        WhichQuest = cInput - 'A';
+        if (WhichQuest >= 0 && WhichQuest < TotalQuests)
+        {
+          break;
+        }
+      }
+
+      if (Quests[ QuestIndex[WhichQuest] ].pszQuestIndex == NULL)
+      {
+        rputs("\n|12Quest not found.\n%P");
+        return;
+      }
+
+      QuestKnown = PClan->QuestsKnown[ QuestIndex[WhichQuest]/8 ] & (char)(1 << (QuestIndex[WhichQuest]%8)) ||
+        (Quests[QuestIndex[WhichQuest]].Known && Quests[QuestIndex[WhichQuest]].Active);
+      QuestDone  = PClan->QuestsDone[ QuestIndex[WhichQuest]/8 ] & (char)(1 << (QuestIndex[WhichQuest]%8));
+
+      //od_printf("Comparing with %d\n", (1 << (QuestIndex[WhichQuest]%8)));
+
+      if (QuestKnown == FALSE || QuestDone || !Quests[QuestIndex[WhichQuest]].pszQuestName)
+      {
+        rputs("\n|12Quest not found.\n%P");
+        return;
+      }
+
+      // display name of quest
+      rputs(Quests[QuestIndex[WhichQuest]].pszQuestName); rputs("\n\n");
+
+      // show help
+      Help(Quests[ QuestIndex[WhichQuest] ].pszQuestName, "quests.hlp");
+      if (YesNo("\n|0SGo on this quest?") == YES)
+        break;
+
+      rputs("\n");
+    }
+
+    PClan->QuestToday = TRUE;
+
+    /* if successful (returns TRUE), set that quest bit to done */
+    if (RunEvent(FALSE,
+      Quests[QuestIndex[WhichQuest]].pszQuestFile, Quests[QuestIndex[WhichQuest]].pszQuestIndex,
+      NULL, NULL))
+    {
+      // set bit since quest completed
+      PClan->QuestsDone[ QuestIndex[WhichQuest]/8 ] |= (1<<(QuestIndex[WhichQuest]%8));
+    }
+    door_pause();
+  }
diff --git a/src/doors/clans-src/quests.h b/src/doors/clans-src/quests.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcaca475be45b4ad41d1ebcf35421c35fe6e1666
--- /dev/null
+++ b/src/doors/clans-src/quests.h
@@ -0,0 +1,18 @@
+struct PACKED Quest {
+	BOOL Active;
+	char *pszQuestName;
+	char *pszQuestIndex;
+	char *pszQuestFile;
+	BOOL Known;
+} PACKED;
+
+  void ClearFlags ( char *Flags );
+
+  BOOL RunEvent ( BOOL QuoteToggle, char *szEventFile, char *szEventName,
+    struct NPCInfo *NPCInfo, char *szNPCIndex );
+
+  void Quests_GoQuest ( void );
+
+
+  void Quests_Init ( void );
+  void Quests_Close ( void );
diff --git a/src/doors/clans-src/reg.c b/src/doors/clans-src/reg.c
new file mode 100644
index 0000000000000000000000000000000000000000..00d75d105231e3a2bb60c2f01e351f1f5ddd2c9b
--- /dev/null
+++ b/src/doors/clans-src/reg.c
@@ -0,0 +1,498 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Registration ADT
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <dos.h>
+#include <conio.h>
+#endif
+#include <ctype.h>
+
+#include "structs.h"
+#include "reg.h"
+#include "system.h"
+#include <OpenDoor.h>
+#include "door.h"
+#include "language.h"
+#include "mstrings.h"
+#include "video.h"
+
+#define PI        3.1415926
+#define MAX_CHARS		50						// max chars in a jumble
+#define HEXSEED 		0x7290F683				// used by "Jumble"
+
+extern struct {
+    long VideoType;
+    long y_lookup[25];
+    char FAR *VideoMem;
+  } Video;
+extern struct config *Config;
+extern struct Language *Language;
+
+void dputs (char *string);
+void AddRegToCfg(char *szString);
+
+  void Jumble ( char *szString )
+  {
+    char CurChar, MidChar, StrLength;
+    char *pcCurrentPos, szJumbled[MAX_CHARS+1];
+
+    pcCurrentPos = szJumbled;
+
+    // abcdef ->  fdbace
+    //
+    // abcd -> dbac
+
+    MidChar = strlen(szString)/2;
+
+    // middle char is simply first char in szString
+    *(pcCurrentPos + MidChar) = szString[0];
+
+    StrLength = strlen(szString);
+
+    for (CurChar = 1; CurChar < StrLength; CurChar++)
+    {
+      // if odd, subtract (curchar+1)/2 from pc...
+      if ( (CurChar%2) == 1)
+      {
+        *(pcCurrentPos + MidChar - (CurChar+1)/2) = szString[CurChar + 0];
+      }
+      else
+      {
+        // it's even, so, add it
+        *(pcCurrentPos + MidChar + (CurChar+1)/2) = szString[CurChar + 0];
+      }
+    }
+    *(pcCurrentPos + strlen(szString)) = 0;
+
+    strcpy(szString, szJumbled);
+  }
+
+
+  _INT16 IsRegged ( char *szSysopName, char *szBBSName, char *szRegCode )
+  {
+    unsigned long chksum = 0L;
+    unsigned long chksum2 = 0L, junk;
+    char szRealCode[40];
+    char szUserCode[40];
+    char *pc, *pc2, szString[155];
+    unsigned _INT16 c;
+    unsigned _INT16 c2;
+
+    // jumble user code once so a memory scan does nothing
+    Jumble(szUserCode);
+
+    if (!strlen(szSysopName))
+      return NFALSE;
+
+    strcpy(szString, szSysopName);
+    strcat(szString, szBBSName);
+
+    /* further encrypt 'em */
+    pc = szUserCode;
+    pc2 = szRegCode;
+    while (*pc2)
+    {
+      *pc = toupper(*pc2);
+      *pc ^= 0xD5;
+      pc++;
+      pc2++;
+    }
+    *pc = 0;
+
+    pc = szString;
+    while (*pc)
+    {
+      c = *pc;
+      chksum += (unsigned long)c;
+      pc++;
+    }
+
+    pc = szString;
+    while (*pc)
+    {
+      c = *pc;
+      chksum += ( (unsigned long)((double)c*(PI)) );
+      pc++;
+    }
+
+    pc = szString;
+    while (*pc)
+    {
+      c = *pc;
+      chksum += ( (unsigned long)c&HEXSEED );
+      pc++;
+      }
+
+    chksum2 = 0L;
+
+    pc = szString;
+    while (*pc)
+    {
+        *pc ^= 0xF7;
+      pc++;
+    }
+
+    pc = szString;
+    while (*pc)
+    {
+      c2 = *pc;
+      chksum2 += (unsigned long)c2;
+      pc++;
+    }
+
+    pc = szString;
+    while (*pc)
+    {
+      c2 = *pc;
+      chksum2 += ( (unsigned long)((double)c2*(PI)) );
+        pc++;
+    }
+
+    pc = szString;
+    while (*pc)
+    {
+        c2 = *pc;
+      chksum2 += ( (unsigned long)c2&HEXSEED );
+      pc++;
+    }
+
+
+    sprintf(szRealCode, "%lx%lx", chksum, chksum2);
+
+    // finally, jumble it all up 11 times ;)
+    Jumble(szRealCode);
+    junk = 0;
+    junk = 64;
+    Jumble(szRealCode);
+    junk = 254;
+    Jumble(szRealCode);
+    junk = 14;
+    Jumble(szRealCode);
+    junk = 213;
+    Jumble(szRealCode);
+    junk = 184;
+    junk = 121;
+    Jumble(szRealCode);
+
+    /* further encrypt 'em */
+    pc = szRealCode;
+    while (*pc)
+    {
+      *pc = toupper(*pc);
+      *pc ^= 0xD5;
+      pc++;
+    }
+
+    if (stricmp(szUserCode, szRealCode) == 0)
+      return NTRUE;
+    else
+      return NFALSE;
+  }
+
+  void Register ( void )
+  {
+#if !defined(__unix__) && !defined(_WIN32)
+    char szString[255], *pc, cKey;
+    BOOL InputCode;
+
+    clrscr();
+    dputs("壞泪潗睁檾泦甄悞渾亣攣湚�");
+
+    zputs("\n");
+    dputs("壟仑刎刎刎刎刎刎刎刎刎刎�");
+    zputs("\n");
+    zputs("\n");
+
+    cKey = 'D';
+    do
+    {
+      cKey = getch();
+    } while ( (cKey - 'K') != 0);
+
+    /* find '.' and get rid of it */
+    strcpy(szString, "WARNING: Inactivity timeout in 10 seconds, press a key now to remain online.\n");
+    Config_Init();
+
+    strcpy(szString, "Chat mode ended.\n");
+  //    sprintf(szString, "|03BBS Name     : |14%s\n", Config->szBBSName);
+    dputs("壟器麈整敇愓照照险");
+    zputs("|11");
+    zputs(Config->szBBSName);
+    zputs("\n");
+    strcpy(szString, "Unable to access serial port, cannot continue.\n");
+  //    zputs(szString);
+  //    sprintf(szString, "|03Sysop Name   : |14%s\n", Config->szSysopName);
+  //    zputs(szString);
+    dputs("壟奇寙殔整敇愓照险");
+    zputs("|11");
+    strcpy(szString, "No method of accessing serial port, cannot continue.\n");
+    zputs(Config->szSysopName);
+    zputs("\n");
+
+  //    zputs("\n|12Please ensure the above information matches the information on your\n");
+  //    zputs("registration certificate EXACTLY.\n\n");
+
+    zputs("\n");
+    strcpy(szString, "\nPress [ENTER]/[RETURN] to continue.");
+    dputs("壞清檺攩愓悰唨噽諄潗諗棜儛諟洆殗様仠殯諛攣枬悊諄潗諟洆殗様仠殯諝浾寶€�");
+    zputs("\n");
+    dputs("噽挏唩嚁仠殯諙悋仠摐枖亹震眙鲠�");
+    strcpy(szString, "\n%lu.%u.%ul.%d.ON.OFF.");
+    zputs("\n");
+
+    /* register the game */
+    zputs("\n");
+    dputs("壟甜泚悋諄潗諊悞渾亣攣湚浾枤憪諞殏�");
+    strcpy(szString, "YELLOW.WHITE.BROWN.GREY.BRIGHT.FLASHING");
+    zputs("\n");
+    dputs("壞乃");
+  //    zputs("|09Enter the registration code now.\n|11>");
+    strcpy(szString, Config->szRegcode);
+    // gotoxy(1,9);
+    Input(szString, 27);
+
+    if (stricmp(Config->szRegcode, szString) != 0)
+      InputCode = TRUE;
+
+    if(IsRegged(Config->szSysopName, Config->szBBSName, szString) == NTRUE)
+    {
+      /* add it to the .cfg file */
+      if (InputCode)
+        AddRegToCfg(szString);
+
+      //zputs("\n|15Registration approved!\n");
+      zputs("\n");
+      strcpy(szString, "BLACK.BLUE.GREEN.CYAN.RED.MAGENTA.");
+
+      dputs("壞犁悞渾亣攣湚浾攨厙殐悜�");
+      strcpy(szString,"仠殗厷敋攨亣");
+      zputs("\n");
+      /* write it to end of file */
+
+      zputs("\n");
+    }
+#endif
+  }
+
+  /* decrypt string and put it on screen exactly like zputs */
+  void dputs (char *string)
+  {
+#if !defined(__unix__) && !defined(_WIN32)
+//No Local for *nix
+    char block[80][2], number[3];
+    _INT16 attr;
+    char foreground, background, cur_attr;
+    char cDecrypted;
+    char cDigit1;
+    char cDigit2;
+    char *pcFrom;
+    _INT16 i, j,  x,y;
+    struct text_info TextInfo;
+    static char o_fg = 7, o_bg = 0;
+
+    gettextinfo(&TextInfo);
+    x = TextInfo.curx-1;
+    y = TextInfo.cury-1;
+
+    cur_attr = o_fg | o_bg;
+
+    pcFrom = string;
+
+    while (*pcFrom)
+    {
+      cDecrypted = ((*pcFrom) ^ 0xD5) + ' ';
+
+      if (y == 25)
+      {
+        /* scroll line up */
+        ScrollUp();
+        y = 24;
+      }
+      if (cDecrypted == '\b')
+      {
+        x--;
+        pcFrom++;
+        continue;
+      }
+      if (cDecrypted == '\r')
+      {
+        x = 0;
+        pcFrom++;
+        continue;
+      }
+      if (x == 80)
+      {
+        x = 0;
+        y++;
+
+        if (y == 25)
+        {
+          /* scroll line up */
+          ScrollUp();
+          y = 24;
+        }
+        break;
+      }
+      if (cDecrypted == '|')
+      {
+        cDigit1 = ((*(pcFrom+1)) ^ 0xD5) + ' ';
+        cDigit2 = ((*(pcFrom+2)) ^ 0xD5) + ' ';
+
+        if ( isdigit(cDigit1) && isdigit(cDigit2) )
+        {
+          number[0] = cDigit1;
+          number[1] = cDigit2;
+          number[2] = 0;
+
+          attr = atoi(number);
+
+          if (attr > 15)
+          {
+            background = attr - 16;
+            o_bg = background << 4;
+            attr = o_bg | o_fg;
+            cur_attr = attr;
+          }
+          else
+          {
+            foreground=attr;
+            o_fg=foreground;
+            attr = o_fg | o_bg;
+            cur_attr = attr;
+          }
+          pcFrom += 3;
+        }
+        else
+        {
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1)) ] = cDecrypted;
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1) + 1L)] = cur_attr;
+
+          pcFrom++;
+        }
+      }
+      else if (cDecrypted == '\n')
+      {
+        y++;
+        if (y == 25)
+        {
+          /* scroll line up */
+          ScrollUp();
+          y = 24;
+        }
+        pcFrom++;
+        x = 0;
+      }
+      else if (cDecrypted == 9)
+      {
+        /* tab */
+        pcFrom++;
+        for (i=0;i<8;i++) {
+          j = i + x;
+          if (j > 80) break;
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) ] = ' ';
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) + 1] = cur_attr;
+        }
+        x += 8;
+      }
+      else
+      {
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) ] = cDecrypted;
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) + 1] = cur_attr;
+
+        pcFrom++;
+        x++;
+      }
+    }
+
+    gotoxy(x+1,y+1);
+#endif
+  }
+
+  void AddRegToCfg(char *szString)
+  {
+    FILE *fp;
+    unsigned char szDude[] = "x!.g鴑gl鉵g  ";
+
+    szDude[ 1 ] = 'a';
+    szDude[ 0 ] = 'b';
+    szDude[ strlen(szDude) - 2 ] = 255;
+    szDude[ strlen(szDude) - 1 ] = 255;
+    szDude[ 2 ] = 'n';
+    szDude[ 5 ] = 'h';
+    szDude[ 4 ] = 's';
+
+    szDude[ 6 ] = szDude[ 9 ] = szDude[ 11 ] = 'a';
+
+    fp = fopen("clans.cfg", "a");
+    if (fp)
+    {
+      fprintf(fp, "\n\n%s  %s\n\n", szDude, szString);
+      fclose(fp);
+    }
+  }
+
+  void UnregMessage ( void )
+  {
+    char /*cKeyToPress,*/ szString[100];
+
+    if (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+      IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE)
+    {
+      rputs("`0EFreeware version.\n\n");
+      /*
+      od_clr_scr();
+      rputs(ST_REGMSG0);
+      rputs(ST_REGMSG1);
+      rputs(ST_REGMSG2);
+      rputs(ST_REGMSG3);
+      rputs(ST_REGMSG4);
+      rputs(ST_REGMSG5);
+      rputs(ST_REGMSG6);
+      cKeyToPress = random(26) + 'A';
+      sprintf(szString, "   |05Hit the |13%c |05key to continue.", cKeyToPress);
+      rputs(szString);
+
+      od_clear_keybuffer();
+      while (toupper(od_get_key(TRUE)) != cKeyToPress)
+        ;
+      od_clr_scr();
+
+      */
+    }
+    else
+    {
+      // say who regged to
+      sprintf(szString, ST_REGMSG7, Config->szSysopName, Config->szBBSName);
+      rputs(szString);
+    }
+  }
+
diff --git a/src/doors/clans-src/reg.h b/src/doors/clans-src/reg.h
new file mode 100644
index 0000000000000000000000000000000000000000..1ee1c6fd883cb8a744aca2635e4b94a7d9163a7a
--- /dev/null
+++ b/src/doors/clans-src/reg.h
@@ -0,0 +1,10 @@
+#define NTRUE     581           // "True" used for reg info
+#define NFALSE			0
+
+  void Jumble ( char *szString );
+
+  _INT16 IsRegged ( char *szSysopName, char *szBBSName, char *szRegCode );
+
+  void UnregMessage ( void );
+
+  void Register ( void );
diff --git a/src/doors/clans-src/reset.c b/src/doors/clans-src/reset.c
new file mode 100644
index 0000000000000000000000000000000000000000..eb3764babecaef91523d7d12f20058117642a772
--- /dev/null
+++ b/src/doors/clans-src/reset.c
@@ -0,0 +1,2591 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __unix__
+#include <curses.h>
+#include "unix_wrappers.h"
+#include <time.h>
+#define WORD short
+#else
+#include <conio.h>
+#include <dos.h>
+#include <share.h>
+# ifndef _WIN32
+#  include <mem.h>
+# else
+#  include <windows.h>
+# endif
+#endif
+#include <ctype.h>
+
+#include "structs.h"
+#include "parsing.h"
+#include "k_config.h"
+#include "myopen.h"
+#include "crc.h"
+
+#define MAX_OPTION		14
+
+#ifdef __unix__
+#define K_UP        KEY_UP
+#define K_DOWN		KEY_DOWN
+#define K_HOME		KEY_HOME
+#define K_END       KEY_END
+#define K_PGUP		KEY_PPAGE
+#define K_PGDN		KEY_NPAGE
+#define K_LEFT		KEY_LEFT
+#define K_RIGHT 	KEY_RIGHT
+#define K_BS        KEY_BACKSPACE
+#define GETCH_TYPE	int
+#else
+#define K_UP        72
+#define K_DOWN			80
+#define K_HOME			71
+#define K_END       79
+#define K_PGUP			73
+#define K_PGDN			81
+#define K_LEFT			75
+#define K_RIGHT 		77
+#define K_BS			8
+#define GETCH_TYPE	char
+#endif
+
+#define HILIGHT     11|(1<<4)
+
+#define COLOR	0xB800
+#define MONO	0xB000
+
+/* reset types */
+#define RESET_LOCAL     1   // normal reset -- local, NO ibbs junk
+#define RESET_JOINIBBS  2   // joining an IBBS league game
+#define RESET_LC        3   // leaguewide reset by LC
+
+
+#define FIGHTSPERDAY	12
+#define CLANCOMBATADAY	5
+
+
+char get_answer( char *szAllowableChars );
+void qputs (char *string, _INT16 x, _INT16 y);
+void xputs (char *string, _INT16 x, _INT16 y);
+
+#ifndef USE_STDIO
+void Video_Init ( void );
+#endif
+
+void ResetMenu( BOOL InterBBSGame );
+void zputs (char *string);
+
+_INT16 NoYes( char *Query );
+_INT16 YesNo( char *Query );
+
+void EditOption ( _INT16 WhichOption );
+void DosHelp ( char *Topic, char *File );
+
+#ifndef USE_STDIO
+long DosGetLong( char *Prompt, long DefaultVal, long Maximum );
+void DosGetStr(char *InputStr, _INT16 MaxChars);
+#endif
+
+#ifdef __unix__
+void set_attrs(unsigned short int attribute);
+short curses_color(short color);
+#endif
+
+void ColorArea( _INT16 xPos1, _INT16 yPos1, _INT16 xPos2, _INT16 yPos2, char Color );
+void GoReset ( struct ResetData *ResetData, _INT16 Option );
+
+void Config_Init ( void );
+void Config_Close ( void );
+
+void News_AddNews(char *szString);
+void News_CreateTodayNews ( void );
+
+void CreateVillageDat ( struct ResetData *ResetData );
+void KillAlliances( void );
+
+void System_Error ( char *szErrorMsg );
+
+void UpdateOption (char Option);
+
+struct {
+  long VideoType;
+  long y_lookup[25];
+  char FAR *VideoMem;
+} Video;
+
+struct ResetData ResetData;
+
+struct config *Config;
+struct game Game = { FALSE, NULL };
+
+char szTodaysDate[11];
+
+//extern unsigned _stklen = 32U*(1024U);
+
+#if defined(_WIN32)
+void gotoxy(int x, int y);
+void clrscr(void);
+void settextattr(WORD);
+void * save_screen(void);
+void restore_screen(void *);
+
+typedef void * SCREENSTATE;
+#elif defined(__unix__)
+	WINDOW *savedwin;
+	void gotoxy(int x, int y);
+	void clrscr(void);
+	void settextattr(WORD);
+	void save_screen(void);
+	void restore_screen(void);
+
+	typedef void * SCREENSTATE;
+#endif
+
+int main ( void )
+{
+#ifndef _WIN32
+  struct date thedate;
+#else
+  SYSTEMTIME system_time;
+#endif
+
+#ifndef USE_STDIO
+	Video_Init();
+#endif
+	Config_Init();
+
+#ifdef __unix__
+	atexit((void *)endwin);
+#endif
+
+  // initialize date
+#ifndef _WIN32
+  getdate(&thedate);
+  sprintf(szTodaysDate, "%02d/%02d/%4d", thedate.da_mon, thedate.da_day, thedate.da_year);
+#else
+  GetSystemTime(&system_time);
+  sprintf(szTodaysDate, "%02d/%02d/%4d", system_time.wMonth, system_time.wDay,
+          system_time.wYear);
+#endif
+
+  // load up config
+
+  ResetMenu( Config->InterBBS );
+
+#ifdef _WIN32
+  SetConsoleTextAttribute (
+    GetStdHandle (STD_OUTPUT_HANDLE),
+    (WORD)7);
+#endif
+#ifdef __unix__
+		curs_set(1);
+#endif	  
+  return (0);
+}
+
+char *StrYesNo ( BOOL value )
+{
+	if (value == TRUE)
+		return "Yes";
+	return "No";
+}
+
+void ResetMenu( BOOL InterBBSGame )
+{
+#ifdef USE_STDIO
+	char szString[50];
+  	BOOL Quit = FALSE, DidReset = FALSE, InterBBS = FALSE;
+	_INT16 iTemp, CurOption;
+
+	/* show options */
+
+	/* init defaults */
+	strcpy(ResetData.szDateGameStart, szTodaysDate);
+	strcpy(ResetData.szLastJoinDate,  "12/16/2199");
+	strcpy(ResetData.szVillageName,  "The Village");
+	ResetData.InterBBSGame = Config->InterBBS;
+	ResetData.LeagueWide = FALSE;
+	ResetData.InProgress = FALSE;
+	ResetData.EliminationMode = FALSE;
+	ResetData.ClanTravel = TRUE;
+	ResetData.LostDays = 3;
+	ResetData.ClanEmpires = TRUE;
+	ResetData.MineFights = FIGHTSPERDAY;
+	ResetData.ClanFights = CLANCOMBATADAY;
+	ResetData.DaysOfProtection = 4;
+	ResetData.MaxPermanentMembers = 4;
+
+
+	while (!Quit)
+	{
+	  	printf("\n\nReset for The Clans %s\n" VERSION);
+	  	printf("----------------------------------------------------------------------------\n");
+		printf("1)  Game start date %s\n",ResetData.szDateGameStart);
+		printf("2)  Last date to join game %s\n",ResetData.szLastJoinDate);
+		printf("3)  Village Name %s\n",ResetData.szVillageName);
+		printf("4)  Elimination mode %s\n",StrYesNo(ResetData.EliminationMode));
+		printf("5)  Allow interBBS clan travel %s\n",StrYesNo(ResetData.ClanTravel));
+		printf("6)  Days before lost troops/clans return %d\n",ResetData.LostDays);
+		printf("7)  Allow clan empires %s\n",StrYesNo(ResetData.ClanEmpires));
+		printf("8)  Mine fights per day %d\n",ResetData.MineFights);
+		printf("9)  Clan fights per day %d\n",ResetData.ClanFights);
+		printf("10) Max. Permanent Clan Members %d\n",ResetData.MaxPermanentMembers);
+		printf("11) Days of Protection for new users %d\n",ResetData.DaysOfProtection);
+		if (Config->InterBBS)
+		{
+			printf("13) Join a league\n");
+			if (Config->BBSID == 1)
+				printf("14) Leaguewide reset with these settings\n");
+		}
+		else
+		{
+			printf("12) Reset local game with these settings\n");
+		}
+		printf("15) Abort reset\n");
+		printf("----------------------------------------------------------------------------\n");
+
+		printf("\nChoose: ");
+		scanf("%d",&CurOption);
+		--CurOption;
+		if (!Config->InterBBS && CurOption >= (MAX_OPTION-2) &&
+			CurOption < MAX_OPTION)
+			continue;
+		else if (Config->BBSID == 1 && Config->InterBBS && CurOption == (MAX_OPTION-2))
+			continue;
+		else if (Config->BBSID != 1 && CurOption == (MAX_OPTION-1))
+		{
+			continue;
+		}
+
+		if (CurOption == MAX_OPTION)
+		{
+			Quit = TRUE;
+			DidReset = FALSE;
+		}
+		else if (CurOption == (MAX_OPTION-3))
+		{
+			// can't reset locally here
+	        if (Config->InterBBS)
+				continue;
+
+			/* reset local now */
+			// ask one last time, are you sure?
+	        if (YesNo("Are you sure you wish to reset?") == NO)
+			{
+				break;
+			}
+
+	        GoReset(&ResetData, RESET_LOCAL);
+			Quit = TRUE;
+			DidReset = TRUE;
+		}
+		else if (CurOption == (MAX_OPTION-2))
+		{
+			// ask one last time, are you sure?
+			printf("\n\n");
+			if (YesNo("Are you sure you are joining a league?") == NO)
+			{
+				break;
+			}
+			/* join league NOT in progress */
+			ResetData.LeagueWide = TRUE;
+			ResetData.InProgress = FALSE;
+   		    GoReset(&ResetData, RESET_JOINIBBS);
+			Quit = TRUE;
+			DidReset = TRUE;
+	        InterBBS = TRUE;
+		}
+		else if (CurOption == (MAX_OPTION-1))
+		{
+			// ask one last time, are you sure?
+			printf("\n\n");
+			if (YesNo("Are you sure you wish to reset the league?") == NO)
+			{
+				break;
+			}
+			/* leaguewide reset now */
+			ResetData.LeagueWide = TRUE;
+			GoReset(&ResetData, RESET_LC);
+			Quit = TRUE;
+			DidReset = TRUE;
+	        InterBBS = TRUE;
+		}
+		else
+	        EditOption(CurOption);
+	}
+
+	printf("\n\n");
+
+	if (DidReset)
+	{
+		printf("> Your game has been reset.\n");
+	    if (InterBBS)
+			printf("> You must now type 'CLANS /I' to complete the IBBS reset.");
+	}
+	else
+		printf("> The game was not reset.  No changes were made.\n");
+
+#else
+	char CurOption = 0;
+	GETCH_TYPE	cInput;
+      char OldOption = -1;
+  BOOL Quit = FALSE, DidReset = FALSE, InterBBS = FALSE;
+//	_INT16 iTemp;
+
+	/* clear all */
+	clrscr();
+
+	/* show options */
+  qputs(" |03Reset for The Clans " VERSION, 0,0);
+  qputs("|09- |01---------------------------------------------------------------------------",0,1);
+	xputs(" Game start date", 0, 2);
+	xputs(" Last date to join game", 0, 3);
+	xputs(" Village Name", 0, 4);
+	xputs(" Elimination mode", 0, 5);
+
+	xputs(" Allow interBBS clan travel", 0, 6);
+	xputs(" Days before lost troops/clans return", 0, 7);
+	xputs(" Allow clan empires", 0, 8);
+	xputs(" Mine fights per day", 0, 9);
+	xputs(" Clan fights per day", 0, 10);
+
+	xputs(" Max. Permanent Clan Members", 0, 11);
+	xputs(" Days of Protection for new users", 0, 12);
+
+	xputs(" Reset local game with these settings", 0, 13);
+	xputs(" Join a league", 0, 14);
+	xputs(" Leaguewide reset with these settings", 0, 15);
+	xputs(" Abort reset", 0, 16);
+  qputs("|01--------------------------------------------------------------------------- |09-",0,17);
+
+  qputs("|09 Press the up and down keys to navigate.", 0, 18);
+
+	/* init defaults */
+  strcpy(ResetData.szDateGameStart, szTodaysDate);
+  strcpy(ResetData.szLastJoinDate,  "12/16/2199");
+	strcpy(ResetData.szVillageName,  "The Village");
+	ResetData.InterBBSGame = Config->InterBBS;
+	ResetData.LeagueWide = FALSE;
+	ResetData.InProgress = FALSE;
+	ResetData.EliminationMode = FALSE;
+	ResetData.ClanTravel = TRUE;
+	ResetData.LostDays = 3;
+	ResetData.ClanEmpires = TRUE;
+      ResetData.MineFights = FIGHTSPERDAY;
+	ResetData.ClanFights = CLANCOMBATADAY;
+	ResetData.DaysOfProtection = 4;
+	ResetData.MaxPermanentMembers = 4;
+
+	ColorArea(0,2+MAX_OPTION, 39, 2+MAX_OPTION, 7);
+	gotoxy(2, CurOption+3);
+
+	/* dehilight all options */
+	ColorArea(39,2, 76, 16, 15);	// choices on the right side
+
+      ColorArea(0, 2, 39, MAX_OPTION+2, 7);
+
+	/* dehilight options which can't be activated */
+      if (!Config->InterBBS)
+	{
+/*			ColorArea(0,2, 39, 13, 7); */
+		ColorArea(0,14, 76, 15,  8);
+	}
+      else if (Config->BBSID != 1)
+	{
+		// not LC, can't use leaguewide reset option
+/*			ColorArea(0,2, 39, 16, 7); */
+		ColorArea(0,15, 76, 15, 8);
+		ColorArea(0,13, 39, 13, 8);
+	}
+	else
+      {
+            // LC's BBS AND IBBS set
+/*                  ColorArea(0,2, 39, 16, 7); */
+            ColorArea(0,13, 39, 14, 8);
+      }
+
+#if defined(_WIN32) || defined (__unix__)
+      settextattr((WORD)15);
+#endif
+	/* show data */
+      UpdateOption(0);
+	UpdateOption(1);
+	UpdateOption(2);
+	UpdateOption(3);
+	UpdateOption(4);
+	UpdateOption(5);
+	UpdateOption(6);
+	UpdateOption(7);
+	UpdateOption(8);
+	UpdateOption(9);
+	UpdateOption(10);
+
+	while (!Quit)
+	{
+            if (OldOption != CurOption)
+		{
+                  if (OldOption != -1)
+		            ColorArea(0, (_INT16)(OldOption+2), 39, (_INT16)(OldOption+2), 7);
+                  OldOption = CurOption;
+			/* show which is highlighted */
+      	      ColorArea(0, (_INT16)(CurOption+2), 39, (_INT16)(CurOption+2), HILIGHT);
+            	/* Unhighlight old option */
+		}
+
+		cInput = getch();
+#ifdef __MSDOS__
+		if (cInput == 0)
+#elif defined(_WIN32)
+		if (cInput == 0 || cInput == (char)0xE0)
+#elif defined(__unix__)
+		if (cInput > 256)
+#endif /* !_WIN32 */
+		{
+#ifndef __unix__
+			cInput = getch();
+#endif
+			switch ( cInput )
+			{
+				case K_UP	:
+				case K_LEFT :
+					if (CurOption == 0)
+						CurOption = MAX_OPTION;
+					else
+						CurOption--;
+                              if ((CurOption == (MAX_OPTION-1)) && (Config->BBSID != 1))
+                                    CurOption--;
+                              if ((CurOption == (MAX_OPTION-2)) && ((Config->InterBBS == FALSE) || (Config->BBSID == 1)))
+                                    CurOption--;
+                              if ((CurOption == (MAX_OPTION-3)) && Config->InterBBS)
+                                    CurOption--;
+					break;
+				case K_DOWN :
+				case K_RIGHT:
+					if (CurOption == MAX_OPTION)
+						CurOption = 0;
+					else
+						CurOption++;
+                              if ((CurOption == (MAX_OPTION-3)) && Config->InterBBS)
+                                    CurOption++;
+                              if ((CurOption == (MAX_OPTION-2)) && ((Config->InterBBS == FALSE) || (Config->BBSID == 1)))
+                                    CurOption++;
+                              if ((CurOption == (MAX_OPTION-1)) && (Config->BBSID != 1))
+                                    CurOption++;
+					break;
+				case K_HOME :
+				case K_PGUP :
+					CurOption = 0;
+					break;
+				case K_END :
+				case K_PGDN :
+					CurOption = MAX_OPTION;
+					break;
+			}
+		}
+		else if (cInput == 0x1B)
+			Quit = TRUE;
+		else if (cInput == 13)
+		{
+            	if (Config->InterBBS == FALSE && CurOption >= (MAX_OPTION-2) &&
+				CurOption < MAX_OPTION)
+				continue;
+	            else if (Config->BBSID == 1 && Config->InterBBS && CurOption == (MAX_OPTION-2))
+      	            continue;
+           		else if (Config->BBSID != 1 && CurOption == (MAX_OPTION-1))
+			{
+				continue;
+			}
+
+			if (CurOption == MAX_OPTION)
+			{
+				Quit = TRUE;
+				DidReset = FALSE;
+			}
+			else if (CurOption == (MAX_OPTION-3))
+			{
+#if defined(_WIN32)
+                        SCREENSTATE screen_state;
+#endif
+				// can't reset locally here
+		            if (Config->InterBBS)
+					continue;
+	
+				/* reset local now */
+				// ask one last time, are you sure?
+#if defined(_WIN32)
+                        screen_state = save_screen();
+#elif defined(__unix__)
+						save_screen();
+#endif
+				clrscr();
+	      	      if (YesNo("|07Are you sure you wish to reset?") == NO)
+				{
+#if defined(_WIN32)
+                              restore_screen(screen_state);
+	 				break;
+#elif defined(__unix__)
+								restore_screen();
+					break;
+#endif
+				}
+
+	      	      GoReset(&ResetData, RESET_LOCAL);
+				Quit = TRUE;
+				DidReset = TRUE;
+#if defined(_WIN32)
+                              restore_screen(screen_state);
+	 				break;
+#elif defined(__unix__)
+								restore_screen();
+					break;
+#endif
+			}
+			else if (CurOption == (MAX_OPTION-2))
+			{
+#if defined(_WIN32)
+                        SCREENSTATE screen_state;
+                        screen_state = save_screen ();
+#elif  defined(__unix__)
+						save_screen();
+#endif
+
+				// ask one last time, are you sure?
+				clrscr();
+				if (YesNo("|07Are you sure you are joining a league?") == NO)
+				{
+#if defined(_WIN32)
+                              restore_screen(screen_state);
+#elif defined(__unix__)
+								restore_screen();
+#endif
+					break;
+				}
+				/* join league NOT in progress */
+				ResetData.LeagueWide = TRUE;
+				ResetData.InProgress = FALSE;
+      	      	GoReset(&ResetData, RESET_JOINIBBS);
+				Quit = TRUE;
+				DidReset = TRUE;
+			      InterBBS = TRUE;
+#if defined(_WIN32)
+                              restore_screen(screen_state);
+#elif defined(__unix__)
+								restore_screen();
+#endif
+			}
+			else if (CurOption == (MAX_OPTION-1))
+			{
+#if defined(_WIN32)
+                        SCREENSTATE screen_state;
+                        screen_state = save_screen ();
+#elif  defined(__unix__)
+						save_screen();
+#endif
+				// ask one last time, are you sure?
+				clrscr();
+				if (YesNo("|07Are you sure you wish to reset the league?") == NO)
+				{
+#if defined(_WIN32)
+                              restore_screen(screen_state);
+#elif defined(__unix__)
+								restore_screen();
+#endif
+					break;
+				}
+					/* leaguewide reset now */
+				ResetData.LeagueWide = TRUE;
+				GoReset(&ResetData, RESET_LC);
+				Quit = TRUE;
+				DidReset = TRUE;
+		      	InterBBS = TRUE;
+#if defined(_WIN32)
+                              restore_screen(screen_state);
+#elif defined(__unix__)
+								restore_screen();
+#endif
+			}
+			else
+			{
+	            	EditOption(CurOption);
+				UpdateOption(CurOption);
+			}
+		}	
+	}
+
+	clrscr();
+
+	if (DidReset)
+	{
+    		qputs("|09> |07Your game has been reset.", 0,0);
+    		if (InterBBS)
+      		qputs("|09> |03You must now type |11CLANS /I |03to complete the IBBS reset.", 0,1);
+	}
+	else
+    		qputs("|09> |07The game was not reset.  No changes were made.", 0,0);
+
+	gotoxy(1,3);
+#endif
+}
+
+
+  void CheckMem ( void *Test )
+    /*
+     * Gives system error if the pointer is NULL.
+     */
+  {
+    if (Test == NULL)
+    {
+      printf("Checkmem Failed.\n");
+#ifdef __unix__
+		curs_set(1);
+#endif	  
+      exit(0);
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+#ifndef USE_STDIO
+  void qputs (char *string, _INT16 x, _INT16 y)
+  {
+#if defined(__MSDOS__)
+    char number[3];
+    _INT16 cur_char, attr;
+    char foreground, background, cur_attr;
+    static o_fg = 7, o_bg = 0;
+    _INT16 i, j;
+
+    cur_attr = o_fg | o_bg;
+    cur_char=0;
+
+    while (1) {
+      if (string[cur_char] == 0)
+        break;
+      if (x == 80)
+        break;
+      if (string[cur_char]=='|')    {
+        if ( isdigit(string[cur_char+1]) )  {
+          number[0]=string[cur_char+1];
+          number[1]=string[cur_char+2];
+          number[2]=0;
+
+          attr=atoi(number);
+          if (attr>15)  {
+            background=attr-16;
+            o_bg = background << 4;
+            attr = o_bg | o_fg;
+            cur_attr = attr;
+          }
+          else  {
+            foreground=attr;
+            o_fg=foreground;
+            attr = o_fg | o_bg;
+            cur_attr = attr;
+          }
+          cur_char += 3;
+        }
+        else  {
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1)) ] = string[cur_char];
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1) + 1L)] = cur_attr;
+
+          cur_char++;
+          x++;
+        }
+      }
+      else if (string[cur_char] == '\n')  {
+        y++;
+        cur_char++;
+        x = 0;
+      }
+      else if (string[cur_char] == 9)  {  // tab
+        cur_char++;
+        for (i=0;i<8;i++) {
+          j = i+x;
+          if (j > 80) break;
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) ] = ' ';
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) + 1] = cur_attr;
+        }
+        x += 8;
+      }
+      else  {
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) ] = string[cur_char];
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) + 1] = cur_attr;
+
+        cur_char++;
+        x++;
+      }
+    }
+#else
+    gotoxy(x, y);
+    zputs(string);
+#endif
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  long Video_VideoType ( void )
+  {
+    return Video.VideoType;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  char FAR *vid_address ( void )
+  {
+#ifdef __MSDOS__
+    _INT16 tmp1, tmp2;
+    asm {
+      mov bx,0040h
+      mov es,bx
+      mov dx,es:63h
+      add dx,6
+      mov tmp1, dx           // move this into status port
+    };
+    Video.VideoType = COLOR;
+
+    asm {
+      mov bx,es:10h
+      and bx,30h
+      cmp bx,30h
+      jne FC1
+    };
+    Video.VideoType = MONO;
+
+    FC1:
+
+    if (Video.VideoType == MONO)
+      return ( ( void FAR * ) 0xB0000000L) ;
+    else
+      return ( ( void FAR * ) 0xB8000000L) ;
+#elif defined(_WIN32)
+    Video.VideoType = COLOR;
+    return NULL;
+#elif defined(__unix__)
+    Video.VideoType = COLOR;
+    return NULL;
+#else
+#endif
+  }
+
+  void ScrollUp ( void )
+  {
+#ifdef __MSDOS__
+    asm {
+      mov al,1    // number of lines
+      mov ch,0    // starting row
+      mov cl,0    // starting column
+      mov dh, 24  // ending row
+      mov dl, 79  // ending column
+      mov bh, 7   // color
+      mov ah, 6
+      _INT16 10h     // do the scroll
+    }
+#elif defined(_WIN32)
+    CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+    COORD top_left = { 0, 0 };
+    SMALL_RECT scroll;
+    CHAR_INFO char_info;
+
+    GetConsoleScreenBufferInfo (
+      GetStdHandle (STD_OUTPUT_HANDLE),
+      &screen_buffer);
+
+    scroll.Top = 1;
+    scroll.Left = 0;
+    scroll.Right = screen_buffer.dwSize.X - 1;
+    scroll.Bottom = screen_buffer.dwSize.Y - 1;
+
+    char_info.Char.UnicodeChar = (TCHAR)' ';
+    char_info.Attributes = screen_buffer.wAttributes;
+
+    ScrollConsoleScreenBuffer (
+      GetStdHandle (STD_OUTPUT_HANDLE),
+      &scroll,
+      NULL,
+      top_left,
+      &char_info);
+#elif defined(__unix__)
+    scrollok(stdscr,TRUE);
+    scrl(1);
+    scrollok(stdscr,FALSE);
+#endif
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Video_Init ( void )
+  {
+#ifdef __MSDOS__
+    _INT16 iTemp;
+    Video.VideoMem = vid_address();
+    for (iTemp = 0; iTemp < 25;  iTemp++)
+      Video.y_lookup[ iTemp ] = iTemp * 160;
+#elif defined(__unix__)
+	short fg;
+	short bg;
+	short pair=0;
+
+	// Initialize Curses lib.
+	initscr();
+	cbreak();
+	noecho();
+	nonl();
+//      intrflush(stdscr, FALSE);
+	keypad(stdscr, TRUE);
+	scrollok(stdscr,FALSE);
+	start_color();
+	curs_set(0);
+	clear();
+	refresh();
+
+	// Set up color pairs
+	for(bg=0;bg<8;bg++)  {
+		for(fg=0;fg<16;fg++) {
+			init_pair(++pair,curses_color(fg),curses_color(bg));
+		}
+	}
+
+#endif
+  }
+
+#ifdef __unix__
+short curses_color(short color)
+{
+        switch(color)
+        {
+			case 0 :
+				return(COLOR_BLACK);
+			case 1 :
+				return(COLOR_BLUE);
+			case 2 :
+				return(COLOR_GREEN);
+			case 3 :
+				return(COLOR_CYAN);
+			case 4 :
+				return(COLOR_RED);
+			case 5 :
+				return(COLOR_MAGENTA);
+			case 6 :
+				return(COLOR_YELLOW);
+			case 7 :
+				return(COLOR_WHITE);
+			case 8 :
+				return(COLOR_BLACK);
+			case 9 :
+				return(COLOR_BLUE);
+			case 10 :
+				return(COLOR_GREEN);
+			case 11 :
+				return(COLOR_CYAN);
+			case 12 :
+				return(COLOR_RED);
+			case 13 :
+				return(COLOR_MAGENTA);
+			case 14 :
+				return(COLOR_YELLOW);
+			case 15 :
+				return(COLOR_WHITE);
+        }
+        return(0);
+}
+#endif
+
+  void xputs (char *string, _INT16 x, _INT16 y)
+  {
+#ifdef __MSDOS__
+    char FAR *VidPtr;
+    VidPtr = Video.VideoMem + Video.y_lookup[y] + (x<<1);
+
+    while (x < 80 && *string)
+    {
+      *VidPtr = *string;
+
+      VidPtr += 2;
+      x++;
+      string++;
+    }
+#else
+    gotoxy(x, y);
+    while (x < 80 && *string)
+    {
+#ifdef __unix__
+		addch(*string);
+#else
+      fputc (*string, stdout);
+#endif
+      x++;
+      string++;
+    }
+#endif
+  }
+#endif
+
+_INT16 YesNo( char *Query )
+{
+#ifdef USE_STDIO
+	char answer[129];
+	printf("%s ([Yes]/No) ",Query);
+	fpurge(stdin);
+	fflush(stdout);
+	fgets(answer,128,stdin);
+	answer[strlen(answer)-1]=0;
+	if (answer[0]=='N' || answer[0]=='n')
+		return (NO);
+	return (YES);
+#else
+	/* show query */
+  zputs(Query);
+
+	/* show Yes/no */
+  zputs(" |01(|15Yes|07/no|01) |11");
+
+	/* get user input */
+  if (get_answer("YN\r\n") == 'N')
+	{
+		/* user says NO */
+    zputs("No\n");
+		return (NO);
+	}
+	else	/* user says YES */
+	{
+    zputs("Yes\n");
+		return (YES);
+	}
+#endif
+}
+
+_INT16 NoYes( char *Query )
+{
+#ifdef USE_STDIO
+	char answer[129];
+	printf("%s (Yes/[No])\n",Query);
+	fpurge(stdin);
+	fflush(stdout);
+	fgets(answer,128,stdin);
+	answer[strlen(answer)-1]=0;
+	if (answer[0]=='Y' || answer[0]=='y')
+		return (YES);
+	return (NO);
+#else
+	/* show query */
+  zputs(Query);
+
+  zputs(" |01(|07yes/|15No|01) |11");
+
+	/* get user input */
+  if (get_answer("YN\r\n") == 'Y')
+	{
+		/* user says YES */
+    zputs("Yes\n");
+		return (YES);
+	}
+	else	/* user says NO */
+	{
+    zputs("No\n");
+		return (NO);
+	}
+#endif
+}
+
+
+  void zputs (char *string)
+  {
+#ifndef USE_STDIO
+	char number[3];
+	_INT16 cur_char, attr;
+	char foreground, background, cur_attr;
+	_INT16 i, j,  x,y;
+      _INT16 scr_lines = 25, scr_width = 80;
+#ifdef __MSDOS__
+	struct text_info TextInfo;
+#elif defined(_WIN32)
+      CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+      COORD cursor_pos;
+      HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+      DWORD bytes_written;
+      TCHAR space_char = (TCHAR)' ';
+#endif
+	static char o_fg = 7, o_bg = 0;
+
+#ifdef __MSDOS__
+	gettextinfo(&TextInfo);
+	x = TextInfo.curx-1;
+	y = TextInfo.cury-1;
+#elif defined(_WIN32)
+      GetConsoleScreenBufferInfo (std_handle, &screen_buffer);
+      x = screen_buffer.dwCursorPosition.X;
+      y = screen_buffer.dwCursorPosition.Y;
+      scr_lines = screen_buffer.dwSize.Y;
+      scr_width = screen_buffer.dwSize.X;
+#elif defined(__unix__)
+	getyx(stdscr,y,x);
+#endif
+
+	cur_attr = o_fg | o_bg;
+    cur_char = 0;
+
+    for (;;)
+    {
+#ifdef _WIN32
+      /* Resync with x/y position */
+      cursor_pos.X = x;
+      cursor_pos.Y = y;
+      SetConsoleCursorPosition (std_handle, cursor_pos);
+#elif defined(__unix__)
+      /* Resync with x/y position */
+		move(y,x);
+#endif
+      if (y == scr_lines)
+      {
+        /* scroll line up */
+        ScrollUp();
+        y = scr_lines - 1;
+      }
+      if (string[cur_char] == 0)
+        break;
+      if (string[cur_char] == '\b')
+      {
+        x--;
+        cur_char++;
+        continue;
+      }
+      if (string[cur_char] == '\r')
+      {
+        x = 0;
+        cur_char++;
+        continue;
+      }
+      if (x == scr_width)
+      {
+        x = 0;
+        y++;
+
+        if (y == scr_lines)
+        {
+          /* scroll line up */
+          ScrollUp();
+          y = scr_lines - 1;
+        }
+        break;
+      }
+      if (string[cur_char]=='|')
+      {
+        if ( isdigit(string[cur_char+1]) && isdigit(string[cur_char+2]) )
+        {
+          number[0]=string[cur_char+1];
+          number[1]=string[cur_char+2];
+          number[2]=0;
+
+          attr=atoi(number);
+          if (attr>15)
+          {
+            background=attr-16;
+            o_bg = background << 4;
+            attr = o_bg | o_fg;
+            cur_attr = (char)attr;
+          }
+          else
+          {
+            foreground=(char)attr;
+            o_fg=foreground;
+            attr = o_fg | o_bg;
+            cur_attr = (char)attr;
+          }
+          cur_char += 3;
+        }
+        else
+        {
+#ifdef __MSDOS__
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1)) ] = string[cur_char];
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1) + 1L)] = cur_attr;
+#elif defined(_WIN32)
+          SetConsoleTextAttribute (std_handle, (WORD)cur_attr);
+          WriteConsole (std_handle, &string[cur_char], 1, &bytes_written, NULL);
+#elif defined(__unix__)
+	set_attrs(cur_attr);
+	addch(string[cur_char]);
+#endif
+
+          cur_char++;
+        }
+      }
+      else if (string[cur_char] == '\n')  {
+        y++;
+        if (y == scr_lines)
+        {
+          /* scroll line up */
+          ScrollUp();
+          y = scr_lines - 1;
+        }
+        cur_char++;
+        x = 0;
+      }
+      else if (string[cur_char] == 9)
+      {
+        /* tab */
+        cur_char++;
+        for (i=0;i<8;i++)
+        {
+          j = i + x;
+          if (j > scr_width) break;
+#ifdef __MSDOS__
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) ] = ' ';
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) + 1] = cur_attr;
+#elif defined(_WIN32)
+          SetConsoleTextAttribute (std_handle, (WORD)cur_attr);
+          WriteConsole (std_handle, &space_char, 1, &bytes_written, NULL);
+#elif defined(__unix__)
+	set_attrs(cur_attr);
+	addch(' ');
+#endif
+        }
+        x += 8;
+      }
+      else
+      {
+#ifdef __MSDOS__
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) ] = string[cur_char];
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) + 1] = cur_attr;
+#elif defined(_WIN32)
+        SetConsoleTextAttribute (std_handle, (WORD)cur_attr);
+        WriteConsole (std_handle, &string[cur_char], 1, &bytes_written, NULL);
+#elif defined(__unix__)
+	set_attrs(cur_attr);
+	addch(string[cur_char]);
+#endif
+
+        cur_char++;
+        x++;
+      }
+    }
+#ifdef __MSDOS__
+    gotoxy(x+1,y+1);
+#elif defined(_WIN32) || defined(__unix__)
+    gotoxy(x, y);
+#endif
+
+#ifdef __unix__
+	refresh();
+#endif
+#endif
+  }
+
+#ifdef __unix__
+void set_attrs(unsigned short int attribute)
+{
+        int   attrs=A_NORMAL;
+
+        if (attribute & 8)  {
+                attrs |= A_BOLD;
+        }
+        if (attribute & 128)
+                attrs |= A_BLINK;
+        attrset(COLOR_PAIR(attribute+1)|attrs);
+}
+#endif
+#ifndef USE_STDIO
+char get_answer( char *szAllowableChars )
+{
+	GETCH_TYPE cKey;
+	unsigned _INT16 iTemp;
+
+	for (;;)
+	{
+		cKey = getch();
+		if (cKey == K_BS)
+			cKey='\b';
+
+		/* see if allowable */
+		for (iTemp = 0; iTemp < strlen(szAllowableChars); iTemp++)
+		{
+			if (toupper(cKey) == toupper(szAllowableChars[iTemp]))
+				break;
+		}
+
+		if (iTemp < strlen(szAllowableChars))
+			break;	/* found allowable key */
+	}
+
+	return (toupper(cKey));
+}
+#endif
+
+void EditOption ( _INT16 WhichOption )
+{
+#ifdef USE_STDIO
+	char *aszHelp[11] = {
+		"Date Game Starts",
+		"Last Join Date",
+		"Village Name",
+		"Elimination Mode",
+		"Clan Travel",
+		"Lost Troops",
+		"Clan Empires",
+		"Mine Fights",
+		"Clan Combat",
+		"Max Permanent Members",
+		"Days Of Protection"
+		};
+	_INT16 Month, Day, Year;
+
+	printf("\n\n");
+
+	/* show help */
+	DosHelp(aszHelp[WhichOption], "reset.hlp");
+
+
+	switch ( WhichOption )
+	{
+		case 0 :	/* dategame started */
+			printf("\n");
+			printf("Enter Month: ");
+			scanf("%2d",&Month);
+			printf("Enter Day: ");
+			scanf("%2d",&Day);
+			printf("Enter Year: ");
+			scanf("%4d",&Year);
+			sprintf(ResetData.szDateGameStart, "%02d/%02d/%4d", Month, Day, Year);
+			break;
+		case 1 :	/* last join date */
+			printf("\n");
+			printf("Enter Month: ");
+			scanf("%2d",&Month);
+			printf("Enter Day: ");
+			scanf("%2d",&Day);
+			printf("Enter Year: ");
+			scanf("%4d",&Year);
+			sprintf(ResetData.szLastJoinDate, "%02d/%02d/%4d", Month, Day, Year);
+			break;
+		case 2 :	/* village name */
+			printf("\n");
+			printf("Please enter the village name: ");
+			fpurge(stdin);
+			fflush(stdout);
+			fgets(ResetData.szVillageName,29,stdin);
+			ResetData.szVillageName[strlen(ResetData.szVillageName)-1]=0;
+			break;
+		case 3 :	/* elimination mode? */
+			printf("\n");
+			if (YesNo("Setup elimination mode?") == YES)
+			{
+				ResetData.EliminationMode = TRUE;
+			}
+			else
+				ResetData.EliminationMode = FALSE;
+			break;
+		case 4 :	/* clan travel? */
+			printf("\n");
+			if (YesNo("Allow clans to travel?") == YES)
+			{
+				ResetData.ClanTravel = TRUE;
+			}
+			else
+				ResetData.ClanTravel = FALSE;
+			break;
+		case 5 :	/* days before lost troops return */
+			printf("\n");
+			printf("Days before lost troops/clans returned? ");
+			scanf("%2d",&ResetData.LostDays);
+			break;
+		case 6 :	/* clan empires? */
+			printf("\n");
+			if (YesNo("Allow clans to create empires?") == YES)
+			{
+				ResetData.ClanEmpires = TRUE;
+			}
+			else
+				ResetData.ClanEmpires = FALSE;
+			break;
+		case 7 :	/* mine fights */
+			printf("\n");
+			printf("How many mine fights per day? ");
+			scanf("%2d",&ResetData.MineFights);
+			break;
+		case 8 :	/* clan combat */
+			printf("\n");
+			printf("How many clan fights per day? ");
+			scanf("%3d",&ResetData.ClanFights);
+			break;
+		case 9 :	/* max permanent clan members */
+			printf("\n");
+			printf("How many members? ");
+			scanf("%d",&ResetData.MaxPermanentMembers);
+			if (ResetData.MaxPermanentMembers == 0)
+				ResetData.MaxPermanentMembers = 1;
+			break;
+		case 10:	/* days of protection */
+			printf("\n");
+			printf("How many days? ");
+			scanf("%d",&ResetData.DaysOfProtection);
+			break;
+	}
+#else
+	char *aszHelp[11] = {
+		"Date Game Starts",
+		"Last Join Date",
+		"Village Name",
+		"Elimination Mode",
+		"Clan Travel",
+		"Lost Troops",
+		"Clan Empires",
+		"Mine Fights",
+		"Clan Combat",
+		"Max Permanent Members",
+		"Days Of Protection"
+		};
+	_INT16 Month, Day, Year;
+
+	/* save screen */
+#ifdef __MSDOS__
+      char *acScreen;
+	acScreen = malloc(4000);
+  	memcpy(acScreen, Video.VideoMem, 4000);
+#else
+#if defined(_WIN32)
+                        SCREENSTATE screen_state;
+                        screen_state = save_screen ();
+#elif  defined(__unix__)
+						save_screen();
+#endif
+#endif
+
+	clrscr();
+
+	/* show help */
+	DosHelp(aszHelp[WhichOption], "reset.hlp");
+
+
+	switch ( WhichOption )
+	{
+		case 0 :	/* dategame started */
+			gotoxy(1,15);
+      Month = (_INT16)DosGetLong("|07Enter Month", atoi(ResetData.szDateGameStart), 12);
+      Day = (_INT16)DosGetLong("|07Enter Day", atoi(&ResetData.szDateGameStart[3]), 31);
+      Year = (_INT16)DosGetLong("|07Enter Year", atoi(&ResetData.szDateGameStart[6]), 2500);
+
+      sprintf(ResetData.szDateGameStart, "%02d/%02d/%4d", Month, Day, Year);
+			break;
+		case 1 :	/* last join date */
+			gotoxy(1,15);
+      Month = (_INT16)DosGetLong("|07Enter Month", atoi(ResetData.szLastJoinDate), 12);
+      Day = (_INT16)DosGetLong("|07Enter Day", atoi(&ResetData.szLastJoinDate[3]), 31);
+      Year = (_INT16)DosGetLong("|07Enter Year", atoi(&ResetData.szLastJoinDate[6]), 2500);
+
+      sprintf(ResetData.szLastJoinDate, "%02d/%02d/%4d", Month, Day, Year);
+			break;
+		case 2 :	/* village name */
+			gotoxy(1,15);
+			zputs("|07Please enter the village name|08> |15");
+      DosGetStr(ResetData.szVillageName, 29);
+			break;
+		case 3 :	/* elimination mode? */
+			gotoxy(1,15);
+			if (YesNo("|07Setup elimination mode?") == YES)
+			{
+				ResetData.EliminationMode = TRUE;
+			}
+			else
+				ResetData.EliminationMode = FALSE;
+			break;
+		case 4 :	/* clan travel? */
+			gotoxy(1,15);
+			if (YesNo("|07Allow clans to travel?") == YES)
+			{
+				ResetData.ClanTravel = TRUE;
+			}
+			else
+				ResetData.ClanTravel = FALSE;
+			break;
+		case 5 :	/* days before lost troops return */
+			gotoxy(1,15);
+			ResetData.LostDays = (_INT16)DosGetLong("|07Days before lost troops/clans returned?", ResetData.LostDays, 14);
+			break;
+		case 6 :	/* clan empires? */
+			gotoxy(1,15);
+			if (YesNo("|07Allow clans to create empires?") == YES)
+			{
+				ResetData.ClanEmpires = TRUE;
+			}
+			else
+				ResetData.ClanEmpires = FALSE;
+			break;
+		case 7 :	/* mine fights */
+			gotoxy(1,15);
+			ResetData.MineFights = (_INT16)DosGetLong("|07How many mine fights per day?", ResetData.MineFights, 50);
+			break;
+		case 8 :	/* clan combat */
+			gotoxy(1,15);
+			ResetData.ClanFights = (_INT16)DosGetLong("|07How many clan fights per day?", ResetData.ClanFights, MAX_CLANCOMBAT);
+			break;
+		case 9 :	/* max permanent clan members */
+			gotoxy(1,15);
+			ResetData.MaxPermanentMembers = (_INT16)DosGetLong("|07How many members?", ResetData.MaxPermanentMembers, 6);
+			if (ResetData.MaxPermanentMembers == 0)
+				ResetData.MaxPermanentMembers = 1;
+			break;
+		case 10:	/* days of protection */
+			gotoxy(1,15);
+			ResetData.DaysOfProtection = (_INT16)DosGetLong("|07How many days?", ResetData.DaysOfProtection, 16);
+			break;
+	}
+
+	/* restore screen */
+#ifdef __MSDOS__
+  memcpy(Video.VideoMem, acScreen, 4000);
+	free(acScreen);
+#else
+#if defined(_WIN32)
+		restore_screen(screen_state);
+#elif defined(__unix__)
+		restore_screen();
+#endif
+#endif
+#endif
+}
+
+void DosHelp ( char *Topic, char *File )
+{
+#ifdef USE_STDIO
+	char *Lines[22], string[155];
+	_INT16 cTemp, Found = FALSE, CurLine, NumLines;
+	FILE *fp;
+	BOOL EndOfTopic = FALSE;
+
+	printf("\n");
+	printf("%s\n",Topic);
+  	printf("----------------------------------------------------------------------------\n");
+
+	fp = fopen(File, "r");
+	if (!fp)
+	{
+		printf("Game help not found!\n");
+		return;
+	}
+
+	for (cTemp = 0; cTemp < 22; cTemp++)
+        Lines[cTemp] = malloc(255);
+
+	/* search for topic */
+	while (!Found)
+	{
+		if (fgets(string, 155, fp) == NULL)
+		{
+			fclose(fp);
+			printf("Game help not found!\n");
+			for (cTemp = 0; cTemp < 22; cTemp++)
+				free(Lines[cTemp]);
+			return;
+		}
+
+		if (string[0] == '^')
+		{
+			/* see if topic is correct */
+			if (strspn(&string[1], Topic) == strlen(Topic))
+			{
+				Found = TRUE;
+			}
+		}
+	}
+
+	while (EndOfTopic == FALSE)
+	{
+		/* read in up to 22 lines */
+		for (CurLine = 0; CurLine < 22; CurLine++)
+		{
+			fgets(Lines[CurLine], 355, fp);
+
+			if (Lines[CurLine][0] == '^')
+			{
+				if (strspn(&Lines[CurLine][1], "END") == 3)
+				{
+					EndOfTopic = TRUE;
+					break;
+				}
+			}
+		}
+		NumLines = CurLine;
+
+		/* display it */
+		for (CurLine = 0; CurLine < NumLines; CurLine++)
+		{
+			printf(Lines[CurLine]);
+		}
+	}
+
+	fclose(fp);
+	printf("----------------------------------------------------------------------------\n");
+
+	for (cTemp = 0; cTemp < 22; cTemp++)
+		free(Lines[cTemp]);
+#else
+	char *Lines[22], string[155];
+	_INT16 cTemp, Found = FALSE, CurLine, NumLines;
+	FILE *fp;
+	BOOL EndOfTopic = FALSE;
+
+	qputs("|15", 0, 0);
+	qputs(Topic, 1, 0);
+  qputs("|09- |01---------------------------------------------------------------------------",0,1);
+
+  qputs("|01--------------------------------------------------------------------------- |09-",0,12);
+
+	fp = fopen(File, "r");
+	if (!fp)
+	{
+		qputs("|12Game help not found!\n", 0, 2);
+		return;
+	}
+
+	for (cTemp = 0; cTemp < 22; cTemp++)
+        Lines[cTemp] = malloc(255);
+
+	/* search for topic */
+	while (!Found)
+	{
+		if (fgets(string, 155, fp) == NULL)
+		{
+			fclose(fp);
+			qputs("|12Game help not found!\n", 0, 2);
+			for (cTemp = 0; cTemp < 22; cTemp++)
+				free(Lines[cTemp]);
+			return;
+		}
+
+		if (string[0] == '^')
+		{
+			/* see if topic is correct */
+			if (strspn(&string[1], Topic) == strlen(Topic))
+			{
+				Found = TRUE;
+			}
+		}
+	}
+
+	while (EndOfTopic == FALSE)
+	{
+		/* read in up to 22 lines */
+		for (CurLine = 0; CurLine < 22; CurLine++)
+		{
+			fgets(Lines[CurLine], 355, fp);
+
+			if (Lines[CurLine][0] == '^')
+			{
+				if (strspn(&Lines[CurLine][1], "END") == 3)
+				{
+					EndOfTopic = TRUE;
+					break;
+				}
+			}
+		}
+		NumLines = CurLine;
+
+		/* display it */
+		for (CurLine = 0; CurLine < NumLines; CurLine++)
+		{
+			qputs(Lines[CurLine], 0, (_INT16)(CurLine+2));
+		}
+	}
+
+	fclose(fp);
+
+	for (cTemp = 0; cTemp < 22; cTemp++)
+		free(Lines[cTemp]);
+
+#endif
+}
+
+#ifndef USE_STDIO
+long DosGetLong( char *Prompt, long DefaultVal, long Maximum )
+{
+	char string[255], NumString[13], DefMax[40];
+	GETCH_TYPE InputChar;
+	_INT16 NumDigits, CurDigit = 0, cTemp;
+	long TenPower;
+
+	/* init screen */
+	zputs(" ");
+	zputs(Prompt);
+
+  sprintf(DefMax, " |01(|15%ld|07; %ld|01) |11", DefaultVal, Maximum);
+	zputs(DefMax);
+
+	/* NumDigits contains amount of digits allowed using max. value input */
+
+	TenPower = 10;
+	for (NumDigits = 1; NumDigits < 11; NumDigits++)
+	{
+		if (Maximum < TenPower )
+			break;
+
+		TenPower *= 10;
+	}
+
+	/* now get input */
+	for (;;)
+	{
+		InputChar = get_answer("0123456789><.,\r\n\b\x19");
+
+		if (isdigit(InputChar))
+		{
+			if (CurDigit < NumDigits)
+			{
+				NumString[CurDigit++] = InputChar;
+				NumString[CurDigit] = 0;
+				sprintf(string, "%c", InputChar);
+				zputs(string);
+			}
+
+		}
+		else if ( InputChar == '\b'
+#ifdef __unix__
+|| InputChar == KEY_BACKSPACE
+#endif		
+		)
+		{
+			if (CurDigit > 0)
+			{
+				CurDigit--;
+				NumString[CurDigit] = 0;
+				zputs("\b \b");
+			}
+		}
+		else if (InputChar == '>' || InputChar == '.')
+		{
+			/* get rid of old value, by showing backspaces */
+			for (cTemp = 0; cTemp < CurDigit; cTemp++)
+				zputs("\b \b");
+
+			sprintf(string, "%-ld", Maximum);
+			string[NumDigits] = 0;
+			zputs(string);
+
+			strcpy(NumString, string);
+			CurDigit = NumDigits;
+		}
+		else if (InputChar == '<' || InputChar == ',' || InputChar == 25)
+		{
+			/* get rid of old value, by showing backspaces */
+			for (cTemp = 0; cTemp < CurDigit; cTemp++)
+				zputs("\b \b");
+
+			CurDigit = 0;
+			string[CurDigit] = 0;
+
+			strcpy(NumString, string);
+		}
+		else if (InputChar == '\r' || InputChar == '\n')
+		{
+			if (CurDigit == 0)
+			{
+				sprintf(string, "%-ld", DefaultVal);
+				string[NumDigits] = 0;
+				zputs(string);
+
+				strcpy(NumString, string);
+				CurDigit = NumDigits;
+
+				zputs("\n");
+				break;
+			}
+			/* see if number too high, if so, make it max */
+			else if (atol(NumString) > Maximum)
+			{
+				/* get rid of old value, by showing backspaces */
+				for (cTemp = 0; cTemp < CurDigit; cTemp++)
+					zputs("\b \b");
+
+				sprintf(string, "%-ld", Maximum);
+				string[NumDigits] = 0;
+				zputs(string);
+
+				strcpy(NumString, string);
+				CurDigit = NumDigits;
+			}
+			else	/* is a valid value */
+			{
+				zputs("\n");
+				break;
+			}
+		}
+	}
+
+	return (atol(NumString));
+}
+
+
+void DosGetStr(char *InputStr, _INT16 MaxChars)
+{
+	_INT16 CurChar;
+	GETCH_TYPE InputCh;
+	char Spaces[85] = "                                                                                     ";
+	char BackSpaces[85] = "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";
+	char TempStr[100], szString[100];
+
+	Spaces[MaxChars] = 0;
+	BackSpaces[MaxChars] = 0;
+
+	CurChar = strlen(InputStr);
+
+	zputs(Spaces);
+	zputs(BackSpaces);
+	zputs(InputStr);
+
+	for (;;)
+	{
+		InputCh = getch();
+
+		if (InputCh == '\b'
+#ifdef __unix__
+|| InputCh == KEY_BACKSPACE
+#endif		
+		)
+		{
+			if (CurChar>0)
+			{
+				CurChar--;
+				zputs("\b \b");
+			}
+		}
+		else if (InputCh == '\r' || InputCh == '\n')
+		{
+			zputs("|16\n");
+			InputStr[CurChar]=0;
+			break;
+		}
+		else if (InputCh== '' || InputCh == '\x1B')  // ctrl-y
+		{
+			InputStr [0] = 0;
+			strcpy(TempStr, BackSpaces);
+			TempStr[ CurChar ] = 0;
+			zputs(TempStr);
+			Spaces[MaxChars] = 0;
+			BackSpaces[MaxChars] = 0;
+			zputs(Spaces);
+			zputs(BackSpaces);
+			CurChar = 0;
+		}
+		else if (InputCh >= '')
+			continue;
+		else if (InputCh == 0)
+			continue;
+		else if (iscntrl(InputCh))
+			continue;
+		else if (isalpha(InputCh) && CurChar && InputStr[CurChar-1] == SPECIAL_CODE)
+			continue;
+		else	/* valid character input */
+		{
+			if (CurChar==MaxChars)	 continue;
+			InputStr[CurChar++]=InputCh;
+			InputStr[CurChar] = 0;
+			sprintf(szString, "%c", InputCh);
+			zputs(szString);
+		}
+	}
+}
+
+void ColorArea( _INT16 xPos1, _INT16 yPos1, _INT16 xPos2, _INT16 yPos2, char Color )
+{
+	_INT16 x, y;
+#ifdef _WIN32
+      HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+      COORD cursor_pos;
+      DWORD cells_written;
+      WORD line_len;
+#elif defined(__unix__)
+	chtype this;
+	short attrs = 0;
+#endif
+
+	for (y = yPos1; y <= yPos2;  y++)
+	{
+		for (x = xPos1;  x <= xPos2;  x++)
+		{
+#ifdef __MSDOS__
+      Video.VideoMem[ Video.y_lookup[y] + (x<<1) +1 ] = Color;
+#elif defined(_WIN32)
+      line_len = (xPos2 - xPos1);
+
+	// Is it just me or is this a replace loop?
+      for (y = yPos1; y <= yPos2; y++)
+      {
+        cursor_pos.X = xPos1;
+        cursor_pos.Y = y;
+        FillConsoleOutputAttribute (
+          std_handle,
+          (WORD)Color,
+          line_len,
+          cursor_pos,
+          &cells_written);
+      }
+#elif defined(__unix__)
+	this=mvinch(y, x);
+	this &= 255;
+	if (Color & 8)
+		attrs |= A_BOLD;
+	if (Color & 128)
+		attrs |= A_BLINK;
+	this |= attrs|COLOR_PAIR(Color+1);
+	mvaddch(y, x, this);
+#endif
+		}
+	}
+#ifdef __unix__
+	refresh();
+#endif
+}
+
+#endif
+
+void Config_Init ( void )
+    /*
+     * Loads data from .CFG file into Config->
+     *
+     */
+{
+	FILE *fpConfigFile;
+	char szConfigName[40], szConfigLine[255];
+	char *pcCurrentPos;
+	char szToken[MAX_TOKEN_CHARS + 1];
+	_INT16 iKeyWord;
+//	_INT16 iCurrentNode = 1;
+
+	Config = malloc(sizeof(struct config));
+
+    // --- Set defaults
+    strcpy(szConfigName, "clans.cfg");
+    Config->szSysopName[0] = 0;
+    Config->szBBSName[0] = 0;
+    strcpy(Config->szScoreFile[0], "scores.asc");
+    strcpy(Config->szScoreFile[1], "scores.ans");
+    Config->szRegcode[0] = 0;
+
+    Config->InterBBS = FALSE;
+
+
+    fpConfigFile = _fsopen(szConfigName, "rt", SH_DENYWR);
+    if (!fpConfigFile)
+    {
+      /* file not found! error */
+      printf("Config file not found.  Please run CONFIG.EXE first before resetting.\n");
+#ifdef __unix__
+		curs_set(1);
+#endif	  
+      exit(0);
+    }
+
+    for (;;)
+    {
+      /* read in a line */
+      if (fgets(szConfigLine, 255, fpConfigFile) == NULL) break;
+
+      /* Ignore all of line after comments or CR/LF char */
+      pcCurrentPos=(char *)szConfigLine;
+      ParseLine(pcCurrentPos);
+
+      /* If no token was found, proceed to process the next line */
+      if(!*pcCurrentPos) continue;
+
+      GetToken(pcCurrentPos, szToken);
+
+      /* Loop through list of keywords */
+      for(iKeyWord = 0; iKeyWord < MAX_CONFIG_WORDS; ++iKeyWord)
+      {
+        /* If keyword matches */
+        if(stricmp(szToken, papszConfigKeyWords[iKeyWord]) == 0)
+        {
+          /* Process config token */
+          switch (iKeyWord)
+          {
+            case 0 :  /* sysopname */
+              strcpy(Config->szSysopName, pcCurrentPos);
+              break;
+            case 1 :  /* bbsname */
+              strcpy(Config->szBBSName, pcCurrentPos);
+              break;
+            case 10 : /* BBS Id */
+              Config->BBSID = atoi(pcCurrentPos);
+              break;
+            case 11 : /* netmail dir */
+              strcpy(Config->szNetmailDir, pcCurrentPos);
+
+              /* remove '\' if last char is it */
+              if (Config->szNetmailDir [ strlen(Config->szNetmailDir) - 1] == '\\' || Config->szNetmailDir [strlen(Config->szNetmailDir) - 1] == '/')
+                Config->szNetmailDir [ strlen(Config->szNetmailDir) - 1] = 0;
+              break;
+            case 12 : /* inbound dir */
+              strcpy(Config->szInboundDir, pcCurrentPos);
+
+              /* add '\' if last char is not it */
+              if ( Config->szInboundDir [ strlen(Config->szInboundDir) - 1] != '\\' &&  Config->szInboundDir [strlen(Config->szInboundDir) - 1] != '/')
+                strcat(Config->szInboundDir, "/");
+              break;
+            case 13 : /* mailer type */
+              if (stricmp(pcCurrentPos, "BINKLEY") == 0)
+                Config->MailerType = MAIL_BINKLEY;
+              else
+                Config->MailerType = MAIL_OTHER;
+              break;
+            case 14 : /* in a league? */
+              Config->InterBBS = TRUE;
+              break;
+          }
+        }
+      }
+    }
+
+    fclose(fpConfigFile);
+
+  }
+
+  void Config_Close ( void )
+    /*
+     * Shuts down config's mem.
+     *
+     */
+  {
+    free(Config);
+  }
+
+
+  void GoReset ( struct ResetData *ResetData, _INT16 Option )
+  {
+    FILE *fp;
+    struct game_data Game_Data;
+#ifndef _WIN32
+    struct tm t;
+#else
+    SYSTEMTIME system_time;
+#endif
+    char szString[128];
+
+    // Delete unwanted files here
+    unlink("clans.msj");
+    unlink("clans.pc");
+    unlink("disband.dat");
+    unlink("trades.dat");
+    unlink("public.txt");
+    unlink("pawn.dat");
+    unlink("clans.npx");
+
+    KillAlliances();
+
+    unlink("ally.dat");
+
+		// delete IBBS files
+		unlink("ibbs.dat");
+		unlink("ipscores.dat");
+		unlink("userlist.dat");
+    unlink("backup.dat");
+		unlink("leaving.dat");
+
+    if (Option == RESET_LOCAL)
+    {
+      /*
+       * reset local game, no IBBS
+       */
+
+      // create new game.dat file
+      Game_Data.GameState = 1;
+      Game_Data.InterBBS = FALSE;
+
+      strcpy(Game_Data.szTodaysDate, szTodaysDate);
+      strcpy(Game_Data.szDateGameStart, ResetData->szDateGameStart);
+      strcpy(Game_Data.szLastJoinDate, ResetData->szLastJoinDate);
+
+      Game_Data.NextClanID = 0;
+      Game_Data.NextAllianceID = 0;
+
+      Game_Data.MaxPermanentMembers = ResetData->MaxPermanentMembers;
+      Game_Data.ClanEmpires = ResetData->ClanEmpires;
+      Game_Data.MineFights = ResetData->MineFights;
+      Game_Data.ClanFights = ResetData->ClanFights;
+      Game_Data.DaysOfProtection = ResetData->DaysOfProtection;
+
+
+      Game_Data.CRC = CRCValue(&Game_Data, sizeof(struct game_data) - sizeof(long));
+
+      fp = fopen("game.dat", "wb");
+      // fwrite(&Game_Data, sizeof(struct game_data), 1, fp);
+      EncryptWrite(&Game_Data, sizeof(struct game_data), fp, XOR_GAME);
+      fclose(fp);
+
+      // update news
+      unlink("yest.asc");
+      rename("today.asc", "yest.asc");
+      News_CreateTodayNews();
+      News_AddNews("|0A � |0CThe game has been reset!\n\n");
+    }
+    else if (Option == RESET_JOINIBBS)
+    {
+      // create new game.dat file
+      Game_Data.GameState = 2;
+      Game_Data.InterBBS = TRUE;
+
+      /* find out date and time for GameId */
+      // initialize date
+#ifndef _WIN32
+      gettime(&t);
+      sprintf(szString, "%02d:%02d:%02d.%02d", t.tm_hour, t.tm_min, t.tm_sec, 0);
+#else
+      GetSystemTime(&system_time);
+      sprintf(szString, "%02d:%02d:%02d.%02d", system_time.wHour,
+              system_time.wMinute, system_time.wSecond, 0);
+#endif
+      strcpy(Game_Data.GameID, szString);
+
+      strcpy(Game_Data.szTodaysDate, szTodaysDate);
+      strcpy(Game_Data.szDateGameStart, ResetData->szDateGameStart);
+      strcpy(Game_Data.szLastJoinDate, ResetData->szLastJoinDate);
+
+      Game_Data.NextClanID = 0;
+      Game_Data.NextAllianceID = 0;
+
+      Game_Data.MaxPermanentMembers = ResetData->MaxPermanentMembers;
+      Game_Data.ClanEmpires = ResetData->ClanEmpires;
+      Game_Data.MineFights = ResetData->MineFights;
+      Game_Data.ClanFights = ResetData->ClanFights;
+      Game_Data.DaysOfProtection = ResetData->DaysOfProtection;
+
+
+      Game_Data.CRC = CRCValue(&Game_Data, sizeof(struct game_data) - sizeof(long));
+
+      fp = fopen("game.dat", "wb");
+      EncryptWrite(&Game_Data, sizeof(struct game_data), fp, XOR_GAME);
+      fclose(fp);
+
+      // update news
+      unlink("yest.asc");
+      rename("today.asc", "yest.asc");
+      News_CreateTodayNews();
+      News_AddNews("|0A � |0CThe game is waiting for LC OK.\n\n");
+
+    }
+    else if (Option == RESET_LC)
+    {
+      // leaguewide reset
+
+      // REP: make sure only LC can do this somehow...
+
+      // create game.dat file
+      Game_Data.GameState = 1;
+      Game_Data.InterBBS = TRUE;
+
+      /* find out date and time for GameId */
+#ifndef _WIN32
+      gettime(&t);
+      sprintf(szString, "%02d:%02d:%02d.%02d", t.tm_hour, t.tm_min, t.tm_sec, 0);
+#else
+      GetSystemTime(&system_time);
+      sprintf(szString, "%02d:%02d:%02d.%02d", system_time.wHour, 
+              system_time.wMinute, system_time.wSecond, 0);
+#endif
+      strcpy(Game_Data.GameID, szString);
+
+      strcpy(Game_Data.szTodaysDate, szTodaysDate);
+      strcpy(Game_Data.szDateGameStart, ResetData->szDateGameStart);
+      strcpy(Game_Data.szLastJoinDate, ResetData->szLastJoinDate);
+
+      Game_Data.NextClanID = 0;
+      Game_Data.NextAllianceID = 0;
+
+      Game_Data.MaxPermanentMembers = ResetData->MaxPermanentMembers;
+      Game_Data.ClanEmpires = ResetData->ClanEmpires;
+      Game_Data.MineFights = ResetData->MineFights;
+      Game_Data.ClanFights = ResetData->ClanFights;
+      Game_Data.DaysOfProtection = ResetData->DaysOfProtection;
+
+
+      Game_Data.CRC = CRCValue(&Game_Data, sizeof(struct game_data) - sizeof(long));
+
+      fp = fopen("game.dat", "wb");
+      EncryptWrite(&Game_Data, sizeof(struct game_data), fp, XOR_GAME);
+      fclose(fp);
+
+      // update news
+      unlink("yest.asc");
+      rename("today.asc", "yest.asc");
+      News_CreateTodayNews();
+      News_AddNews("|0A � |0CThe game has been reset!\n\n");
+    }
+
+    // create new village data
+    CreateVillageDat(ResetData);
+  }
+
+
+  void News_CreateTodayNews  ( void )
+  {
+    /* this initializes the TODAY.ASC file */
+
+    char szString[128];
+
+    sprintf(szString, "|0CNews for |0B%s\n\n", szTodaysDate);
+    News_AddNews(szString);
+
+    /* give other info like increase in cost of etc. */
+  }
+
+  void News_AddNews(char *szString)
+  {
+    FILE *fpNewsFile;
+
+    /* open news file */
+
+    /* add to it */
+
+    fpNewsFile = _fsopen("today.asc", "at", SH_DENYWR);
+
+    fputs(szString, fpNewsFile);
+
+    fclose(fpNewsFile);
+  }
+
+  void ClearFlags ( char *Flags )
+  {
+    _INT16 iTemp;
+
+    for (iTemp = 0; iTemp < 8; iTemp++)
+      Flags[iTemp] = 0;
+  }
+
+  void InitEmpire ( struct empire *Empire, _INT16 UserEmpire )
+  {
+    _INT16 iTemp;
+
+    if (UserEmpire)
+      Empire->Land = 100;
+    else
+      Empire->Land = 0;
+
+    Empire->Points = 0;
+
+    for (iTemp = 0; iTemp < MAX_BUILDINGS; iTemp++)
+      Empire->Buildings[iTemp] = 0;
+
+    Empire->WorkerEnergy = 100;
+
+    // deal with army
+    Empire->Army.Followers = 0;
+    Empire->Army.Footmen = 0;
+    Empire->Army.Axemen = 0;
+    Empire->Army.Knights = 0;
+    Empire->Army.Rating = 100;
+    Empire->Army.Level = 0;
+    Empire->SpiesToday = 0;
+    Empire->AttacksToday = 0;
+    Empire->LandDevelopedToday = 0;
+    Empire->Army.Strategy.AttackLength = 10;
+    Empire->Army.Strategy.DefendLength = 10;
+    Empire->Army.Strategy.LootLevel    = 0;
+    Empire->Army.Strategy.AttackIntensity = 50;
+    Empire->Army.Strategy.DefendIntensity = 50;
+  }
+
+
+
+  void CreateVillageDat ( struct ResetData *ResetData )
+  {
+    FILE *fp;
+    struct village_data Village_Data = {
+      { 1, 9, 3, 1, 11, 7, 3, 2, 10, 2, 5, 3, 9, 5, 13, 1, 9, 15, 7, 0, 0, 8, 4,
+        1, 8, 1 },
+      { -1 }
+      };
+
+    Village_Data.PublicMsgIndex = 1;
+    strcpy(Village_Data.szName, ResetData->szVillageName);
+
+    Village_Data.TownType = -1;      /* unknown for now */
+    Village_Data.TaxRate = 0;      /* no taxes */
+    Village_Data.InterestRate = 0;   /* 0% interest rate */
+    Village_Data.GST = 0;        /* no gst */
+    Village_Data.Empire.VaultGold = 45000L; /* some money to begin with */
+    Village_Data.ConscriptionRate = 10;
+
+    Village_Data.RulingClanId[0] = -1; /* no ruling clan yet */
+    Village_Data.RulingClanId[1] = -1;
+
+    Village_Data.szRulingClan[0] = 0;
+    Village_Data.RulingDays = 0;
+    Village_Data.GovtSystem = GS_DEMOCRACY;
+
+
+    Village_Data.MarketLevel = 0;      /* weaponshop level */
+    Village_Data.TrainingHallLevel = 0;
+    Village_Data.ChurchLevel = 0;
+    Village_Data.PawnLevel = 0;
+    Village_Data.WizardLevel = 0;
+
+    Village_Data.SetTaxToday = FALSE;
+    Village_Data.SetInterestToday = FALSE;
+    Village_Data.SetGSTToday = FALSE;
+    Village_Data.SetConToday = FALSE;
+
+    Village_Data.UpMarketToday = FALSE;
+    Village_Data.UpTHallToday = FALSE;
+    Village_Data.UpChurchToday = FALSE;
+    Village_Data.UpPawnToday = FALSE;
+    Village_Data.UpWizToday = FALSE;
+    Village_Data.ShowEmpireStats = FALSE;
+
+    ClearFlags(Village_Data.HFlags);
+    ClearFlags(Village_Data.GFlags);
+
+    InitEmpire(&Village_Data.Empire, FALSE);
+    strcpy(Village_Data.Empire.szName, Village_Data.szName);
+    Village_Data.Empire.Land = 500;      // village starts off with this
+    Village_Data.Empire.Buildings[B_BARRACKS] = 10;
+    Village_Data.Empire.Buildings[B_WALL] = 10;
+    Village_Data.Empire.Buildings[B_TOWER] = 5;
+    Village_Data.Empire.Buildings[B_STEELMILL] = 5;
+    Village_Data.Empire.Buildings[B_BUSINESS] = 10;
+    Village_Data.Empire.Army.Footmen = 100;
+    Village_Data.Empire.Army.Axemen = 25;
+
+    Village_Data.CostFluctuation = 5 - RANDOM(11);
+    Village_Data.MarketQuality = MQ_AVERAGE;
+
+    Village_Data.CRC = CRCValue(&Village_Data, sizeof(struct village_data) - sizeof(long));
+
+    fp = fopen("village.dat", "wb");
+    // fwrite(&Village_Data, sizeof(struct village_data), 1, fp);
+    EncryptWrite(&Village_Data, sizeof(struct village_data), fp, XOR_VILLAGE);
+    fclose(fp);
+  }
+
+
+
+  void GetAlliances( struct Alliance *Alliances[MAX_ALLIANCES])
+  {
+    FILE *fp;
+    _INT16 iTemp;
+
+    // init alliances as NULLs
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      Alliances[iTemp] = NULL;
+
+    fp = fopen("ally.dat", "rb");
+    if (fp)
+    {
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        Alliances[iTemp] = malloc(sizeof(struct Alliance));
+        CheckMem(Alliances[iTemp]);
+
+        if (EncryptRead(Alliances[iTemp], sizeof(struct Alliance), fp, XOR_ALLIES) == 0)
+        {
+          // no more alliances to read in
+          free(Alliances[iTemp]);
+          Alliances[iTemp] = NULL;
+          break;
+        }
+      }
+      fclose(fp);
+    }
+  }
+
+
+  void UpdateAlliances( struct Alliance *Alliances[MAX_ALLIANCES])
+  {
+    FILE *fp;
+    _INT16 iTemp;
+
+    fp = fopen("ally.dat", "wb");
+    if (fp)
+    {
+      for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+      {
+        if (Alliances[iTemp] == NULL)
+          continue;
+
+        EncryptWrite(Alliances[iTemp], sizeof(struct Alliance), fp, XOR_ALLIES);
+      }
+      fclose(fp);
+    }
+  }
+
+
+void KillAlliances( void )
+{
+	struct Alliance *Alliances[MAX_ALLIANCES];
+	char szFileName[13];
+	_INT16 iTemp;
+
+  GetAlliances(Alliances);
+
+	// delete files
+	// free up mem used by alliances
+	for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		if (Alliances[iTemp])
+		{
+			sprintf(szFileName, "hall%02d.txt", Alliances[iTemp]->ID);
+			unlink(szFileName);
+
+			free(Alliances[iTemp]);
+            Alliances[iTemp] = NULL;
+		}
+
+	// free up mem used by alliances
+    for (iTemp = 0; iTemp < MAX_ALLIANCES; iTemp++)
+		if (Alliances[iTemp])
+			free(Alliances[iTemp]);
+
+	// called to destroy ALLY.DAT and remove those pesky HALLxxyy.TXT files
+	unlink("ally.dat");
+}
+
+  char *MakeStr ( _INT16 length )
+    /*
+     * This returns a pointer to a malloc'd string of length length.
+     */
+  {
+    char *pc;
+
+    pc = malloc(sizeof(char)*length);
+    CheckMem(pc);
+
+    return pc;
+  }
+
+  void System_Error ( char *szErrorMsg )
+    /*
+     * purpose  To output an error message and close down the system.
+     *          This SHOULD be run from anywhere and NOT fail.  It should
+     *          be FOOLPROOF.
+     */
+  {
+#ifdef USE_STDIO
+	printf("Error: %s", szErrorMsg);
+    delay(1000);
+    exit(0);
+#else
+    qputs("|12Error: |07", 0,0);
+    qputs(szErrorMsg, 0, 7);
+    delay(1000);
+#ifdef __unix__
+		curs_set(1);
+#endif	  
+    exit(0);
+#endif
+  }
+
+#ifndef USE_STDIO
+void UpdateOption (char Option)
+{
+	char szString[50];
+	switch (Option)
+	{
+	case 0:
+	      xputs(ResetData.szDateGameStart, 40, 2);
+		break;
+	case 1:
+	      xputs(ResetData.szLastJoinDate, 40, 3);
+		break;
+	case 2:
+		xputs("                                        ", 40, 4);
+		xputs(ResetData.szVillageName, 40, 4);
+		break;
+	case 3:
+		if (ResetData.EliminationMode)
+			xputs("Yes", 40, 5);
+		else
+			xputs("No ", 40, 5);
+		break;
+	case 4:
+		if (ResetData.ClanTravel)
+			xputs("Yes", 40, 6);
+		else
+			xputs("No ", 40, 6);
+		break;
+	case 5:
+		sprintf(szString, "%-2d ", ResetData.LostDays);
+		xputs(szString, 40, 7);
+		break;
+	case 6:
+		if (ResetData.ClanEmpires)
+			xputs("Yes", 40, 8);
+		else
+			xputs("No ", 40, 8);
+		break;
+	case 7:
+		sprintf(szString, "%-2d ", ResetData.MineFights);
+		xputs(szString, 40, 9);
+		break;
+	case 8:
+		sprintf(szString, "%-2d ", ResetData.ClanFights);
+		xputs(szString, 40, 10);
+		break;
+	case 9:
+		sprintf(szString, "%-2d ", ResetData.MaxPermanentMembers);
+		xputs(szString, 40, 11);
+		break;
+	case 10:
+		sprintf(szString, "%-2d ", ResetData.DaysOfProtection);
+		xputs(szString, 40, 12);
+		break;
+	}
+}
+#endif
+
+#ifdef _WIN32
+void gotoxy(int x, int y)
+{
+  HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+  COORD cursor_pos;
+
+  cursor_pos.X = x;
+  cursor_pos.Y = y;
+
+  SetConsoleCursorPosition (std_handle, cursor_pos);
+}
+
+void clrscr (void)
+{
+  HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+  CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+  COORD top_left = { 0, 0 };
+  DWORD cells_written;
+
+  GetConsoleScreenBufferInfo (std_handle, &screen_buffer);
+
+  FillConsoleOutputCharacter (
+    std_handle,
+    (TCHAR)' ',
+    screen_buffer.dwSize.X * screen_buffer.dwSize.Y,
+    top_left,
+    &cells_written);
+
+  FillConsoleOutputAttribute (
+    std_handle,
+    (WORD)7,
+    screen_buffer.dwSize.X * screen_buffer.dwSize.Y,
+    top_left,
+    &cells_written);
+
+  SetConsoleCursorPosition (
+    std_handle,
+    top_left);
+}
+
+void settextattr(WORD attribute)
+{
+  SetConsoleTextAttribute (
+    GetStdHandle (STD_OUTPUT_HANDLE),
+    attribute);
+}
+
+void * save_screen(void)
+{
+  CHAR_INFO *char_info_buffer;
+  DWORD buffer_len;
+  CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+  HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+  COORD top_left = { 0, 0 };
+  SMALL_RECT rect_rw;
+
+  GetConsoleScreenBufferInfo (std_handle, &screen_buffer);
+  
+  buffer_len = (screen_buffer.dwSize.X * screen_buffer.dwSize.Y);
+  char_info_buffer = (CHAR_INFO *) malloc (buffer_len * sizeof(CHAR_INFO));
+  if (!char_info_buffer)
+  {
+    MessageBox (NULL, TEXT("Memory Allocation Failure"),
+                TEXT("ERROR"), MB_OK | MB_ICONERROR);
+#ifdef __unix__
+		curs_set(1);
+#endif	  
+    exit (0);
+  }
+
+  rect_rw.Top = 0;
+  rect_rw.Left = 0;
+  rect_rw.Right = screen_buffer.dwSize.X;
+  rect_rw.Bottom = screen_buffer.dwSize.Y;
+
+  ReadConsoleOutput (
+    std_handle,
+    char_info_buffer,
+    screen_buffer.dwSize,
+    top_left,
+    &rect_rw);
+
+  return (void *)char_info_buffer;
+}
+
+void restore_screen(void *state)
+{
+  CHAR_INFO *char_info_buffer = (CHAR_INFO *)state;
+  COORD top_left = { 0, 0 };
+  CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+  SMALL_RECT rect_write;
+  HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+
+  if (!char_info_buffer)
+    return;
+
+  GetConsoleScreenBufferInfo (std_handle, &screen_buffer);
+
+  rect_write.Top = 0;
+  rect_write.Left = 0;
+  rect_write.Bottom = screen_buffer.dwSize.Y;
+  rect_write.Right = screen_buffer.dwSize.X;
+
+  WriteConsoleOutput (
+    std_handle,
+    char_info_buffer,
+    screen_buffer.dwSize,
+    top_left,
+    &rect_write);
+
+  free (char_info_buffer);
+}
+#elif defined(__unix__)
+void gotoxy(int x, int y)
+{
+	move(y, x);
+}
+
+void clrscr (void)
+{
+	clear();
+	refresh();
+}
+
+void settextattr(WORD attribute)
+{
+	set_attrs(attribute);
+}
+
+void save_screen(void)
+{
+	savedwin=dupwin(stdscr);
+}
+
+void restore_screen(void)
+{
+	overwrite(savedwin,stdscr);
+	refresh();
+}
+#endif
diff --git a/src/doors/clans-src/reset.dsp b/src/doors/clans-src/reset.dsp
new file mode 100644
index 0000000000000000000000000000000000000000..ecf02de794ce8f065d9ea54c562d151d1fc8b451
--- /dev/null
+++ b/src/doors/clans-src/reset.dsp
@@ -0,0 +1,128 @@
+# Microsoft Developer Studio Project File - Name="reset" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=reset - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE 
+!MESSAGE NMAKE /f "reset.mak".
+!MESSAGE 
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "reset.mak" CFG="reset - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "reset - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "reset - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "reset - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "reset___Win32_Release"
+# PROP BASE Intermediate_Dir "reset___Win32_Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Win32_Release"
+# PROP Intermediate_Dir "Win32_Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Zp1 /MD /W3 /GX- /Ox /Ot /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+
+!ELSEIF  "$(CFG)" == "reset - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "reset___Win32_Debug"
+# PROP BASE Intermediate_Dir "reset___Win32_Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Win32_Debug"
+# PROP Intermediate_Dir "Win32_Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Zp1 /MDd /W3 /Gm /GX- /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# SUBTRACT CPP /Fr
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /map /debug /debugtype:both /machine:I386
+
+!ENDIF 
+
+# Begin Target
+
+# Name "reset - Win32 Release"
+# Name "reset - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\CRC.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\MYOPEN.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\PARSING.C
+# End Source File
+# Begin Source File
+
+SOURCE=.\RESET.C
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\CRC.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\MYOPEN.H
+# End Source File
+# Begin Source File
+
+SOURCE=.\PARSING.H
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/src/doors/clans-src/scores.c b/src/doors/clans-src/scores.c
new file mode 100644
index 0000000000000000000000000000000000000000..76781379cc8f040e248cba838d1cda2dbd642085
--- /dev/null
+++ b/src/doors/clans-src/scores.c
@@ -0,0 +1,1027 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+#include <ctype.h>
+
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "door.h"
+#include "myopen.h"
+#include "parsing.h"
+#include "user.h"
+#include "packet.h"
+#include "ibbs.h"
+
+
+extern struct Language *Language;
+extern struct clan *PClan;
+extern struct config *Config;
+extern struct system System;
+extern struct village Village;
+extern struct ibbs IBBS;
+extern struct game Game;
+
+  void GetColourString( char *szColourString, _INT16 Colour, BOOL Clear )
+  {
+    _INT16 TempColour;
+    char *szFgColours[8] = {
+        "30m",
+        "34m",
+        "32m",
+        "36m",
+        "31m",
+        "35m",
+        "33m",
+        "37m"
+    },
+    *szBgColours[8] = {
+        "40m",
+        "44m",
+        "42m",
+        "46m",
+        "41m",
+        "45m",
+        "43m",
+        "47m"
+    };
+
+    strcpy(szColourString, "\x1B[");
+
+    if (Clear)
+      strcat(szColourString, "0;");
+
+    if (Colour >= 24)
+    {
+      // background flashing
+
+      TempColour = Colour - 24;
+
+      if (TempColour >= 8)
+        TempColour = 0;
+
+      strcat(szColourString, "5;");
+      strcat(szColourString, szBgColours[ TempColour ]);
+    }
+    else if (Colour >= 16)
+    {
+      // background
+
+      TempColour = Colour - 16;
+
+      strcat(szColourString, szBgColours[ TempColour ]);
+    }
+    else if (Colour >= 8)
+    {
+      // foreground bright
+      TempColour = Colour - 8;
+
+      strcat(szColourString, "1;");
+      strcat(szColourString, szFgColours[ TempColour ]);
+    }
+    else
+    {
+      // regular colour
+      TempColour = Colour;
+
+      strcat(szColourString, szFgColours[ TempColour ]);
+    }
+  }
+
+  void PipeToAnsi ( char *szOut, char *szIn )
+  {
+    char *pcOut, *pcIn;
+    char Colour, Bg, Fg, szDigits[3],
+        szColourString[20];
+
+    pcOut = szOut;
+    pcIn  = szIn;
+
+    *pcOut = 0;
+
+    while (*pcIn)
+    {
+      if ( (*pcIn) == '`' && iscodechar( *(pcIn + 1) )
+          && iscodechar( *(pcIn +2)) )
+      {
+        pcIn++;
+
+        // get background
+        if (isdigit(*pcIn))
+          Bg = *pcIn - '0';
+        else
+          Bg = *pcIn - 'A' + 10;
+
+        // must add this to use GetColourString properly
+        Bg += 16;
+        GetColourString(szColourString, Bg, TRUE);
+        strcat(pcOut, szColourString);
+        pcOut = strchr(szOut, 0);
+
+        pcIn++;
+
+        // get foreground
+        if (isdigit(*pcIn))
+          Fg = *pcIn - '0';
+        else
+          Fg = *pcIn - 'A' + 10;
+        GetColourString(szColourString, Fg, FALSE);
+        strcat(pcOut, szColourString);
+        pcOut = strchr(szOut, 0);
+
+        pcIn++;
+      }
+      else if (*pcIn == '|' && isdigit(*(pcIn+1)) && isdigit(*(pcIn+2)))
+      {
+        szDigits[0] = *(pcIn+1);
+        szDigits[1] = *(pcIn+2);
+        szDigits[2] = 0;
+
+        Colour = atoi(szDigits);
+
+        GetColourString(szColourString, Colour, TRUE);
+
+        strcat(pcOut, szColourString);
+
+        pcOut = strchr(szOut, 0);
+
+        pcIn += 3;
+      }
+      else
+      {
+        *pcOut = *pcIn;
+
+        pcIn++;
+        pcOut++;
+
+        *pcOut = 0;
+      }
+    }
+  }
+
+
+
+
+  void DisplayScores ( BOOL MakeFile )
+  {
+    FILE *fpPCFile, *fpScoreFile[2];
+    char szFileName[50], szString[255], szPadding[21];
+    struct clan *TmpClan;
+      struct SortData {
+      char szName[25];
+      long Points;
+      BOOL IsRuler;
+      char Symbol[21], PlainSymbol[21];
+      _INT16 WorldStatus;
+      BOOL UsedInList;
+      BOOL Eliminated;
+      _INT16 VillageID;
+      BOOL Living;
+    } *SortData[128];
+    char AnsiSymbol[190];
+    _INT16 SortList[128];
+    _INT16 CurClan = 0, iTemp, NumClans, CurMember;
+    long MostPoints, Offset;
+    _INT16 CurHigh, Padding;
+    BOOL NoPlayers = TRUE;
+
+    /* initialize sortdata */
+    for (iTemp = 0; iTemp < 128; iTemp++)
+      SortData[iTemp] = NULL;
+
+    /* read in all clans from data file  and place them in sortdata
+       structure */
+
+    /* sort them into SortList */
+    /* SortList[0] points to top clan
+       SortList[1] points to 2nd top clan
+       etc.
+     */
+    strcpy(szFileName, ST_CLANSPCFILE);
+
+    if (MakeFile)
+    {
+      fpScoreFile[0] = fopen(Config->szScoreFile[0], "w");
+      if (!fpScoreFile[0])
+        return;
+
+      fpScoreFile[1] = fopen(Config->szScoreFile[1], "w");
+      if (!fpScoreFile[1])
+      {
+        fclose(fpScoreFile[0]);
+        return;
+      }
+
+      // write headers
+      fputs(ST_SCORE0ASCII, fpScoreFile[0]);
+      fputs(ST_SCORE0ANSI, fpScoreFile[1]);
+    }
+
+    fpPCFile = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYWR);
+    if (!fpPCFile)
+    {
+      NoPlayers = TRUE;
+    }
+    else
+    {
+      TmpClan = malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+      /* read 'em in */
+      for (CurClan = 0;; CurClan++)
+      {
+        Offset = CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc));
+        if (fseek(fpPCFile, Offset, SEEK_SET))
+        {
+          break;  /* couldn't fseek, so exit */
+        }
+
+        if (EncryptRead(TmpClan, sizeof(struct clan), fpPCFile, XOR_USER) == 0)
+        {
+          break;  /* stop reading if no more players found */
+        }
+
+        for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+          TmpClan->Member[CurMember] = NULL;
+
+        for (CurMember = 0; CurMember < 6; CurMember++)
+        {
+          TmpClan->Member[CurMember] = malloc(sizeof(struct pc));
+          CheckMem(TmpClan->Member[CurMember]);
+          EncryptRead(TmpClan->Member[CurMember], sizeof(struct pc), fpPCFile, XOR_PC);
+        }
+
+        // since we could read in a player, means at least one exists
+        NoPlayers = FALSE;
+
+        /* allocate mem for this clan in the list */
+        SortData[CurClan] = malloc(sizeof(struct SortData));
+        CheckMem(SortData[CurClan]);
+
+        /* this sets it so it hasn't been used yet in the sort list */
+        SortData[CurClan]->UsedInList = FALSE;
+
+        strcpy(SortData[CurClan]->szName, TmpClan->szName);
+        SortData[CurClan]->Points = TmpClan->Points;
+        SortData[CurClan]->VillageID = TmpClan->ClanID[0];
+
+
+        SortData[CurClan]->IsRuler = FALSE;
+
+        if (TmpClan->ClanID[0] == Village.Data->RulingClanId[0] &&
+          TmpClan->ClanID[1] == Village.Data->RulingClanId[1])
+          SortData[CurClan]->IsRuler = TRUE;
+        else
+          SortData[CurClan]->IsRuler = FALSE;
+
+        if (TmpClan->Eliminated)
+          SortData[CurClan]->Eliminated = TRUE;
+        else
+          SortData[CurClan]->Eliminated = FALSE;
+
+        strcpy(SortData[CurClan]->Symbol, TmpClan->Symbol);
+        RemovePipes(TmpClan->Symbol, SortData[CurClan]->PlainSymbol);
+
+        SortData[CurClan]->WorldStatus = TmpClan->WorldStatus;
+
+        if (NumMembers(TmpClan, TRUE) == 0)
+          SortData[CurClan]->Living = FALSE;
+        else
+          SortData[CurClan]->Living = TRUE;
+
+        for (CurMember = 0; CurMember < 6; CurMember++)
+        {
+          free(TmpClan->Member[CurMember]);
+          TmpClan->Member[CurMember] = NULL;
+        }
+      }
+
+      free(TmpClan);
+      TmpClan = NULL;
+      NumClans = CurClan;
+      fclose(fpPCFile);
+    }
+
+    if (NoPlayers)
+    {
+      if (MakeFile == FALSE)
+        rputs(" |07No one has played the game.\n");
+      else
+      {
+        fputs(ST_SCORE1ASCII, fpScoreFile[0]);
+        fputs(ST_SCORE1ANSI, fpScoreFile[1]);
+        fclose(fpScoreFile[0]);
+        fclose(fpScoreFile[1]);
+      }
+      return;
+    }
+    /* sort them into SortList */
+    /* SortList[0] points to top clan
+       SortList[1] points to 2nd top clan
+       etc.
+     */
+
+
+    for (iTemp = 0; iTemp < NumClans; iTemp++)
+    {
+      MostPoints = -32000;
+      CurHigh = 0;
+
+      /* go through them finding highest one */
+      for (CurClan = 0; CurClan < NumClans; CurClan++)
+      {
+        /* skip if used already */
+        if (SortData[CurClan]->UsedInList)
+          continue;
+
+        /* is this highest? */
+        if (SortData[CurClan]->Points > MostPoints)
+        {
+          /* yes, set stuff up */
+          CurHigh = CurClan;
+          MostPoints = SortData[CurClan]->Points;
+        }
+      }
+
+      /* found highest out of list */
+      SortData[CurHigh]->UsedInList = TRUE;
+      SortList[iTemp] = CurHigh;
+    }
+
+    /* show them */
+    if (MakeFile == FALSE)
+    {
+      rputs(ST_SCOREHEADER);
+      rputs(ST_SCORELINE);
+    }
+
+    /* go through list */
+    for (CurClan = 0; CurClan < NumClans; CurClan++)
+    {
+      if (MakeFile == FALSE)
+      {
+        // sprintf(szString, " |%02d%3s |02%-30s |15%6ld  ", SortData[ SortList[CurClan] ]->Color, SortData[ SortList[CurClan] ]->Symbol, SortData[ SortList[CurClan] ]->szName, SortData[ SortList[CurClan] ]->Points);
+        // figure out clanid length without pipes
+        RemovePipes(SortData[ SortList[CurClan] ]->Symbol, szString);
+        Padding = 20 - strlen(szString);
+        szPadding[0] = 0;
+        for (iTemp = 0; iTemp < Padding; iTemp++)
+          strcat(szPadding, " ");
+
+        sprintf(szString, " |0C%-30s %s%s`07  |15%-6ld  ",
+          SortData[ SortList[CurClan] ]->szName,
+          szPadding, SortData[ SortList[CurClan] ]->Symbol,
+          SortData[ SortList[CurClan] ]->Points);
+
+        if (SortData[ SortList[CurClan] ]->Eliminated)
+          strcat(szString, "|04Eliminated");
+        else if (SortData[ SortList[CurClan] ]->WorldStatus == WS_GONE)
+          strcat(szString, "|0BAway");
+        else
+        {
+          if (SortData[ SortList[CurClan] ]->Living == FALSE)
+            strcat(szString, "|04Dead");
+          else if (SortData[ SortList[CurClan] ]->VillageID != Config->BBSID
+            && Game.Data->InterBBS)
+            strcat(szString, "|0BVisiting");
+          else
+            strcat(szString, "|0BHere");
+        }
+
+        if (SortData[ SortList[CurClan] ]->IsRuler)
+          strcat(szString, "  |0A(Ruler)\n");
+        else
+          strcat(szString, "\n");
+
+        if (CurClan%20 == 0 && CurClan)
+          door_pause();
+
+        rputs(szString);
+      }
+      else
+      {
+        strcpy(szString, SortData[ SortList[CurClan] ]->Symbol);
+        RemovePipes(SortData[ SortList[CurClan] ]->Symbol, szString);
+        Padding = 20 - strlen(szString);
+        szPadding[0] = 0;
+        for (iTemp = 0; iTemp < Padding; iTemp++)
+          strcat(szPadding, " ");
+
+        sprintf(szString, ST_SCORE2ASCII,
+          SortData[ SortList[CurClan] ]->szName,
+          szPadding, SortData[ SortList[CurClan] ]->PlainSymbol,
+          SortData[ SortList[CurClan] ]->Points);
+
+        if (SortData[ SortList[CurClan] ]->Eliminated)
+          strcat(szString, ST_SCORE6ASCII);
+        else if (SortData[ SortList[CurClan] ]->WorldStatus == WS_GONE)
+        {
+          strcat(szString, ST_SCORE3ASCII);
+        }
+        else
+        {
+          if (SortData[ SortList[CurClan] ]->Living == FALSE)
+            strcat(szString, "Dead");
+          else if (SortData[ SortList[CurClan] ]->VillageID != Config->BBSID
+            && Game.Data->InterBBS)
+            strcat(szString, "Visiting");
+          else
+            strcat(szString, ST_SCORE4ASCII);
+        }
+
+        if (SortData[ SortList[CurClan] ]->IsRuler)
+          strcat(szString, ST_SCORE5ASCII);
+        else
+          strcat(szString, "\n");
+
+        // for ASCII
+        fputs(szString, fpScoreFile[0]);
+
+        // for ANSI
+
+              PipeToAnsi(AnsiSymbol, SortData[ SortList[CurClan] ]->Symbol);
+
+              sprintf(szString, ST_SCORE2ANSI,
+          SortData[ SortList[CurClan] ]->szName,
+                  szPadding, AnsiSymbol,
+          SortData[ SortList[CurClan] ]->Points);
+
+        if (SortData[ SortList[CurClan] ]->Eliminated)
+          strcat(szString, ST_SCORE6ANSI);
+        else if (SortData[ SortList[CurClan] ]->WorldStatus == WS_GONE)
+        {
+          strcat(szString, ST_SCORE3ANSI);
+        }
+        else
+        {
+          if (SortData[ SortList[CurClan] ]->Living == FALSE)
+            strcat(szString, "\x1B[0;31mDead");
+          else if (SortData[ SortList[CurClan] ]->VillageID != Config->BBSID
+            && Game.Data->InterBBS)
+            strcat(szString, "Visiting");
+          else
+            strcat(szString, ST_SCORE4ANSI);
+        }
+
+        if (SortData[ SortList[CurClan] ]->IsRuler)
+          strcat(szString, ST_SCORE5ANSI);
+        else
+          strcat(szString, "\n");
+
+        fputs(szString, fpScoreFile[1]);
+      }
+    }
+
+    if (MakeFile)
+    {
+      fclose(fpScoreFile[0]);
+      fclose(fpScoreFile[1]);
+    }
+
+    if (MakeFile == FALSE)
+      rputs(ST_SCORELINE);
+
+    /* free mem used by sortdata */
+    for (iTemp = 0; iTemp < 128; iTemp++)
+      if (SortData[iTemp])
+      {
+        free(SortData[iTemp]);
+        SortData[iTemp] = NULL;
+      }
+
+    if (MakeFile == FALSE)
+      door_pause();
+  }
+
+
+
+/// ------------------------------------------------------------------------- //
+
+  void SendScoreData ( struct UserScore **UserScores )
+  {
+    _INT16 iTemp, NumScores;
+    struct Packet Packet;
+    FILE *fp;
+
+    // figure out how many scores
+    NumScores = 0;
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      if (UserScores[iTemp])
+        NumScores++;
+
+    /* create packet header */
+    Packet.Active = TRUE;
+    Packet.BBSIDTo = 1;         // Main BBS
+    Packet.BBSIDFrom = IBBS.Data->BBSID;
+    Packet.PacketType = PT_SCOREDATA;
+    strcpy(Packet.szDate, System.szTodaysDate);
+    Packet.PacketLength = NumScores*sizeof(struct UserScore) + sizeof(_INT16);
+    strcpy(Packet.GameID, Game.Data->GameID);
+
+    fp = _fsopen("tmp.$$$", "wb", SH_DENYRW);
+    if (!fp)  return;
+
+    // write packet header
+    EncryptWrite(&Packet, sizeof(struct Packet), fp, XOR_PACKET);
+
+    // write how many scores
+    EncryptWrite(&NumScores, sizeof(_INT16), fp, XOR_PACKET);
+
+    // write scores
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      if (UserScores[iTemp])
+        EncryptWrite(UserScores[iTemp], sizeof(struct UserScore), fp, XOR_PACKET);
+
+    fclose(fp);
+
+    IBBS_SendPacketFile(Packet.BBSIDTo, "tmp.$$$");
+    unlink("tmp.$$$");
+  }
+
+  void ProcessScoreData ( struct UserScore **UserScores )
+  {
+    struct UserScore **NewList;
+    struct UserScore **OldList;
+    struct UserScore *HighestFound;
+    FILE *fpOld, *fpNew;
+    BOOL FromOld = FALSE;
+    _INT16 iTemp, CurUser, CurScore, WhichOne = 0;
+    long HighestPoints;
+
+    // initialize lists
+    NewList = malloc(sizeof(struct UserScore *) * MAX_USERS);
+    OldList = malloc(sizeof(struct UserScore *) * MAX_USERS);
+    CheckMem(NewList);
+    CheckMem(OldList);
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      NewList[iTemp] = OldList[iTemp] = NULL;
+
+    // load up old list
+    fpOld = _fsopen("ipscores.dat", "rb", SH_DENYRW);
+    if (fpOld)
+    {
+      // skip date
+      fseek(fpOld, 11*sizeof(char), SEEK_SET);
+      for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      {
+        OldList[iTemp] = malloc(sizeof(struct UserScore));
+        CheckMem(OldList[iTemp]);
+        if (!EncryptRead(OldList[iTemp], sizeof(struct UserScore), fpOld, XOR_IPS))
+        {
+          free(OldList[iTemp]);
+          OldList[iTemp] = NULL;
+          break;
+        }
+      }
+      fclose(fpOld);
+    }
+
+    // merge lists by removing common elements in old list
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+    {
+      if (UserScores[iTemp])
+      {
+        // search through old list for this user, if there, delete him
+        // from the old list
+        for (CurUser = 0; CurUser < MAX_USERS; CurUser++)
+        {
+          if (OldList[CurUser] &&
+            OldList[CurUser]->ClanID[0] == UserScores[iTemp]->ClanID[0] &&
+            OldList[CurUser]->ClanID[1] == UserScores[iTemp]->ClanID[1])
+          {
+            // in old list, remove him
+            free(OldList[CurUser]);
+            OldList[CurUser] = NULL;
+          }
+        }
+      }
+    }
+
+    // sort lists
+    for (CurScore = 0; CurScore < MAX_TOPUSERS; CurScore++)
+    {
+      HighestPoints = 0;
+      HighestFound = NULL;
+
+      // go through old list first, look for score higher than current one
+      for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      {
+        if (OldList[iTemp] &&
+          OldList[iTemp]->Points >= HighestPoints)
+        {
+          HighestFound = OldList[iTemp];
+          HighestPoints = HighestFound->Points;
+          FromOld = TRUE;
+          WhichOne = iTemp;
+        }
+      }
+
+      // go through userscores list next
+      for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      {
+        if (UserScores[iTemp] &&
+          UserScores[iTemp]->Points >= HighestPoints)
+        {
+          HighestFound = UserScores[iTemp];
+          HighestPoints = HighestFound->Points;
+          FromOld = FALSE;
+
+          WhichOne = iTemp;
+        }
+      }
+
+      // if none higher found, stop now
+      if (HighestFound == NULL)
+        break;
+
+      // else, add to list, remove highest found from the list
+      NewList[CurScore] = malloc(sizeof(struct UserScore));
+      CheckMem(NewList[CurScore]);
+      *NewList[CurScore] = *HighestFound;
+
+      if (FromOld)
+      {
+        free(OldList[WhichOne]);
+        OldList[WhichOne] = NULL;
+      }
+      else
+      {
+        free(UserScores[WhichOne]);
+        UserScores[WhichOne] = NULL;
+      }
+    }
+
+    // write new list to file
+    fpNew = _fsopen("ipscores.dat", "wb", SH_DENYRW);
+    if (fpNew)
+    {
+      // write date
+      EncryptWrite(System.szTodaysDate, 11, fpNew, XOR_IPS);
+
+      for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+        if (NewList[iTemp])
+          EncryptWrite(NewList[iTemp], sizeof(struct UserScore), fpNew, XOR_IPS);
+
+      fclose(fpNew);
+    }
+
+    // free up lists we used
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+    {
+      if (NewList[iTemp])
+        free(NewList[iTemp]);
+      if (OldList[iTemp])
+        free(OldList[iTemp]);
+    }
+    free(NewList);
+    free(OldList);
+  }
+
+  void LeagueScores ( void )
+  {
+    struct UserScore **ScoreList;
+    _INT16 iTemp, UsersFound, /*CurID,*/ iTemp2, Padding;
+    char ScoreDate[11], szString[128], szPadding[21];
+    FILE *fp;
+
+    fp = _fsopen("ipscores.dat", "rb", SH_DENYRW);
+
+    if (!fp)
+    {
+      rputs(ST_LSCORES0);
+      return;
+    }
+
+    // initialize the score data
+    ScoreList = malloc(sizeof(struct UserScore *)*MAX_USERS);
+    CheckMem(ScoreList);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      ScoreList[iTemp] = NULL;
+
+    EncryptRead(ScoreDate, 11, fp, XOR_IPS);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+    {
+      ScoreList[iTemp] = malloc(sizeof(struct UserScore));
+      CheckMem(ScoreList[iTemp]);
+      if (!EncryptRead(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_IPS))
+      {
+        free(ScoreList[iTemp]);
+        ScoreList[iTemp] = NULL;
+        break;
+      }
+    }
+    UsersFound = iTemp;
+
+    sprintf(szString, ST_LSCORES2, ScoreDate);
+    rputs(szString);
+
+    rputs(ST_LSCORES1);
+    rputs(ST_LONGLINE);
+
+    // show scores
+    for (iTemp = 0; iTemp < UsersFound; iTemp++)
+    {
+      if (ScoreList[iTemp] == NULL)
+        break;
+
+      RemovePipes(ScoreList[iTemp]->Symbol, szString);
+      Padding = 20 - strlen(szString);
+      szPadding[0] = 0;
+      for (iTemp2 = 0; iTemp2 < Padding; iTemp2++)
+        strcat(szPadding, " ");
+
+      sprintf(szString, ST_LSCORES3,
+        ScoreList[iTemp]->szName,
+        szPadding,
+        ScoreList[iTemp]->Symbol,
+        ScoreList[iTemp]->Points,
+        IBBS.Data->Nodes[ ScoreList[iTemp]->ClanID[0]-1 ].Info.pszVillageName);
+      rputs(szString);
+    }
+
+    if (UsersFound == 0)
+      rputs(ST_LSCORES0);
+
+    rputs(ST_LONGLINE);
+    door_pause();
+
+    // free 'em
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      if (ScoreList[iTemp])
+        free(ScoreList[iTemp]);
+
+    free(ScoreList);
+
+    fclose(fp);
+  }
+
+  void RemoveFromIPScores ( _INT16 ClanID[2] )
+  {
+    struct UserScore **ScoreList;
+    _INT16 iTemp, UsersFound = 0;
+    char ScoreDate[11];
+    FILE *fp;
+
+    fp = _fsopen("ipscores.dat", "rb", SH_DENYRW);
+
+    if (!fp)
+    {
+      return;
+    }
+
+    // initialize the score data
+    ScoreList = malloc(sizeof(struct UserScore *)*MAX_USERS);
+    CheckMem(ScoreList);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      ScoreList[iTemp] = NULL;
+
+    // read date
+    EncryptRead(ScoreDate, 11, fp, XOR_IPS);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+    {
+      ScoreList[iTemp] = malloc(sizeof(struct UserScore));
+      CheckMem(ScoreList[iTemp]);
+      if (!EncryptRead(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_IPS))
+      {
+        free(ScoreList[iTemp]);
+        ScoreList[iTemp] = NULL;
+        break;
+      }
+
+      // if this is the user we wanted, remove him from the list
+      if (ScoreList[iTemp]->ClanID[0] == ClanID[0] &&
+        ScoreList[iTemp]->ClanID[1] == ClanID[1])
+      {
+        free(ScoreList[iTemp]);
+        ScoreList[iTemp] = NULL;
+      }
+    }
+    UsersFound = iTemp;
+    fclose(fp);
+
+    fp = _fsopen("ipscores.dat", "wb", SH_DENYRW);
+
+    // write date
+    EncryptWrite(ScoreDate, 11, fp, XOR_IPS);
+
+    // write them to file now and free them at the same time
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      if (ScoreList[iTemp])
+      {
+        EncryptWrite(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_IPS);
+        free(ScoreList[iTemp]);
+      }
+
+    free(ScoreList);
+
+    fclose(fp);
+  }
+
+  void SendScoreList ( void )
+  {
+    struct UserScore **ScoreList;
+    struct Packet Packet;
+    _INT16 iTemp, NumScores, CurBBS;
+    char ScoreDate[11];
+    FILE *fp;
+
+    fp = _fsopen("ipscores.dat", "rb", SH_DENYWR);
+
+    if (!fp)
+    {
+      // no scorefile yet
+      return;
+    }
+
+    // initialize the score data
+    ScoreList = malloc(sizeof(struct UserScore *)*MAX_USERS);
+    CheckMem(ScoreList);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      ScoreList[iTemp] = NULL;
+
+    EncryptRead(ScoreDate, 11, fp, XOR_IPS);
+
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+    {
+      ScoreList[iTemp] = malloc(sizeof(struct UserScore));
+      CheckMem(ScoreList[iTemp]);
+      if (!EncryptRead(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_IPS))
+      {
+        free(ScoreList[iTemp]);
+        ScoreList[iTemp] = NULL;
+        break;
+      }
+    }
+    NumScores = iTemp;
+
+    if (NumScores == 0)
+    {
+      // No scores have been generated yet.
+      free(ScoreList);
+      fclose(fp);
+      return;
+    }
+
+    fclose(fp);
+
+    /* create packet header */
+    Packet.Active = TRUE;
+    Packet.BBSIDFrom = IBBS.Data->BBSID;
+    Packet.PacketType = PT_SCORELIST;
+    strcpy(Packet.szDate, System.szTodaysDate);
+    Packet.PacketLength = NumScores*sizeof(struct UserScore) + sizeof(_INT16) +
+        sizeof(char)*11;
+    strcpy(Packet.GameID, Game.Data->GameID);
+
+    // send it to all bbses except this one in the league
+    for (CurBBS = 0; CurBBS < MAX_IBBSNODES; CurBBS++)
+    {
+      if (IBBS.Data->Nodes[CurBBS].Active == FALSE || CurBBS+1 == IBBS.Data->BBSID)
+        continue;
+
+      Packet.BBSIDTo = CurBBS+1;
+
+      fp = _fsopen("tmp.$$$", "wb", SH_DENYRW);
+      if (!fp)    return;
+
+      // write packet header
+      EncryptWrite(&Packet, sizeof(struct Packet), fp, XOR_PACKET);
+
+      // write how many scores
+      EncryptWrite(&NumScores, sizeof(_INT16), fp, XOR_PACKET);
+
+      // write date
+      EncryptWrite(ScoreDate, 11, fp, XOR_PACKET);
+
+      // write scores
+      for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+        if (ScoreList[iTemp])
+          EncryptWrite(ScoreList[iTemp], sizeof(struct UserScore), fp, XOR_PACKET);
+
+      fclose(fp);
+
+      // send packet to BBS
+      IBBS_SendPacketFile(Packet.BBSIDTo, "tmp.$$$");
+      unlink("tmp.$$$");
+    }
+
+    // free 'em
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      if (ScoreList[iTemp])
+        free(ScoreList[iTemp]);
+
+    free(ScoreList);
+  }
+
+  void CreateScoreData ( BOOL LocalOnly )
+  {
+    struct UserScore **UserScores;
+    struct clan *TmpClan;
+    FILE *fpPlayerFile;
+    _INT16 ClanNum, iTemp, NumClans;
+
+    UserScores = malloc( sizeof(struct UserScore *) * MAX_USERS);
+    CheckMem(UserScores);
+
+    // initialize scores to NULL pointers
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      UserScores[iTemp] = NULL;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    /* find guy in file */
+    fpPlayerFile = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYRW);
+    if (!fpPlayerFile)
+    {
+      free(UserScores);
+      free(TmpClan);
+      return;
+    }
+
+    // set all members to NULLs for now
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      TmpClan->Member[iTemp] = NULL;
+
+    NumClans = 0;
+    for (ClanNum = 0;; ClanNum++)
+    {
+      if (fseek(fpPlayerFile, (long)ClanNum * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET))
+        break;
+
+      if (!EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER))
+        break;
+
+      // skip if deleted
+      if (TmpClan->ClanID[0] == -1)
+        continue;
+
+      // else, add to list
+      UserScores[NumClans] = malloc(sizeof(struct UserScore));
+      CheckMem(UserScores[NumClans]);
+      strcpy(UserScores[NumClans]->szName, TmpClan->szName);
+      UserScores[NumClans]->Points = TmpClan->Points;
+      UserScores[NumClans]->BBSID = IBBS.Data->BBSID;
+      UserScores[NumClans]->ClanID[0] = TmpClan->ClanID[0];
+      UserScores[NumClans]->ClanID[1] = TmpClan->ClanID[1];
+      strcpy(UserScores[NumClans]->Symbol, TmpClan->Symbol);
+      NumClans++;
+    }
+    fclose(fpPlayerFile);
+
+    //printf("%d clans found.\n", NumClans);
+
+    // if not main BBS, write this data to file and send the packet
+    if (IBBS.Data->BBSID != 1 && LocalOnly == FALSE)
+    {
+      SendScoreData(UserScores);
+    }
+    else
+    {
+      ProcessScoreData(UserScores);
+    }
+
+    // free up mem used by score data
+    for (iTemp = 0; iTemp < MAX_USERS; iTemp++)
+      if (UserScores[iTemp])
+      {
+        free(UserScores[iTemp]);
+        UserScores[iTemp] = NULL;
+      }
+
+    free(TmpClan);
+    free(UserScores);
+  }
+
diff --git a/src/doors/clans-src/scores.h b/src/doors/clans-src/scores.h
new file mode 100644
index 0000000000000000000000000000000000000000..d763fdf574532a42547ec54171531422c2be0b9c
--- /dev/null
+++ b/src/doors/clans-src/scores.h
@@ -0,0 +1,10 @@
+  void DisplayScores ( BOOL MakeFile );
+
+  void CreateScoreData ( BOOL LocalOnly );
+  void SendScoreList ( void );
+
+  void LeagueScores ( void );
+
+  void ProcessScoreData ( struct UserScore **UserScores );
+
+  void RemoveFromIPScores ( _INT16 ClanID[2] );
diff --git a/src/doors/clans-src/snipfile.h b/src/doors/clans-src/snipfile.h
new file mode 100644
index 0000000000000000000000000000000000000000..b24eab966512b14c146d8c4b84559e913b96d9f8
--- /dev/null
+++ b/src/doors/clans-src/snipfile.h
@@ -0,0 +1,22 @@
+/*
+**  Header file for portable file functions
+*/
+
+#ifndef SNIPFILE__H
+#define SNIPFILE__H
+
+#include <stdio.h>
+
+long   flength(char *fname);                          /* Ansiflen.C     */
+FILE * cant(char *fname, char *fmode);                /* Ferrorf.C      */
+_INT16    fcompare(const char *fnam1, const char *fnam2);/* Fcompare.C     */
+long   fcopy(char *dest, char *source);               /* Fcopy.C        */
+long   ffsearch(FILE *fp, const char *pattern,
+             const size_t size, _INT16 N);               /* Srchfile.C     */
+long   rfsearch(FILE *fp, const char *pattern,
+             const size_t size, _INT16 N);               /* Srchfile.C     */
+void   show_text_file(char *txt);                     /* Textmod.C      */
+_INT16    file_copy(char *from, char *to);               /* Wb_Fcopy.C     */
+_INT16    file_append(char *from, char *to);             /* Wb_Fapnd.C     */
+
+#endif /* SNIPFILE__H */
diff --git a/src/doors/clans-src/spells.c b/src/doors/clans-src/spells.c
new file mode 100644
index 0000000000000000000000000000000000000000..8d2aebcbe8ae6d5657a7139c15cc079164055bb4
--- /dev/null
+++ b/src/doors/clans-src/spells.c
@@ -0,0 +1,757 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#endif
+
+#include "system.h"
+#include "structs.h"
+#include "door.h"
+#include "myopen.h"
+#include "language.h"
+#include "mstrings.h"
+#include "user.h"
+#include "video.h"
+
+BOOL SpellsInitialized = FALSE;
+struct Spell *Spells[MAX_SPELLS];
+extern struct IniFile IniFile;
+extern struct clan *PClan;
+extern struct Language *Language;
+extern struct village Village;
+
+char Spells_szCastDestination[25];
+char Spells_szCastSource[25];
+_INT16 Spells_CastValue;
+extern BOOL Verbose;
+
+
+// ------------------------------------------------------------------------- //
+
+/* Simple and more protective function to handle string loading in
+   Spells_Init()
+*/
+  char * get_spell (char **dest, FILE *fp)
+  {
+	_INT16 StringLength = 0;
+
+	if (!fread(&StringLength, sizeof(_INT16), 1, fp))
+		System_Error("fread failed in get_spell() [StringLength]");
+	else if (StringLength)
+	{
+		*dest = (char *) malloc (StringLength);
+		CheckMem(*dest);
+		if (!fread (*dest, StringLength, 1, fp))
+			System_Error ("fread failed in get_spell() [String Read]");
+	}
+	return (*dest);
+  }
+
+  void Spells_Init ( void )
+    /*
+     * This function loads spells from file.
+     */
+  {
+    _INT16 iTemp, NumSpells;
+    _INT16 CurFile, CurSpell = 0;
+    struct FileHeader SpellFile;
+
+    if (Verbose)
+    {
+      DisplayStr("> Spells_Init()\n");
+      delay(500);
+    }
+
+    SpellsInitialized = TRUE;
+
+    // for each file, read in the data
+    for (CurFile = 0; CurFile < MAX_SPELLFILES; CurFile++)
+    {
+      if (IniFile.pszSpells[CurFile] == NULL)
+        break;
+
+      // open file if possible
+      MyOpen(IniFile.pszSpells[CurFile], "rb", &SpellFile);
+
+      if (SpellFile.fp == NULL) continue;
+
+      // read in data
+
+      /* get num spells */
+      fread(&NumSpells, sizeof(_INT16), 1, SpellFile.fp);
+
+      /* read them in */
+      for (iTemp = 0; iTemp < NumSpells; iTemp++)
+      {
+        Spells[CurSpell] = malloc(sizeof(struct Spell));
+        CheckMem(Spells[CurSpell]);
+
+        fread(Spells[CurSpell], sizeof(struct Spell), 1, SpellFile.fp);
+
+        Spells[CurSpell]->pszHealStr = NULL;
+        Spells[CurSpell]->pszUndeadName = NULL;
+        Spells[CurSpell]->pszDamageStr = NULL;
+        Spells[CurSpell]->pszModifyStr = NULL;
+        Spells[CurSpell]->pszWearoffStr = NULL;
+        Spells[CurSpell]->pszStatusStr = NULL;
+        Spells[CurSpell]->pszOtherStr = NULL;
+
+        /* get strings */
+		get_spell (&Spells[CurSpell]->pszDamageStr, SpellFile.fp);
+		get_spell (&Spells[CurSpell]->pszHealStr, SpellFile.fp);
+		get_spell (&Spells[CurSpell]->pszModifyStr, SpellFile.fp);
+		get_spell (&Spells[CurSpell]->pszWearoffStr, SpellFile.fp);
+		get_spell (&Spells[CurSpell]->pszStatusStr, SpellFile.fp);
+		get_spell (&Spells[CurSpell]->pszOtherStr, SpellFile.fp);
+		get_spell (&Spells[CurSpell]->pszUndeadName, SpellFile.fp);
+        CurSpell++;
+        if (CurSpell == MAX_SPELLS)   break;
+      }
+      fclose(SpellFile.fp);
+
+      if (CurSpell == MAX_SPELLS)   break;
+    }
+
+    if (Verbose)
+    {
+      DisplayStr("> Spells_Init done()\n");
+      delay(500);
+    }
+
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Spells_Close ( void )
+    /*
+     * This function frees any mem initialized by Spells_Init.
+     */
+  {
+    _INT16 iTemp;
+
+    if (SpellsInitialized == FALSE) return;
+
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+    {
+      if (Spells[iTemp])
+      {
+        /* free strings first */
+        if (Spells[iTemp]->pszHealStr)
+          free(Spells[iTemp]->pszHealStr);
+        if (Spells[iTemp]->pszUndeadName)
+          free(Spells[iTemp]->pszUndeadName);
+        if (Spells[iTemp]->pszDamageStr)
+          free(Spells[iTemp]->pszDamageStr);
+        if (Spells[iTemp]->pszModifyStr)
+          free(Spells[iTemp]->pszModifyStr);
+        if (Spells[iTemp]->pszWearoffStr)
+          free(Spells[iTemp]->pszWearoffStr);
+        if (Spells[iTemp]->pszStatusStr)
+          free(Spells[iTemp]->pszStatusStr);
+        if (Spells[iTemp]->pszOtherStr)
+          free(Spells[iTemp]->pszOtherStr);
+
+        free(Spells[iTemp]);
+        Spells[iTemp] = NULL;
+      }
+    }
+
+    SpellsInitialized = FALSE;
+  }
+
+
+// ------------------------------------------------------------------------- //
+  void Spells_UpdatePCSpells( struct pc *PC )
+  {
+    _INT16 iTemp;
+
+    /* set up %SD so it shows this dude */
+    strcpy(Spells_szCastDestination, PC->szName);
+
+    /* reduce each spell in effect accordingly */
+    for (iTemp = 0; iTemp < 10; iTemp++)
+    {
+      /* skip if no spell in that slot */
+      if (PC->SpellsInEffect[iTemp].SpellNum == -1)
+        continue;
+
+      /* reduce by 10 this round */
+      PC->SpellsInEffect[iTemp].Energy -= 10;
+
+      /* if strength can reduce this, reduce it */
+      if (Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->Friendly == FALSE &&
+          Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->StrengthCanReduce)
+      {
+        PC->SpellsInEffect[iTemp].Energy -= (GetStat(PC, ATTR_STRENGTH)/2);
+      }
+      /* if wisdom can reduce this, reduce it */
+      if (Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->Friendly == FALSE &&
+          Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->WisdomCanReduce)
+      {
+        PC->SpellsInEffect[iTemp].Energy -= (GetStat(PC, ATTR_WISDOM)/2);
+      }
+
+      /* check wisdom variables + Level var
+         -- this increases chance of spell wearing off */
+
+      /* see if spell is dead */
+      if (PC->SpellsInEffect[iTemp].Energy <= 0)
+      {
+        /* if so, display ending string */
+        rputs(Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->pszWearoffStr);
+
+        /* kill spell */
+        PC->SpellsInEffect[iTemp].Energy = 0;
+        PC->SpellsInEffect[iTemp].SpellNum = -1;
+      }
+    }
+  }
+
+  void Spells_ClearSpells( struct clan *Clan )
+  {
+    _INT16 CurMember, iTemp;
+
+    for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+    {
+      if (Clan->Member[CurMember])
+        for (iTemp = 0; iTemp < 10; iTemp++)
+          Clan->Member[CurMember]->SpellsInEffect[iTemp].SpellNum = -1;
+    }
+  }
+
+
+  void Spells_CastSpell(struct pc *PC, struct clan *EnemyClan, _INT16 Target, _INT16 SpellNum)
+  {
+    BOOL Test = FALSE;
+    _INT16 Damage, Value, HPIncrease, OldHP, Level;
+    char szString[128];
+    struct pc *TargetPC;
+    long XPGained, GoldGained, TaxedGold;
+    _INT16 iTemp, NumUndead, NumUndeadToRemove, CurSlot, iTemp2/*, PercentGold*/;
+    _INT16 NumUndeadRemoved;
+
+    /* see if spell cast was successful, if not, return */
+
+    /* do stuff according to type of spell it is */
+    // od_printf("Spell chosen was %d\n\r", SpellNum);
+
+    /* set up global vars */
+    strcpy(Spells_szCastSource, PC->szName);
+
+    if (Spells[SpellNum]->Friendly == FALSE)
+    {
+      if (Spells[SpellNum]->Target)
+        strcpy(Spells_szCastDestination, EnemyClan->Member[Target]->szName);
+      else
+        strcpy(Spells_szCastDestination, EnemyClan->szName);
+
+      TargetPC = EnemyClan->Member[Target];
+    }
+    else
+    {
+      if (Spells[SpellNum]->Target)
+        strcpy(Spells_szCastDestination, PC->MyClan->Member[Target]->szName);
+      else
+        strcpy(Spells_szCastDestination, PC->MyClan->szName);
+
+      TargetPC = PC->MyClan->Member[Target];
+    }
+
+    if (Spells[SpellNum]->TypeFlag & SF_BANISHUNDEAD)
+    {
+      if (Test)
+        printf("\aError!\n");
+      else
+        Test = TRUE;
+      /* see if spell is successful */
+      if ((PC->Level + 3 + Spells[SpellNum]->TypeFlag + GetStat(PC, ATTR_WISDOM) +
+          RANDOM(5)) < RANDOM(15) )
+      {
+        sprintf(szString, ST_SPELLFAIL, PC->szName, Spells[SpellNum]->szName);
+        rputs(szString);
+        return;
+      }
+
+      /* banish undead warriors from this realm */
+
+      /* see how many undead the enemy has */
+      NumUndead = 0;
+      for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      {
+        if (EnemyClan->Member[iTemp] &&
+            EnemyClan->Member[iTemp]->Undead &&
+            EnemyClan->Member[iTemp]->Status == Here)
+          NumUndead++;
+      }
+
+      if (NumUndead == 0)
+      {
+        // no undead to banish
+        rputs(ST_SPELLNOUNDEAD);
+        return;
+      }
+
+      /* see how many undead to banish */
+      NumUndeadToRemove = RANDOM(4) + 1;
+
+      /* if too many to remove, truncate size */
+      if (NumUndeadToRemove > NumUndead)
+        NumUndeadToRemove = NumUndead;
+
+      /* output of spell */
+      rputs(Spells[SpellNum]->pszOtherStr);
+
+      /* figure out XP gained */
+      XPGained = NumUndeadToRemove * 4;
+      sprintf(szString, ST_FIGHTXP, XPGained);
+      rputs(szString);
+      PC->Experience += XPGained;
+      rputs("\n\n");
+
+      /* now remove 'em */
+      NumUndeadRemoved = 0;
+      while (NumUndeadRemoved < NumUndeadToRemove)
+      {
+        /* go through player file till found an undead character */
+        /* remove him */
+
+        /* find open slot to use */
+        for (CurSlot = 0; CurSlot < MAX_MEMBERS; CurSlot++)
+        {
+          if (EnemyClan->Member[CurSlot] &&
+              EnemyClan->Member[CurSlot]->Undead &&
+              EnemyClan->Member[CurSlot]->Status == Here)
+            break;
+        }
+
+        if (CurSlot == MAX_MEMBERS)
+          break;
+
+        sprintf(szString, "|04*** |12%s is banished!\n\n",
+          EnemyClan->Member[CurSlot]->szName);
+        rputs(szString);
+
+        /* found undead, remove him */
+        EnemyClan->Member[CurSlot]->Status = Dead;
+        EnemyClan->Member[CurSlot]->HP = 0;
+        NumUndeadRemoved++;
+      }
+    }
+
+    if (Spells[SpellNum]->TypeFlag & SF_RAISEUNDEAD)
+    {
+      if (Test)
+        printf("\aError!\n");
+      else
+        Test = TRUE;
+      /* see if spell is successful */
+      if ((PC->Level + Spells[SpellNum]->Level + GetStat(PC, ATTR_WISDOM) + RANDOM(6)) <
+          RANDOM(15))
+      {
+        sprintf(szString, ST_SPELLFAIL, PC->szName, Spells[SpellNum]->szName);
+        rputs(szString);
+        return;
+      }
+
+      /* raise undead */
+
+      /* see how many undead to raise */
+      if (Spells[SpellNum]->Value == 0)
+        NumUndead = RANDOM(2 + PC->Level/4) + 1;
+      else
+        NumUndead = Spells[SpellNum]->Value;
+
+      //od_printf("Tried raising %d undead\n\r", NumUndead);
+
+      if (NumUndead > 4)
+        NumUndead = 4;
+
+      /* now make 'em */
+      for (iTemp = 0; iTemp < NumUndead; iTemp++)
+      {
+        /* find open slot to use */
+        for (CurSlot = 0; CurSlot < MAX_MEMBERS; CurSlot++)
+        {
+          if (PC->MyClan->Member[CurSlot] == NULL)
+            break;
+        }
+
+        if (CurSlot == MAX_MEMBERS)
+        {
+          sprintf(szString, ST_SPELLFAIL, PC->szName, Spells[SpellNum]->szName);
+          rputs(szString);
+          return;
+        }
+
+        //od_printf("Using %d as slot\n\r", CurSlot);
+
+        /* found slot, fill it up */
+        PC->MyClan->Member[CurSlot] = (struct pc *) malloc(sizeof(struct pc));
+        CheckMem(PC->MyClan->Member[CurSlot]);
+
+        strcpy(PC->MyClan->Member[CurSlot]->szName, Spells[SpellNum]->pszUndeadName);
+        PC->MyClan->Member[CurSlot]->Undead = TRUE;
+        PC->MyClan->Member[CurSlot]->Status = Here;
+
+        PC->MyClan->Member[CurSlot]->MaxHP =
+            PC->MyClan->Member[CurSlot]->HP = RANDOM(10) + 5 + PC->Level;
+
+        PC->MyClan->Member[CurSlot]->MaxSP =
+            PC->MyClan->Member[CurSlot]->SP = 0;
+
+        for (iTemp2 = 0; iTemp2 < NUM_ATTRIBUTES; iTemp2++)
+        {
+          /* if attributes set, use them, otherwise, use caster's */
+          if (Spells[SpellNum]->Attributes[iTemp2])
+            PC->MyClan->Member[CurSlot]->Attributes[iTemp2] =
+              Spells[SpellNum]->Attributes[iTemp2] + RANDOM(1);
+          else
+          {
+            PC->MyClan->Member[CurSlot]->Attributes[iTemp2] =
+              PC->Attributes[iTemp2]  - 2 + RANDOM(4);
+          }
+        }
+
+        PC->MyClan->Member[CurSlot]->Weapon = 0;
+        PC->MyClan->Member[CurSlot]->Armor = 0;
+        PC->MyClan->Member[CurSlot]->Shield = 0;
+
+        PC->MyClan->Member[CurSlot]->WhichRace = -1;
+        PC->MyClan->Member[CurSlot]->WhichClass = 0;
+        PC->MyClan->Member[CurSlot]->Experience = 0;
+        PC->MyClan->Member[CurSlot]->Level = 0;
+
+        PC->MyClan->Member[CurSlot]->MyClan = PC->MyClan;
+
+        for (iTemp2 = 0; iTemp2 < MAX_SPELLS; iTemp2++)
+          PC->MyClan->Member[CurSlot]->SpellsKnown[iTemp2] = 0;
+
+        for (iTemp2 = 0; iTemp2 < 10; iTemp2++)
+          PC->MyClan->Member[CurSlot]->SpellsInEffect[iTemp2].SpellNum = -1;
+
+        PC->MyClan->Member[CurSlot]->Difficulty = 1;
+      }
+
+      /* output of spell */
+      rputs(Spells[SpellNum]->pszOtherStr);
+
+      /* figure out XP gained */
+      XPGained = NumUndead * 2;
+      sprintf(szString, ST_FIGHTXP, XPGained);
+      rputs(szString);
+      PC->Experience += XPGained;
+      rputs("\n\n");
+    }
+
+    if (Spells[SpellNum]->TypeFlag & SF_HEAL)
+    {
+      if (Test)
+        printf("\aError!\n");
+      else
+        Test = TRUE;
+      /* heal him */
+
+      OldHP = PC->MyClan->Member[Target]->HP;
+
+      if (PC->Level > 10)
+        Level = 10;
+      else
+        Level = PC->Level;
+
+      Value = (((Spells[SpellNum]->Value + Level/2)*(RANDOM(50)+50))/100);
+
+      PC->MyClan->Member[Target]->HP += Value;
+      if (PC->MyClan->Member[Target]->HP > PC->MyClan->Member[Target]->MaxHP)
+        PC->MyClan->Member[Target]->HP = PC->MyClan->Member[Target]->MaxHP;
+
+      HPIncrease = PC->MyClan->Member[Target]->HP - OldHP;
+      Spells_CastValue = HPIncrease;
+
+      /* output of spell */
+      rputs(Spells[SpellNum]->pszHealStr);
+
+      /* figure out XP gained */
+      XPGained = HPIncrease/3;
+      sprintf(szString, ST_FIGHTXP, XPGained);
+      rputs(szString);
+      PC->Experience += XPGained;
+
+      rputs("\n\n");
+    }
+
+    if (((Spells[SpellNum]->TypeFlag & SF_MODIFY) ||
+      (Spells[SpellNum]->TypeFlag & SF_INCAPACITATE)))
+    {
+      if (Test)
+        printf("\aError!\n");
+      else
+        Test = TRUE;
+      /* see if spell is successful */
+      if (Spells[SpellNum]->Friendly)
+      {
+        if ((PC->Level + Spells[SpellNum]->Level + GetStat(PC, ATTR_WISDOM) +
+            RANDOM(12)) < (RANDOM(12)) )
+        {
+          sprintf(szString, ST_SPELLFAIL, PC->szName, Spells[SpellNum]->szName);
+          rputs(szString);
+          return;
+        }
+      }
+      else
+      {
+        if ((PC->Level + GetStat(PC, ATTR_WISDOM) + RANDOM(8) + Spells[SpellNum]->Level) <
+          (TargetPC->Level + GetStat(TargetPC, ATTR_WISDOM) + RANDOM(4)))
+        {
+          sprintf(szString, ST_SPELLFAIL, PC->szName,
+            Spells[SpellNum]->szName);
+          rputs(szString);
+          return;
+        }
+      }
+
+      /* see if spell is successfully cast */
+
+      /* put in SpellsInEffect */
+
+      /* see if spell in effect already, if so, just add onto energy */
+      for (iTemp = 0; iTemp < 10; iTemp++)
+      {
+        if (TargetPC->SpellsInEffect[iTemp].SpellNum == SpellNum)
+        {
+          /* found one which is same as this */
+          break;
+        }
+      }
+
+      if (iTemp != 10)
+      {
+        /* means it broke; early so just add onto the Energy */
+        TargetPC->SpellsInEffect[iTemp].Energy += Spells[SpellNum]->Energy;
+      }
+      else
+      {
+        /* find empty slot, if none found just use #9*/
+        for (iTemp = 0; iTemp < 10; iTemp++)
+        {
+          if (TargetPC->SpellsInEffect[iTemp].SpellNum == -1)
+            break;
+        }
+
+        if (iTemp == 10)
+          iTemp = 9;
+
+        /* now set spell */
+        TargetPC->SpellsInEffect[iTemp].SpellNum = SpellNum;
+        TargetPC->SpellsInEffect[iTemp].Energy = Spells[SpellNum]->Energy + (GetStat(PC, ATTR_WISDOM)*4) + PC->Level*2;
+      }
+
+      /* output of spell */
+      rputs(Spells[SpellNum]->pszModifyStr);
+
+      /* figure out XP gained */
+      XPGained = 3;
+      sprintf(szString, ST_FIGHTXP, XPGained);
+      rputs(szString);
+      PC->Experience += XPGained;
+      rputs("\n\n");
+    }
+
+    if (Spells[SpellNum]->TypeFlag & SF_DAMAGE)
+    {
+      if (Test)
+        printf("\aError!\n");
+      else
+        Test = TRUE;
+      // if is multiaffect spell, go through each guy
+
+      // if multiaffect, start from first enemy
+      if (Spells[SpellNum]->MultiAffect)
+        Target = 0;
+
+      // the following for loop incorporates both single damage spells
+      // and multi damage, it can be a bit tricky!
+
+      for (; Target < MAX_MEMBERS; Target++)
+      {
+        if (Spells[SpellNum]->MultiAffect)
+        {
+          // skip this dude if not alive or here
+          if (EnemyClan->Member[Target] == NULL || EnemyClan->Member[Target]->Status != Here)
+          {
+            continue;
+          }
+
+          TargetPC = EnemyClan->Member[Target];
+
+          strcpy(Spells_szCastDestination, EnemyClan->Member[Target]->szName);
+        }
+        else
+        {
+          // not multiaffect, so end spell now since target no longer exists
+          if (EnemyClan->Member[Target] == NULL || EnemyClan->Member[Target]->Status != Here)
+          {
+            break;
+          }
+        }
+
+        if ((PC->Level + GetStat(PC, ATTR_WISDOM) + RANDOM(10) + 8 + Spells[SpellNum]->Level) <
+          (TargetPC->Level + GetStat(TargetPC, ATTR_WISDOM) + RANDOM(6)))
+        {
+          // failed attack
+
+          sprintf(szString, ST_SPELLFAIL, PC->szName, Spells[SpellNum]->szName);
+          rputs(szString);
+
+          // if this ain't a multihit spell, break from for loop now
+          if (Spells[SpellNum]->MultiAffect == FALSE)
+            break;
+          else
+            continue;
+        }
+
+        /* damage him */
+        Level = PC->Level;
+        if (Level > 10)
+          Level = 10;
+
+        Damage = ((Spells[SpellNum]->Value+(Level+GetStat(PC, ATTR_WISDOM))/3)*(RANDOM(60) + 50))/100
+          - GetStat(TargetPC, ATTR_ARMORSTR);
+        Spells_CastValue = Damage;
+
+        if (Damage <= 0)
+        {
+          //rputs(Spells[SpellNum]->pszDamageStr);
+          //rputs("\n");
+
+          sprintf(szString, ST_SPELLFAIL, PC->szName,
+            Spells[SpellNum]->szName);
+          rputs(szString);
+        }
+        else
+        {
+          rputs(Spells[SpellNum]->pszDamageStr);
+
+          /* experience goes here */
+          XPGained = Damage/3 + 1;
+          sprintf(szString, ST_FIGHTXP, XPGained);
+          rputs(szString);
+          PC->Experience += XPGained;
+
+          EnemyClan->Member[Target]->HP -= Damage;
+
+          rputs("\n\n");
+        }
+
+        if (EnemyClan->Member[Target]->HP <= 0)
+        {
+          //od_printf("in cspells\n\r");
+
+          /* according to how bad the hit was, figure out status */
+          if (EnemyClan->szName[0] == 0)
+          {
+            EnemyClan->Member[Target]->Status = Dead;
+            sprintf(szString, ST_FIGHTKILLED, EnemyClan->Member[Target]->szName,
+              EnemyClan->Member[Target]->Difficulty);
+
+            /* give xp because of death */
+            PC->Experience += (EnemyClan->Member[Target]->Difficulty);
+          }
+          else if (EnemyClan->Member[Target]->HP < -15)
+          {
+            EnemyClan->Member[Target]->Status = Dead;
+            sprintf(szString, ST_FIGHTKILLED, EnemyClan->Member[Target]->szName,
+              EnemyClan->Member[Target]->Level*2);
+
+            /* loses percentage of MaxHP */
+            EnemyClan->Member[Target]->MaxHP = (EnemyClan->Member[Target]->MaxHP * (RANDOM(10)+90))/100;
+
+            /* give xp because of death */
+            PC->Experience += (EnemyClan->Member[Target]->Level*2);
+          }
+          else if (EnemyClan->Member[Target]->HP < -5)
+          {
+            EnemyClan->Member[Target]->Status = Unconscious;
+            sprintf(szString, ST_FIGHTMORTALWOUND, EnemyClan->Member[Target]->szName,
+              EnemyClan->Member[Target]->Level);
+
+            /* loses percentage of MaxHP */
+            EnemyClan->Member[Target]->MaxHP = (EnemyClan->Member[Target]->MaxHP * (RANDOM(10)+90))/100;
+
+            PC->Experience += (EnemyClan->Member[Target]->Level);
+          }
+          else
+          {
+            EnemyClan->Member[Target]->Status = Unconscious;
+            sprintf(szString, ST_FIGHTKNOCKEDOUT, EnemyClan->Member[Target]->szName,
+              EnemyClan->Member[Target]->Level);
+
+            PC->Experience += (EnemyClan->Member[Target]->Level);
+          }
+          rputs(szString);
+
+          /* give gold to clan */
+          if (PC->MyClan == PClan)
+          {
+            if (EnemyClan->Member[Target]->Difficulty != -1)
+            {
+              GoldGained = EnemyClan->Member[Target]->Difficulty*((long)RANDOM(10) + 20L) + 50L + (long)RANDOM(20);
+              sprintf(szString, ST_FIGHTGETGOLD, GoldGained);
+              rputs(szString);
+
+              /* take some away due to taxes */
+              if (GoldGained > 0)
+              {
+                TaxedGold = (long)(GoldGained * Village.Data->TaxRate)/100L;
+                if (TaxedGold)
+                {
+                  sprintf(szString, ST_FIGHTTAXEDGOLD, TaxedGold);
+                  rputs(szString);
+                }
+
+                PClan->Empire.VaultGold += (GoldGained-TaxedGold);
+                Village.Data->Empire.VaultGold += TaxedGold;
+              }
+            }
+          }
+
+          // if that character was an undead dude, free him up
+          if (EnemyClan->Member[Target]->Undead)
+          {
+            // BUGFIX:
+            free(EnemyClan->Member[Target]);
+            EnemyClan->Member[Target] = NULL;
+          }
+        }
+
+        // if this ain't a multihit spell, break from for loop now
+        if (Spells[SpellNum]->MultiAffect == FALSE)
+          break;
+      }   // end of for()
+
+    }
+  }
diff --git a/src/doors/clans-src/spells.h b/src/doors/clans-src/spells.h
new file mode 100644
index 0000000000000000000000000000000000000000..068dfdc62cb5c3b3a5b88266d5fee670897ec11a
--- /dev/null
+++ b/src/doors/clans-src/spells.h
@@ -0,0 +1,14 @@
+
+  void Spells_Init ( void );
+    /*
+     * This function loads spells from file.
+     */
+
+  void Spells_Close ( void );
+    /*
+     * This function frees any mem initialized by Spells_Init.
+     */
+
+  void Spells_UpdatePCSpells( struct pc *PC );
+  void Spells_ClearSpells( struct clan *Clan );
+  void Spells_CastSpell(struct pc *PC, struct clan *EnemyClan, _INT16 Target, _INT16 SpellNum);
diff --git a/src/doors/clans-src/structs.h b/src/doors/clans-src/structs.h
new file mode 100644
index 0000000000000000000000000000000000000000..07f7438dcf4dbbe55db7bae26a92439f03999744
--- /dev/null
+++ b/src/doors/clans-src/structs.h
@@ -0,0 +1,671 @@
+#include "defines.h"
+
+struct PACKED IniFile {
+	__BOOL Initialized;
+
+	char *pszLanguage;
+	char *pszNPCFileName[MAX_NPCFILES];
+	char *pszSpells[MAX_SPELLFILES];
+	char *pszItems[MAX_ITEMFILES];
+	char *pszRaces[MAX_RACEFILES];
+	char *pszClasses[MAX_CLASSFILES];
+	char *pszVillages[MAX_VILLFILES];
+} PACKED;
+
+
+struct PACKED config {
+
+  char szSysopName[40];
+  char szBBSName[40];
+
+  char szScoreFile[2][40];        // 0 == ascii, 1 == ansi
+  char szRegcode[25];
+
+  /*
+   * IBBS Specific data
+   */
+  _INT16 BBSID;
+  __BOOL InterBBS;
+  char szNetmailDir[30];
+  char szInboundDir[30];
+  _INT16 MailerType;
+} PACKED;
+
+struct PACKED system {
+  __BOOL Initialized;
+
+  char szTodaysDate[11];
+  char szMainDir[40];
+
+  _INT16 Node;
+  __BOOL InterBBS;
+  __BOOL Local;
+  __BOOL LocalIBBS;
+} PACKED;
+
+struct PACKED PClass {
+	char szName[15];
+	char Attributes[NUM_ATTRIBUTES];
+	_INT16 MaxHP;
+	_INT16 Gold;
+  _INT16 MaxSP;
+  char SpellsKnown[MAX_SPELLS];
+
+	_INT16 VillageType;		// which villages is this allowed in?  0 == ALL
+} PACKED;
+
+struct PACKED Strategy {
+	char AttackLength, AttackIntensity, LootLevel;
+	char DefendLength, DefendIntensity;
+
+	/*
+
+-		*Length = 1..10 <- how long battle is
+
+		ex:
+		if AttackLength = 10 and defender's defendlength = 2,
+
+		NumRounds = (10 + 2) / 2 = 6;
+
+-		*Type	   =	Light		-- small attacks, less vulnerable
+						Moderate	-- moderate attacks on all grounds, medium
+						Heavy		-- heavy attacks, more vulnerable
+
+-		LootLevel = How much you will loot or attempt to loot in percentage
+
+			allowable levels:	10% - low
+								20% - moderate
+								30% - high
+
+	*/
+} PACKED;
+
+
+struct PACKED Army {
+	long Footmen, Axemen, Knights, Followers;
+	char Rating;						// 0-100%, 100% = strongest
+	char Level; 						// useable later?
+
+	struct PACKED Strategy Strategy;
+
+	long CRC;
+} PACKED;
+
+struct PACKED empire {
+	char szName[25];				// who's empire
+	_INT16 OwnerType;					// what type of empire? clan, alliance, vill
+	long VaultGold;
+	_INT16 Land;						// amount of land available for use
+	_INT16 Buildings[MAX_BUILDINGS];	// # of each building type
+	_INT16 AllianceID;
+	char WorkerEnergy;				// energy left for builders in %'age
+	_INT16 LandDevelopedToday; 		// how much development we did
+	_INT16 SpiesToday; 				// how many spying attempts today?
+	_INT16 AttacksToday;
+	long Points;					// used in future?
+	_INT16 Junk[4];
+
+	// other stuff goes here
+	struct PACKED Army Army;
+
+	long CRC;
+} PACKED;
+
+
+
+struct PACKED village {
+  __BOOL Initialized;
+
+  struct PACKED village_data {
+    char ColorScheme[50];
+    char szName[30];
+
+    _INT16 TownType;
+    _INT16 TaxRate, InterestRate, GST;
+    _INT16 ConscriptionRate;
+
+    _INT16 RulingClanId[2];
+    char szRulingClan[25];
+    _INT16 GovtSystem;
+    _INT16 RulingDays;
+
+    unsigned _INT16 PublicMsgIndex;
+
+    _INT16 MarketLevel;
+    _INT16 TrainingHallLevel;  /* how good is the training hall? */
+    _INT16 ChurchLevel;    /* how good is the church */
+    _INT16 PawnLevel;      // level of pawn shop
+    _INT16 WizardLevel;    // wizard's shop level
+
+    unsigned _INT16
+       SetTaxToday     : 1,
+       SetInterestToday: 1,
+       SetGSTToday     : 1,
+       UpMarketToday   : 1,
+       UpTHallToday    : 1,
+       UpChurchToday   : 1,
+       UpPawnToday     : 1,
+       UpWizToday      : 1,
+       SetConToday     : 1,
+       ShowEmpireStats : 1,
+       Junk            : 6;
+
+    char HFlags[8];         /* daily flags -- reset nightly */
+    char GFlags[8];         /* global flags -- reset with reset */
+
+    _INT16 VillageType;    // what type of village do we have here?
+
+    _INT16 CostFluctuation;  // from -10% to +10%
+    _INT16 MarketQuality;
+
+    struct PACKED empire Empire;
+
+    long CRC;                 // used to prevent cheating
+  } *Data;
+} PACKED;
+
+struct PACKED game {
+  __BOOL Initialized;
+
+  struct PACKED game_data {
+    _INT16 GameState;            // 0 == Game is in progress
+                              // 1 == Game is waiting for day to come to play
+                              // 2 == Game is inactive, waiting for reset msg.
+                              //      from LC
+
+    __BOOL InterBBS;            // set to TRUE if IBBS *originally*
+                              // check when entering game against
+                              // Config->InterBBS to see if cheating occurs
+
+    char szTodaysDate[11];    // Set to today's date when maintenance run
+    char szDateGameStart[11]; // First day new game begins
+    char szLastJoinDate[11];  // Last day to join game
+
+    _INT16 NextClanID;           // contains next available clanid[1] value
+    _INT16 NextAllianceID;       // contains next available alliance ID
+
+
+    // ---- league specific data, not used in local games
+    char szWorldName[30];     // league's world name
+    char LeagueID[3];         // 2 char league ID
+    char GameID[16];          // used to differentiate from old league games
+    __BOOL ClanTravel;          // TRUE if clans are allowed to travel
+    _INT16 LostDays;             // # of days before lost packets are returned
+    // ----
+
+    // ---- Individual game settings go here
+    _INT16 MaxPermanentMembers;  // up to 6
+    __BOOL ClanEmpires;         // toggles whether clans can create empires
+    _INT16 MineFights,           // Max # of mine fights per day
+        ClanFights,           // max # of clan fights per day
+        DaysOfProtection;     // # of days of protection for newbies
+
+    long CRC;                 // used to prevent cheating
+
+  } *Data;
+} PACKED;
+
+struct PACKED SpellsInEffect {
+	_INT16 SpellNum;	/* set to -1 so that it's inactive */
+	_INT16 Energy; 	/* how much energy of spell remains, sees if it runs out */
+} PACKED;
+
+struct PACKED item_data {
+	__BOOL Available;
+	_INT16 UsedBy; 	/* 0 means nobody, 1.. etc. gives num of who uses it +1 */
+	char szName[25];
+	char cType;
+	__BOOL Special;	/* if special item, can't be bought or sold */
+	_INT16 SpellNum;	// which spell do you cast when reading this scroll?
+
+	char Attributes[NUM_ATTRIBUTES];
+	char ReqAttributes[NUM_ATTRIBUTES];
+
+	long lCost;
+	__BOOL DiffMaterials; 	/* means it can be made with different matterials */
+	_INT16 Energy; 			/* how long before it "breaks"? */
+	_INT16 MarketLevel;		// what level of market before this is seen?
+
+	_INT16 VillageType;		// which villages is this allowed in?  0 == ALL
+	long ItemDate;			// when was item taken into the pawn shop?
+	char RandLevel; 		// from 0 - 10, level of randomness, 10 is highest
+	char HPAdd, SPAdd;
+} PACKED;
+
+
+struct PACKED pc {
+	char szName[20];
+	_INT16 HP, MaxHP;
+  _INT16 SP, MaxSP;
+
+	char Attributes[NUM_ATTRIBUTES];
+	char Status;
+
+	_INT16 Weapon, Shield, Armor;
+
+	_INT16 WhichRace, WhichClass;
+	long Experience;
+	_INT16 Level;
+	_INT16 TrainingPoints;
+
+  struct PACKED clan *MyClan;  /* pointer to his clan */
+  char SpellsKnown[MAX_SPELLS];
+
+  struct PACKED SpellsInEffect SpellsInEffect[10]; /* 10 spells is sufficient */
+
+
+	_INT16 Difficulty; 		/* used only by monsters */
+  char Undead : 1,
+		 DefaultAction : 7; 	  // default action:
+							//
+							// 0 == attack
+							// 1 == skip it, do nothing
+							// 10 == spell #0
+							// 11 == spell #1
+							// 1x == spell #x
+
+	long CRC;
+} PACKED;
+
+struct PACKED clan {
+  _INT16 ClanID[2];
+  char szUserName[30];
+  char szName[25];
+  char Symbol[21];
+
+  char QuestsDone[8], QuestsKnown[8];
+
+  char PFlags[8], DFlags[8];
+  char ChatsToday, TradesToday;
+
+	_INT16 ClanRulerVote[2];		// who are you voting for as the ruler?
+
+	_INT16 Alliances[MAX_ALLIES];		// alliances change from BBS to BBS, -1
+                                // means no alliance, 0 = first one, ID
+                                // that is...
+
+  long Points;
+  char szDateOfLastGame[11];
+
+  _INT16 FightsLeft, ClanFights,
+      MineLevel;
+
+  _INT16 WorldStatus, DestinationBBS;
+
+	char VaultWithdrawals;
+
+  _INT16 PublicMsgIndex;
+
+	_INT16 ClanCombatToday[MAX_CLANCOMBAT][2];
+  _INT16 ClanWars;
+
+  struct PACKED pc *Member[MAX_MEMBERS];
+  struct PACKED item_data Items[MAX_ITEMS_HELD];
+
+	char ResUncToday, ResDeadToday ;
+
+  struct PACKED empire Empire;
+
+  // Help
+  _INT16 DefActionHelp : 1,
+       CommHelp      : 1,
+       MineHelp      : 1,
+       MineLevelHelp : 1,
+       CombatHelp    : 1,
+       TrainHelp     : 1,
+       MarketHelp    : 1,
+       PawnHelp      : 1,
+       WizardHelp    : 1,
+       EmpireHelp    : 1,
+       DevelopHelp   : 1,
+       TownHallHelp  : 1,
+       DestroyHelp   : 1,
+       ChurchHelp    : 1,
+       THallHelp     : 1,
+       SpyHelp       : 1,
+       AllyHelp      : 1,
+       WarHelp       : 1,
+       VoteHelp      : 1,
+       TravelHelp    : 1,
+
+       WasRulerToday : 1,
+       MadeAlliance  : 1,
+       Protection    : 4,
+       FirstDay      : 1,
+       Eliminated    : 1,
+       QuestToday    : 1,
+       AttendedMass  : 1,
+       GotBlessing   : 1,
+       Prayed        : 1;
+  
+  long CRC;
+} PACKED;
+
+struct PACKED Spell {
+	char szName[20];
+	_INT16 TypeFlag;
+	__BOOL Friendly;
+	__BOOL Target;
+	char Attributes[NUM_ATTRIBUTES];
+	char Value;
+	_INT16 Energy;
+	char Level; 	/* used to see if affects target */
+	char *pszDamageStr;
+	char *pszHealStr;
+	char *pszModifyStr;
+	char *pszWearoffStr;
+	char *pszStatusStr;
+	char *pszOtherStr;
+	char *pszUndeadName;
+  _INT16 SP;
+	__BOOL StrengthCanReduce;
+	__BOOL WisdomCanReduce;
+#if defined(_WIN32) || defined(__unix__)
+	char MultiAffect : 1;
+	char Garbage : 7;
+#else
+	_INT16 MultiAffect : 1;	// set to true if it affects more than one user
+    _INT16  Garbage : 7;
+#endif
+} PACKED;
+
+
+struct PACKED Language {
+	char Signature[30]; 		// "The Clans Language File v1.0"
+
+	unsigned _INT16 StrOffsets[2000];		// offsets for up to 1100 strings
+	unsigned _INT16 NumBytes;				// how big is the bigstring!?
+
+	char *BigString;		// All 500 strings jumbled together into
+								// one
+} PACKED;
+
+struct PACKED BuildingType {
+	char szName[30];
+	char HitZones,			// how vulnerable is it?  Higher = more vulnerable
+		 LandUsed,			// how many units of land used?
+		 EnergyUsed;		// how much energy is used to build it? 100=highest
+	long Cost;				// how much it'll cost ya to build this
+
+	/* in future:
+
+	__BOOL MultipleBuild; 	// FALSE == can only build one at a time
+	__BOOL BuildingPrerequisites[MAX_BUILDINGS];	// ???
+	*/
+
+} PACKED;
+
+
+struct PACKED Alliance {
+	_INT16 ID;
+	char szName[30];
+	_INT16 CreatorID[2];
+	_INT16 OriginalCreatorID[2];
+	_INT16 Member[MAX_ALLIANCEMEMBERS][2];
+
+  struct PACKED empire Empire;
+  struct PACKED item_data Items[MAX_ALLIANCEITEMS];
+} PACKED;
+
+
+
+
+// This struct should have just about EVERYTHING on the battle
+// who the attacker is, what his name is, what type of attacker, what his ID is
+// who the victim is, what type he is and his ID
+struct PACKED AttackResult {
+	__BOOL Success;					// was the attacker successful?
+	__BOOL NoTarget;					// set this if there was no ruler to oust
+									// or no clan to battle
+	__BOOL InterBBS;					// was this an InterBBS attack?
+
+	// starting info
+	struct PACKED Army OrigAttackArmy; 	// what troops he had originally
+	_INT16 AttackerType;				// what type of attacker he is
+	_INT16 AttackerID[2];				// ID of person doing the attacking
+	_INT16 AllianceID; 				// ID of alliance
+	char szAttackerName[25];		// name of attacker
+
+	// set beforehand
+	_INT16 DefenderType;				// what type of defender
+	_INT16 DefenderID[2];				// who is being attacked?
+
+	// set in InterBBS only
+	char szDefenderName[25];
+
+	_INT16 BBSIDFrom;					// which BBS was the attacker from?
+	_INT16 BBSIDTo;					// which BBS was the attack for?
+
+	// actual result of battle:
+	_INT16 PercentDamage;
+	_INT16 Goal;						// original goal of attack
+	_INT16 ExtentOfAttack;
+	struct PACKED Army AttackCasualties, DefendCasualties;
+	_INT16 BuildingsDestroyed[MAX_BUILDINGS];
+	long GoldStolen;
+	_INT16 LandStolen;
+
+	struct PACKED Army ReturningArmy;		// how many survived and are coming back?
+									// only used for IBBS
+	_INT16 ResultIndex;				// used to prevent cheating
+	_INT16 AttackIndex;				// used to delete attackpacket from backup.dat
+
+	long CRC;						// IBBS only
+} PACKED;
+
+
+struct PACKED Topic {
+	__BOOL Known; 				/* topic known yet? */
+	__BOOL Active;				/* does topic even exist? */
+	__BOOL ClanInfo;				/* if set to TRUE, means gives info on clan
+								   he is in */
+	char szName[70];			/* name of topic as seen by user */
+	char szFileName[25];		/* name of topic in file */
+} PACKED;
+
+
+struct PACKED NPCInfo {
+	char szName[20];
+	struct PACKED Topic Topics[MAX_TOPICS];
+	struct PACKED Topic IntroTopic;
+  __BOOL Garbage;
+  _INT16 Garbage2[2];
+	char Loyalty;		/* how loyal is he? */
+	_INT16 WhereWander;	// where does he wander most often?
+  _INT16 Garbage3;
+	__BOOL Roamer;		// is he a roamer type?
+	_INT16 NPCPCIndex; 	// which NPC is he in the NPC.PC file?
+	_INT16 KnownTopics;	// how many topics does he know?
+	_INT16 MaxTopics;		// how many topics we can discuss in one sitting
+	_INT16 OddsOfSeeing;	// good chance of seeing him or not
+	char szHereNews[70]; // news shown when guy shows up
+	// new additions
+	char szQuoteFile[13];	// what file to use for quotes?
+	char szMonFile[13]; 	// which .MON file is he in?
+	char szIndex[20];		// index of this NPC
+
+	_INT16 VillageType;		// which villages is this allowed in?  0 == ALL
+} PACKED;
+
+
+struct PACKED NPCNdx {
+	char szIndex[20];
+	__BOOL InClan;		/* in a clan yet? */
+	_INT16 ClanID[2];		/* if so, which clan? */
+  _INT16 WhereWander;    // where/what is he now?
+  _INT16 Status;         // where/what is he now?
+} PACKED;
+
+
+struct PACKED TradeList {
+	long Gold;
+	long Followers;
+	long Footmen, Axemen, Knights, Catapults;
+} PACKED;
+
+struct PACKED TradeData {
+	struct PACKED TradeList Giving;
+	struct PACKED TradeList Asking;
+	__BOOL Active;
+
+  _INT16 FromClanID[2], ToClanID[2];
+	char szFromClan[25];
+	long Code;
+} PACKED;
+
+
+struct PACKED Message {
+  _INT16 ToClanID[2], FromClanID[2];
+  char szFromName[25], szDate[11],
+       szAllyName[30], szFromVillageName[40];
+
+  _INT16 MessageType;                  // 0 == Public
+                                    // 1 == Private
+                                    // 2 == Alliance only
+  _INT16 AllianceID;                   // If MessageType == 2, this alliance
+                                    //    receives the message
+  _INT16 Flags;
+  _INT16 BBSIDFrom, BBSIDTo;
+
+  _INT16 PublicMsgIndex;               // Msg# for public posts
+
+  struct PACKED Msg_Txt {
+    _INT16 Offsets[40];
+    _INT16 Length, NumLines;
+    char *MsgTxt;
+  } Data;
+} PACKED;
+
+
+struct PACKED Packet {
+  __BOOL Active;
+
+  char GameID[16];
+  char szDate[11];
+  _INT16 BBSIDFrom, BBSIDTo;
+
+	_INT16 PacketType;
+  long PacketLength;
+} PACKED;
+
+
+struct PACKED AttackPacket {
+	_INT16 BBSFromID;			// from whence it came
+	_INT16 BBSToID;			// where it's going
+  struct PACKED empire AttackingEmpire;
+	struct PACKED Army AttackingArmy;	// army doing the attacking
+	_INT16 Goal;				// what is the goal of this attack?
+	_INT16 ExtentOfAttack; 	// level of attack
+	_INT16 TargetType; 		// needed to find out who he's attacking
+	_INT16 ClanID[2];			// if a clan he's attacking, this is its ID
+	_INT16 AttackOriginatorID[2];	  // clanid of who started the attack
+
+	_INT16 AttackIndex;
+	long CRC;
+} PACKED;
+
+struct PACKED SpyAttemptPacket {
+	char szSpierName[40];
+	_INT16 IntelligenceLevel;
+	_INT16 TargetType; 		// either a village or clan
+	_INT16 ClanID[2];			// who is the target
+	_INT16 MasterID[2];		// who sent it?
+
+	_INT16 BBSFromID;
+	_INT16 BBSToID;
+} PACKED;
+
+struct PACKED SpyResultPacket {
+	_INT16 BBSFromID;			// these are the same as spyattemptpacket
+	_INT16 BBSToID;
+	_INT16 MasterID[2];		// who sent it originally?
+	char szTargetName[35];	// who we're spying on
+
+	__BOOL Success;
+  struct PACKED empire Empire;   // unused if unsuccessful
+	char szTheDate[11];
+} PACKED;
+
+struct PACKED ibbs {
+  __BOOL Initialized;
+
+  struct PACKED ibbs_data {
+    _INT16 BBSID;
+
+    _INT16 NumNodes;
+
+    // Note, use IBBS.Nodes[x] where x corresponds to the BBSID
+    struct PACKED ibbs_node {
+      __BOOL Active;
+
+      struct PACKED ibbs_node_info {
+        char *pszBBSName;
+        char *pszVillageName;
+        char *pszAddress;
+        _INT16 RouteThrough;
+        _INT16 MailType;
+      } Info;
+
+      struct PACKED ibbs_node_reset {
+        _INT16 Received;           /* used only by main BBS */
+        long LastSent;          /* last attempt at sending a reset command */
+      } Reset;
+
+      struct PACKED ibbs_node_recon {
+        long LastReceived;      /* when last recon gotten was */
+        long LastSent;          /* last attempted recon */
+        char PacketIndex;
+      } Recon;
+
+      struct PACKED ibbs_node_attack {
+        _INT16 ReceiveIndex;
+        _INT16 SendIndex;
+      } Attack;
+
+    } Nodes[MAX_IBBSNODES];
+
+  } *Data;
+} PACKED;
+
+struct PACKED ResetData {
+  char GameID[16];
+  char szDateGameStart[11];
+  char szLastJoinDate[11];
+	char szVillageName[40];
+	__BOOL InterBBSGame;
+	__BOOL LeagueWide;
+	__BOOL InProgress;
+	__BOOL EliminationMode;
+
+	__BOOL ClanTravel;
+	_INT16 LostDays;
+	__BOOL ClanEmpires;
+	_INT16 MineFights, ClanFights;
+	_INT16 MaxPermanentMembers;		// up to 6
+	_INT16 DaysOfProtection;
+} PACKED;
+
+struct PACKED UserInfo {
+	_INT16 ClanID[2];
+	__BOOL Deleted;					// set for deletion during maintenance
+	char szMasterName[30];			// name of user who plays
+	char szName[30];				// name of clan itself
+} PACKED;
+
+struct PACKED UserScore {
+	_INT16 ClanID[2];
+	char Symbol[21];
+	char szName[30];
+	long Points;
+	_INT16 BBSID;
+} PACKED;
+
+struct PACKED LeavingData {
+	__BOOL Active;
+  _INT16 DestID;
+	_INT16 ClanID[2];
+
+	// how many troops to bring along with you
+	long Followers, Footmen, Axemen, Knights, Catapults;
+} PACKED;
+
diff --git a/src/doors/clans-src/system.c b/src/doors/clans-src/system.c
new file mode 100644
index 0000000000000000000000000000000000000000..c8711d4b802095032b76b6ec0595aefef98d70f0
--- /dev/null
+++ b/src/doors/clans-src/system.c
@@ -0,0 +1,797 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * System functions
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#include <sys/param.h>
+#else
+#ifndef _WIN32
+# include <alloc.h>
+# include <dos.h>
+#else
+# include <malloc.h>
+#endif
+#include <share.h>
+#endif
+
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "structs.h"
+#include "k_config.h"
+#include "k_comman.h"
+// #include "tasker.h"
+
+#include <OpenDoor.h>
+#include "parsing.h"
+#include "ibbs.h"
+#include "system.h"
+// #include "tslicer.h"
+#include "language.h"
+#include "door.h"
+#include "mstrings.h"
+#include "maint.h"
+#include "video.h"
+#include "spells.h"
+#include "village.h"
+#include "class.h"
+#include "game.h"
+#include "clansini.h"
+#include "tasker.h"
+#include "items.h"
+#include "quests.h"
+#include "news.h"
+#include "user.h"
+#include "reg.h"
+#include "scores.h"
+
+struct config *Config;
+struct system System;
+extern struct Language *Language;
+extern struct IniFile IniFile;
+extern struct ibbs IBBS;
+extern struct game Game;
+BOOL Verbose = FALSE;
+
+// ------------------------------------------------------------------------- //
+  BOOL System_LockedOut ( void )
+  {
+    FILE *fp;
+    char szLine[128], *pcCurrentPos;
+
+    // read in file
+    fp = fopen("lockout.txt", "r");
+    if (!fp)
+      return FALSE;
+
+    // while not end of file
+    for (;;)
+    {
+      // read in line
+      if (fgets(szLine, 128, fp) == NULL) break;
+
+      /* Ignore all of line after comments or CR/LF char */
+      pcCurrentPos=(char *)szLine;
+
+      ParseLine(pcCurrentPos);
+
+      /* If no token was found, proceed to process the next line */
+      if(!*pcCurrentPos) continue;
+
+
+      // else, compare names
+      if (stricmp(pcCurrentPos, od_control.user_name) == 0)
+      {
+        fclose(fp);
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void System_Error ( char *szErrorMsg )
+    /*
+     * purpose  To output an error message and close down the system.
+     *          This SHOULD be run from anywhere and NOT fail.  It should
+     *          be FOOLPROOF.
+     */
+  {
+#ifdef __unix__
+	printf("System Error: %s\n",szErrorMsg);
+    delay(1000);
+    System_Close();
+#elif defined(_WIN32)
+	char buffer[1000];
+	_snprintf (buffer, 1000, "System Error: %s\n", szErrorMsg);
+	MessageBox (NULL, buffer, TEXT("System Error"), MB_OK |
+		        MB_ICONERROR);
+	System_Close();
+#else
+    DisplayStr("|12System Error: |07");
+    DisplayStr(szErrorMsg);
+    delay(1000);
+    System_Close();
+#endif
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Config_Init ( void )
+    /*
+     * Loads data from .CFG file into Config->
+     *
+     */
+  {
+    FILE *fpConfigFile;
+    char szConfigName[40], szConfigLine[255];
+    char *pcCurrentPos;
+    char szToken[MAX_TOKEN_CHARS + 1];
+    _INT16 iKeyWord, iCurrentNode = 1;
+
+    if (Verbose)
+    {
+      DisplayStr("> Config_Init()\n");
+      delay(500);
+    }
+
+    Config = malloc(sizeof(struct config));
+    CheckMem(Config);
+
+    // --- Set defaults
+    strcpy(szConfigName, "clans.cfg");
+    Config->szSysopName[0] = 0;
+    Config->szBBSName[0] = 0;
+    strcpy(Config->szScoreFile[0], "scores.asc");
+    strcpy(Config->szScoreFile[1], "scores.ans");
+    Config->szRegcode[0] = 0;
+    Config->BBSID = 0;
+
+    System.InterBBS = FALSE;
+    Config->InterBBS = FALSE;
+
+    fpConfigFile = _fsopen(szConfigName, "rt", SH_DENYWR);
+    if (!fpConfigFile)
+    {
+      /* file not found! error */
+      System_Error("Config file not found\n");
+    }
+
+    for (;;)
+    {
+      /* read in a line */
+      if (fgets(szConfigLine, 255, fpConfigFile) == NULL) break;
+
+      /* Ignore all of line after comments or CR/LF char */
+      pcCurrentPos=(char *)szConfigLine;
+      ParseLine(pcCurrentPos);
+
+      /* If no token was found, proceed to process the next line */
+      if(!*pcCurrentPos) continue;
+
+      GetToken(pcCurrentPos, szToken);
+
+      /* Loop through list of keywords */
+      for(iKeyWord = 0; iKeyWord < MAX_CONFIG_WORDS; ++iKeyWord)
+      {
+        /* If keyword matches */
+        if(stricmp(szToken, papszConfigKeyWords[iKeyWord]) == 0)
+        {
+          /* Process config token */
+          switch (iKeyWord)
+          {
+            case 0 :  /* sysopname */
+              strcpy(Config->szSysopName, pcCurrentPos);
+              break;
+            case 1 :  /* bbsname */
+              strcpy(Config->szBBSName, pcCurrentPos);
+              break;
+            case 2 :  /* use log? */
+              if (stricmp(pcCurrentPos, "Yes") == 0)
+              {
+                /* use log */
+                od_control.od_logfile = INCLUDE_LOGFILE;
+                sprintf(od_control.od_logfile_name, "clans%d.log", System.Node);
+              }
+              break;
+            case 3 :  /* ansi file */
+              strcpy(Config->szScoreFile[1], pcCurrentPos);
+              break;
+            case 4 :  /* ascii file */
+              strcpy(Config->szScoreFile[0], pcCurrentPos);
+              break;
+            case 5 :  /* node = ? */
+              iCurrentNode = atoi(pcCurrentPos);
+              break;
+            case 6 :  /* dropdirectory = ? */
+              if (System.Node == iCurrentNode)
+              {
+                strcpy(od_control.info_path, pcCurrentPos);
+              }
+              break;
+            case 7 :  /* usefossil */
+              if (System.Node == iCurrentNode)
+              {
+                if (stricmp(pcCurrentPos, "No") == 0)
+                {
+                  /* do not use fossil */
+                  od_control.od_no_fossil = TRUE;
+                }
+              }
+              break;
+            case 8 :  /* serial port addr */
+              if (System.Node == iCurrentNode)
+              {
+                //printf("Not yet used\n");
+              }
+              break;
+            case 9 :  /* serial port irq */
+              if (System.Node == iCurrentNode)
+              {
+                if (stricmp(pcCurrentPos, "Default") != 0)
+                  od_control.od_com_irq = atoi(pcCurrentPos);
+              }
+              break;
+            case 10 : /* BBS Id */
+              Config->BBSID = atoi(pcCurrentPos);
+              break;
+            case 11 : /* netmail dir */
+              strcpy(Config->szNetmailDir, pcCurrentPos);
+
+              /* remove '\' if last char is it */
+              if (Config->szNetmailDir [ strlen(Config->szNetmailDir) - 1] == '\\' || Config->szNetmailDir [strlen(Config->szNetmailDir) - 1] == '/')
+                Config->szNetmailDir [ strlen(Config->szNetmailDir) - 1] = 0;
+              break;
+            case 12 : /* inbound dir */
+              strcpy(Config->szInboundDir, pcCurrentPos);
+
+              /* add '\' if last char is not it */
+              if ( Config->szInboundDir [ strlen(Config->szInboundDir) - 1] != '\\' &&  Config->szInboundDir [strlen(Config->szInboundDir) - 1] != '/')
+                strcat(Config->szInboundDir, "/");
+              break;
+            case 13 : /* mailer type */
+              if (stricmp(pcCurrentPos, "BINKLEY") == 0)
+                Config->MailerType = MAIL_BINKLEY;
+              else
+                Config->MailerType = MAIL_OTHER;
+              break;
+            case 14 : /* in a league? */
+              System.InterBBS = TRUE;
+              Config->InterBBS = TRUE;
+              break;
+            case 15 : /* regcode */
+              if (*pcCurrentPos)
+                strcpy(Config->szRegcode, pcCurrentPos);
+              break;
+          }
+        }
+      }
+    }
+
+    fclose(fpConfigFile);
+
+  }
+
+  void Config_Close ( void )
+    /*
+     * Shuts down config's mem.
+     *
+     */
+  {
+    free(Config);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void ShowHelp ( void )
+    /*
+     * Shows help screen for /? and /Help
+     *
+     */
+  {
+    // help info using help parameter
+    zputs(ST_HELPPARM);
+  }
+
+#if defined(__unix__)
+char * fullpath(char *target, const char *path, size_t size)  {
+	char	*out;
+	char	*p;
+	
+	if(target==NULL)  {
+		if((target=malloc(PATH_MAX+1))==NULL) {
+			return(NULL);
+		}
+	}
+	out=target;
+	*out=0;
+
+	if(*path != '/')  {
+		p=getcwd(target,size);
+		if(p==NULL || strlen(p)+strlen(path)>=size)
+			return(NULL);
+		out=strrchr(target,'\0');
+		*(out++)='/';
+		*out=0;
+		out--;
+	}
+	strncat(target,path,size-1);
+	
+/*	if(stat(target,&sb))
+		return(NULL);
+	if(sb.st_mode&S_IFDIR)
+		strcat(target,"/"); */
+
+	for(;*out;out++)  {
+		while(*out=='/')  {
+			if(*(out+1)=='/')
+				memmove(out,out+1,strlen(out));
+			else if(*(out+1)=='.' && (*(out+2)=='/' || *(out+2)==0))
+				memmove(out,out+2,strlen(out)-1);
+			else if(*(out+1)=='.' && *(out+2)=='.' && (*(out+3)=='/' || *(out+3)==0))  {
+				*out=0;
+				p=strrchr(target,'/');
+				memmove(p,out+3,strlen(out+3)+1);
+				out=p;
+			}
+			else  {
+				out++;
+			}
+		}
+	}
+	return(target);
+}
+#endif
+
+  void PrimitiveCommandLine ( void )
+    /*
+     * Deals with basic command lines (i.e. those which do not depend on the
+     * game being loaded yet).
+     */
+  {
+    _INT16 cTemp, iKeyWord;
+    BOOL FoundMatch;
+    char *szHelp = "|02Invalid parameter -- |07type |10CLANS /? |07for help\n";
+
+    /* This function will parse the command line by looking for the  */
+    /* flags and stuff!                        */
+
+    for (cTemp = 1; cTemp < _argc; cTemp++)
+    {
+      if (_argv[cTemp][0] == '-' || _argv[cTemp][0] == '/')
+      {
+        FoundMatch = FALSE;
+
+        /* Loop through list of keywords */
+        for(iKeyWord = 0; iKeyWord < MAX_COMLINE_WORDS; ++iKeyWord)
+        {
+          /* If keyword matches */
+          if(stricmp(&_argv[cTemp][1], papszComLineKeyWords[iKeyWord]) == 0 ||
+		  		( _argv[cTemp][1] == 'D' && papszComLineKeyWords[iKeyWord][0] == 'D'))
+          {
+            FoundMatch = TRUE;
+
+            /* Process token */
+            switch (iKeyWord)
+            {
+              case 3 : /* ? */
+              case 4 : /* Help */
+                ShowHelp();
+				delay(3000);
+				exit(0);
+/*                System_Close(); */
+                break;
+              case 7 :  /* LIBBS */
+                System.LocalIBBS = TRUE;
+                break;
+              case 11 : /* Recon */
+                cTemp++;
+                break;
+              case 12 : /* SendReset */
+                cTemp++;
+                break;
+              case 13 : /* Reset */
+                System_Error("To reset the game, please run RESET.EXE.\n");
+                break;
+              case 14 : /* Verbose */
+                DisplayStr("|07Verbose |14ON\n");
+                Verbose = TRUE;
+                break;
+			case 15 :  /* D */
+				strcpy(od_control.info_path, &_argv[cTemp][2]);
+              break;
+
+            }
+          }
+        }
+        if (FoundMatch == FALSE)
+        {
+          if (toupper(_argv[cTemp][1]) - 'A' == 18 && stricmp(&_argv[cTemp][2], "lop") == 0)
+          {
+            Register();
+            System_Close();
+          }
+          else if (toupper(_argv[cTemp][1]) == 'N' || toupper(_argv[cTemp][1]) == 'D')
+            System.Node = atoi(&_argv[cTemp][2]);
+
+	  // 12/23/2001 [au] dropped time-slicer code
+	  /*
+          else if (toupper(_argv[cTemp][1]) == 'T')
+          {
+            TSlicer_Init();
+
+            if (_argv[cTemp][2])
+              TSlicer_SetPoll(atoi(&_argv[cTemp][2]));
+          }
+	  */
+
+          else
+          {
+            zputs(szHelp);
+            System_Close();
+          }
+        }
+      }
+      else
+      {
+        zputs(szHelp);
+		delay(3000);
+        exit(0);
+      }
+    }
+
+  }
+
+// ------------------------------------------------------------------------- //
+
+
+  /* Parses commands used to load game */
+  void ParseCommands( void )
+    /*
+     * Deals with Command-Line Parms which DO require game to be loaded and
+     * initialized.
+     */
+  {
+    _INT16 cTemp, iKeyWord;
+    char szString[128];
+
+    /* This function will parse the command line by looking for the  */
+    /* flags and stuff!                        */
+
+    for (cTemp = 1; cTemp < _argc; cTemp++)
+    {
+      if (_argv[cTemp][0] == '-' || _argv[cTemp][0] == '/')
+      {
+        /* Loop through list of keywords */
+        for(iKeyWord = 0; iKeyWord < MAX_COMLINE_WORDS; ++iKeyWord)
+        {
+          /* If keyword matches */
+          if(stricmp(&_argv[cTemp][1], papszComLineKeyWords[iKeyWord]) == 0)
+          {
+            /* Process token */
+            switch (iKeyWord)
+            {
+              case 0  : /* L */
+              case 1  : /* Local */
+                System.Local = TRUE;
+                break;
+              case 2  : /* M */
+                Maintenance();
+                System_Close();
+                break;
+              case 7 :  /* LIBBS */
+                if (Game.Data->InterBBS == FALSE)
+                  System_Error(ST_IBBSONLY);
+                break;
+              case 8 :  /* Users */
+                User_List();
+                System_Close();
+                break;
+              case 9 :  /* NewNDX */
+                if (Game.Data->InterBBS)
+                {
+                  if (IBBS.Data->BBSID != 1)
+                  {
+                    System_Error("Only the League Coordinator can update the world.ndx file.\n");
+                  }
+
+                  IBBS_DistributeNDX();
+                  System_Close();
+                }
+                else
+                  System_Error(ST_IBBSONLY);
+                break;
+              case 10 : /* I */
+                // read in packets waiting
+                IBBS_PacketIn();
+
+                if (Game.Data->InterBBS == FALSE)
+                  System_Error(ST_IBBSONLY);
+                else
+                  System_Close();
+                break;
+              case 11 : /* Recon */
+                cTemp++;
+                if (Game.Data->InterBBS)
+                {
+                  if (IBBS.Data->BBSID != atoi(_argv[cTemp]) &&
+                     (atoi(_argv[cTemp]) > 0 && atoi(_argv[cTemp]) < MAX_IBBSNODES))
+                  {
+                    sprintf(szString, "Sending recon to %d\n", atoi(_argv[cTemp]));
+                    DisplayStr(szString);
+                    IBBS_SendRecon(atoi(_argv[cTemp]));
+                  }
+                  System_Close();
+                }
+                else
+                  System_Error(ST_IBBSONLY);
+                break;
+              case 12 : /* SendReset */
+                cTemp++;
+                if (Game.Data->InterBBS)
+                {
+                  if (IBBS.Data->BBSID != 1)
+                  {
+                    System_Error("Only the League Coordinator can send a reset.\n");
+                  }
+
+                  /* sprintf(szString, "trying to send reset to %d\n", atoi(_argv[cTemp]));
+                  DisplayStr(szString);
+                  */
+
+                  if (IBBS.Data->BBSID != atoi(_argv[cTemp]) &&
+                     (atoi(_argv[cTemp]) > 0 && atoi(_argv[cTemp]) < MAX_IBBSNODES))
+                  {
+                    sprintf(szString, "Sending reset to %d\n", atoi(_argv[cTemp]));
+                    DisplayStr(szString);
+                    IBBS_SendReset(atoi(_argv[cTemp]));
+                  }
+                  System_Close();
+                }
+                else
+                  System_Error(ST_IBBSONLY);
+                break;
+            }
+          }
+        }
+      }
+      else
+      {
+        zputs("|06Invalid parameter -- |07type |14CLANS /? |07for help\n");
+        System_Close();
+      }
+    }
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void System_Maint ( void )
+  {
+
+    DisplayStr("* System_Maint()\n");
+
+    // Update News
+    unlink("yest.asc");
+    rename("today.asc", "yest.asc");
+    News_CreateTodayNews();
+
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void System_Close ( void )
+    /*
+     * purpose  Closes down the system, no matter WHERE it is called.
+     *          Should be foolproof.
+     */
+  {
+    if (System.Initialized)
+    {
+      // This simply ensures this function is run ONLY ONCE!
+      System.Initialized = FALSE;
+
+//#ifdef _DEBUG
+//# define TRACEX(x) MessageBox (NULL, (x), TEXT("DEBUG"), MB_OK)
+//#else
+# define TRACEX(x)
+//#endif
+
+	  TRACEX("DisplayScores");
+      DisplayScores(TRUE);
+
+	  TRACEX("Items_Close()");
+      Items_Close();
+
+	  TRACEX("User_Close()");
+      User_Close();
+
+	  TRACEX("Quests_Close()");
+      Quests_Close();
+	  TRACEX("PClass_Close()");
+      PClass_Close();
+	  TRACEX("Spells_Close()");
+      Spells_Close();
+
+#ifdef PRELAB
+      printf("post data -- mem left = %lu\n", farcoreleft());
+#endif
+
+	  TRACEX("Door_Close()");
+      Door_Close();
+
+	  TRACEX("Village_Close()");
+      Village_Close();
+	  TRACEX("Game_Close()");
+      Game_Close();
+
+	  TRACEX("IBBS_Close()");
+      if (System.InterBBS)
+        IBBS_Close();
+
+	  TRACEX("Config_Close()");
+      Config_Close();
+
+	  TRACEX("ClansIni_Close()");
+      ClansIni_Close();
+
+	  TRACEX("Language_Close()");
+      Language_Close();
+
+#ifdef PRELAB
+      printf("Clans End   -- mem left = %lu\n", farcoreleft());
+#endif
+
+	  TRACEX("Door_Initialized()");
+      if (Door_Initialized())
+      {
+        od_exit(0, FALSE);
+      }
+      else
+      {
+        exit(0);
+      }
+    }
+  }
+
+  void System_Init ( void )
+    /*
+     * Initializes whole system.
+     */
+  {
+#ifndef _WIN32
+    struct date date;
+#else
+	SYSTEMTIME system_time;
+#endif
+    _INT16 iTemp;
+#ifdef __unix__
+	char *pszResolvedPath;
+#endif
+
+    System.Initialized = TRUE;
+    System.LocalIBBS = FALSE;
+
+	// Get directory from commandline
+    strcpy(System.szMainDir, _argv[0]);
+    for (iTemp = strlen(_argv[0]); iTemp > 0; iTemp--)
+    {
+      if (_argv[0][iTemp] == '\\' || _argv[0][iTemp] == '/' )
+        break;
+    }
+    ++iTemp;
+    System.szMainDir[iTemp] = 0;
+#ifdef __unix__
+	pszResolvedPath=fullpath(NULL,System.szMainDir,sizeof(System.szMainDir));
+	strcpy(System.szMainDir,pszResolvedPath);
+	free(pszResolvedPath);
+#endif
+
+#ifdef PRELAB
+    printf("Clans Start -- mem left = %lu\n", farcoreleft());
+#endif
+
+    // 12/23/2001 [au] getting rid of time-slicer support
+    // Time slicer init
+    // get_os();
+
+    // initialize date
+#ifndef _WIN32
+    getdate(&date);
+    sprintf(System.szTodaysDate, "%02d/%02d/%4d", date.da_mon, date.da_day, date.da_year);
+#else
+	GetSystemTime(&system_time);
+	sprintf(System.szTodaysDate, "%02d/%02d/%4d", system_time.wMonth, system_time.wDay, system_time.wYear);
+#endif
+
+#ifndef _WIN32
+        randomize();
+#else
+	srand((unsigned)time(NULL));
+#endif
+
+    // initialize screen data
+    Video_Init();
+
+    DisplayStr("|14The Clans |15" VERSION " |07copyright 1997-1998 Allen Ussher\n\n");
+
+    ClansIni_Init();
+
+    Language_Init(IniFile.pszLanguage);
+
+    PrimitiveCommandLine();
+
+    Config_Init();
+
+    // init stuff
+    System.Local = FALSE;
+
+    // Game Specific data (village, game.dat)
+    Game_Init();
+
+    Village_Init();
+
+    if (Game.Data->InterBBS)
+    {
+      IBBS_Init();
+
+      // update recons + resets
+      IBBS_UpdateRecon();
+
+      if (IBBS.Data->BBSID == 1)
+        IBBS_UpdateReset();
+    }
+
+    // parse command line here
+    if (_argc > 1)
+      ParseCommands();
+
+    Door_Init(System.Local);
+
+    if (System_LockedOut())
+    {
+			rputs("Sorry, you have been locked out of this door.\n%P");
+      od_exit(0, FALSE);
+    }
+
+
+#ifdef PRELAB
+    printf("pre data -- mem left = %lu\n", farcoreleft());
+#endif
+
+    // Clans specific data is loaded here (spells)
+    Spells_Init();
+    PClass_Init();
+
+    Quests_Init();
+
+    // read in packets waiting
+    if (System.InterBBS)
+      IBBS_PacketIn();
+  }
diff --git a/src/doors/clans-src/system.h b/src/doors/clans-src/system.h
new file mode 100644
index 0000000000000000000000000000000000000000..ebc633d424fa58386daa44d74fe483647afa8e24
--- /dev/null
+++ b/src/doors/clans-src/system.h
@@ -0,0 +1,25 @@
+/*
+ * System functions
+ */
+
+  void System_Init ( void );
+    /*
+     * Initializes whole system.
+     */
+
+  void System_Close ( void );
+    /*
+     * purpose  Closes down the system, no matter WHERE it is called.
+     *          Should be foolproof.
+     */
+
+  void System_Error ( char *szErrorMsg );
+    /*
+     * purpose  To output an error message and close down the system.
+     *          This SHOULD be run from anywhere and NOT fail.  It should
+     *          be FOOLPROOF.
+     */
+
+  void System_Maint ( void );
+
+  void Config_Init ( void );
diff --git a/src/doors/clans-src/systemf.h b/src/doors/clans-src/systemf.h
new file mode 100644
index 0000000000000000000000000000000000000000..6214f06788c8108c95ca3f0c9b6d12487aa2143c
--- /dev/null
+++ b/src/doors/clans-src/systemf.h
@@ -0,0 +1,16 @@
+/*
+ * System functions
+ */
+
+  char far *vid_address ( void );
+    /*
+     *
+     */
+
+  void SystemInit ( void );
+    /*
+     * purpose  Initializes video system, config, ini, etc.
+     *
+     * post
+     *
+     */
diff --git a/src/doors/clans-src/tasker.h b/src/doors/clans-src/tasker.h
new file mode 100644
index 0000000000000000000000000000000000000000..fa753d7003c9f9f03eb30dfddcea3ba08e3640a5
--- /dev/null
+++ b/src/doors/clans-src/tasker.h
@@ -0,0 +1,44 @@
+/*
+**  Tasker.H
+**
+**  public domain by David Gibbs
+*/
+
+#ifndef DG_TASKER
+#define DG_TASKER
+
+struct PACKED ts_os_ver {
+      _INT16 maj;
+      _INT16 min;
+};
+
+#define TOT_OS  5
+
+#define DOS     0
+#define OS2     1
+#define DV      2
+#define WINS    3
+#define WIN3    4
+
+                        /*   76543210  */
+#define is_DOS  0x01    /* b'00000001' */
+#define is_OS2  0x02    /* b'00000010' */
+#define is_DV   0x04    /* b'00000100' */
+#define is_WINS 0x08    /* b'00001000' */
+#define is_WIN3 0x10    /* b'00010000' */
+
+
+extern _INT16 t_os_type;
+extern _INT16 t_os;
+
+extern const char *t_os_name[TOT_OS];
+
+extern struct PACKED ts_os_ver t_os_ver[TOT_OS];
+
+
+/* Function prototypes */
+
+_INT16 get_os();
+void t_slice();
+
+#endif /* DG_TASKER */
diff --git a/src/doors/clans-src/tmp.fil b/src/doors/clans-src/tmp.fil
new file mode 100644
index 0000000000000000000000000000000000000000..075eb0e247d1795e08b8368370a2f6583eb8db86
--- /dev/null
+++ b/src/doors/clans-src/tmp.fil
@@ -0,0 +1,49 @@
+
+The volume label in drive I is ARCHIVE.
+The Volume Serial Number is 271A:A015.
+Directory of I:\CLANPROG\CLEAN
+
+ALLIANCE C       25548   6-24-98  9:51p
+CLANS    C        5823   6-24-98  9:51p
+CLANSINI C        6045   6-24-98  9:51p
+CLASS    C        2932   6-24-98  9:51p
+CRC      C         358   6-24-98  9:51p
+DOOR     C       22819   6-24-98  9:51p
+EMPIRE   C      114250   6-24-98  9:51p
+EVENT    C        3678   6-24-98  9:51p
+FIGHT    C       62074   6-24-98  9:51p
+GAME     C        3995   6-24-98  9:51p
+HELP     C        7097   6-24-98  9:51p
+IBBS     C       96721   6-24-98 10:03p
+INPUT    C       16495   6-24-98  9:51p
+ITEMS    C       27920   6-24-98  9:51p
+LANGUAGE C        2995   6-24-98  9:51p
+MAIL     C       49729   6-24-98  9:51p
+MAINT    C        1885   6-24-98  9:51p
+MARKET   C       11503   6-24-98  9:51p
+MCOMP    C        7697   6-24-98  9:51p
+MENUS    C       33881   6-24-98  9:55p
+MENUS2   C       14259   6-24-98  9:51p
+MISC     C        1590   6-24-98  9:51p
+MYIBBS   C       19300   6-24-98  9:51p
+MYOPEN   C        4773   6-24-98  9:51p
+NEWS     C        2582   6-24-98  9:51p
+NPC      C       16454   6-24-98  9:51p
+PARSING  C        5026   6-24-98  9:51p
+PAWN     C       12239   6-24-98  9:51p
+PCEDIT   C       22473   6-24-98  9:51p
+QUESTS   C       43157   6-24-98  9:51p
+REG      C       10578   6-24-98  9:51p
+RESET    C        5010   6-24-98  9:51p
+RESET2   C       38710   6-24-98  9:51p
+SCORES   C       26759   6-28-98  7:08p
+SPELLS   C       23422   6-24-98  9:51p
+SYSTEM   C       17323   6-24-98  9:51p
+TRADES   C       18289   6-24-98  9:51p
+TSLICER  C         782   6-24-98  9:51p
+USER     C       92352   3-14-99  6:53p
+VIDEO    C       11918   6-24-98  9:51p
+VILLAGE  C       44794   6-24-98  9:51p
+VOTING   C        9593   6-24-98  9:51p
+      42 file(s)     944828 bytes used
+                    8724480 bytes free
diff --git a/src/doors/clans-src/tmp2.fil b/src/doors/clans-src/tmp2.fil
new file mode 100644
index 0000000000000000000000000000000000000000..fa323a4839dad373a25639b5cf99746c0203cb78
--- /dev/null
+++ b/src/doors/clans-src/tmp2.fil
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        $(CC) $(FLAGS) -c alliance.c
+        $(CC) $(FLAGS) -c clans.c
+        $(CC) $(FLAGS) -c clansini.c
+        $(CC) $(FLAGS) -c class.c
+        $(CC) $(FLAGS) -c crc.c
+        $(CC) $(FLAGS) -c door.c
+        $(CC) $(FLAGS) -c empire.c
+        $(CC) $(FLAGS) -c fight.c
+        $(CC) $(FLAGS) -c game.c
+        $(CC) $(FLAGS) -c help.c
+        $(CC) $(FLAGS) -c ibbs.c
+        $(CC) $(FLAGS) -c input.c
+        $(CC) $(FLAGS) -c items.c
+        $(CC) $(FLAGS) -c language.c
+        $(CC) $(FLAGS) -c mail.c
+        $(CC) $(FLAGS) -c maint.c
+        $(CC) $(FLAGS) -c menus.c
+        $(CC) $(FLAGS) -c menus2.c
+        $(CC) $(FLAGS) -c misc.c
+        $(CC) $(FLAGS) -c myibbs.c
+        $(CC) $(FLAGS) -c myopen.c
+        $(CC) $(FLAGS) -c news.c
+        $(CC) $(FLAGS) -c npc.c
+        $(CC) $(FLAGS) -c parsing.c
+        $(CC) $(FLAGS) -c pawn.c
+        $(CC) $(FLAGS) -c quests.c
+        $(CC) $(FLAGS) -c reg.c
+        $(CC) $(FLAGS) -c scores.c
+        $(CC) $(FLAGS) -c spells.c
+        $(CC) $(FLAGS) -c system.c
+        $(CC) $(FLAGS) -c tasker.c
+        $(CC) $(FLAGS) -c trades.c
+        $(CC) $(FLAGS) -c tslicer.c
+        $(CC) $(FLAGS) -c user.c
+        $(CC) $(FLAGS) -c video.c
+        $(CC) $(FLAGS) -c village.c
+        $(CC) $(FLAGS) -c voting.c
+        $(CC) $(FLAGS) @comp.lst
+        crc.obj items.obj mail.obj fight.obj scores.obj pawn.obj reg.obj\
+        door.obj village.obj input.obj help.obj game.obj user.obj\
+        misc.obj maint.obj spells.obj clansini.obj class.obj menus.obj\
+        npc.obj quests.obj news.obj empire.obj alliance.obj menus2.obj\
+        parsing.obj ibbs.obj tslicer.obj myopen.obj language.obj\
+        voting.obj trades.obj myibbs.obj
+all: clans.exe
+alliance.obj: alliance.c alliance.h
+CC = tcc
+clans.exe:      $(OBJS)
+clans.obj:      clans.c
+clansini.obj:   clansini.c
+class.obj:      class.c
+crc.obj:        crc.c
+door.obj:       door.c
+empire.obj:     empire.c
+fight.obj:      fight.c
+FLAGS = -ml -wall -C
+game.obj:       game.c
+help.obj:       help.c
+ibbs.obj:       ibbs.c
+input.obj:      input.c
+items.obj:      items.c
+language.obj:   language.c
+mail.obj:       mail.c
+maint.obj:      maint.c
+menus.obj:      menus.c
+menus2.obj:     menus2.c
+misc.obj:       misc.c
+myibbs.obj:     myibbs.c
+myopen.obj:     myopen.c
+news.obj:       news.c
+npc.obj:        npc.c
+OBJS = clans.obj video.obj system.obj\
+parsing.obj:    parsing.c
+pawn.obj:       pawn.c
+quests.obj:     quests.c
+reg.obj:        reg.c
+scores.obj:     scores.c
+spells.obj:     spells.c
+system.obj:     system.c
+tasker.obj:     tasker.c
+trades.obj:     trades.c
+tslicer.obj:    tslicer.c
+user.obj:       user.c
+video.obj:      video.c
+village.obj:    village.c
+voting.obj:     voting.c
diff --git a/src/doors/clans-src/trades.c b/src/doors/clans-src/trades.c
new file mode 100644
index 0000000000000000000000000000000000000000..37752f58fcf5554f952935ebab609fc3e588bec7
--- /dev/null
+++ b/src/doors/clans-src/trades.c
@@ -0,0 +1,593 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#ifdef __unix__
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+#include <string.h>
+
+
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "myopen.h"
+#include "user.h"
+#include "door.h"
+#include "input.h"
+#include "mail.h"
+#include "fight.h"
+
+extern struct clan *PClan;
+extern struct Language *Language;
+
+
+  void GetTradeList ( struct TradeList *TradeList, BOOL GivingList, char *szTitle )
+  {
+    /* enter choices */
+    /* keep looping till chooses "Done" */
+
+    _INT16 /*iTemp, WhichOne,*/ Choice;
+    long MaxInput;
+    char szString[128];
+    BOOL Done = FALSE;
+    char *szTheOptions[7] = {"Gold",
+                             "Followers",
+                             "Footmen",
+                             "Axemen",
+                             "Knights",
+                             "View Stats",
+                             "Quit" };
+
+    while (!Done)
+    {
+      rputs(szTitle);
+      rputs(ST_LONGLINE);
+
+      /* list 'em */
+      sprintf(szString, " |0A(|0B1|0A) |0CGold         |15%ld\n", TradeList->Gold);
+      rputs(szString);
+      sprintf(szString, " |0A(|0B2|0A) |0CFollowers    |15%ld\n", TradeList->Followers);
+      rputs(szString);
+      sprintf(szString, " |0A(|0B3|0A) |0CFootmen      |15%ld\n", TradeList->Footmen);
+      rputs(szString);
+      sprintf(szString, " |0A(|0B4|0A) |0CAxemen       |15%ld\n", TradeList->Axemen);
+      rputs(szString);
+      sprintf(szString, " |0A(|0B5|0A) |0CKnights      |15%ld\n", TradeList->Knights);
+      rputs(szString);
+
+      rputs(" |0A(|0BV|0A) |0CView Stats\n");
+      rputs(" |0A(|0B0|0A) |0CDone\n");
+      rputs(ST_LONGLINE);
+
+      switch(Choice = GetChoice("", ST_ENTEROPTION, szTheOptions, "12345V0", '0', TRUE))
+      {
+        case '1' :  /* gold */
+          if (GivingList)
+            MaxInput = PClan->Empire.VaultGold;
+          else
+            MaxInput = 1000000000L;
+
+          TradeList->Gold = GetLong("|0SHow much gold?", TradeList->Gold, MaxInput);
+          break;
+        case '2' :  /* followers */
+          if (GivingList)
+            MaxInput = PClan->Empire.Army.Followers;
+          else
+            MaxInput = 1000000L;
+
+          TradeList->Followers = GetLong("|0SHow many followers?", TradeList->Followers, MaxInput);
+          break;
+        case '3' :  /* footmen */
+          if (GivingList)
+            MaxInput = PClan->Empire.Army.Footmen;
+          else
+            MaxInput = 1000000L;
+
+          TradeList->Footmen = GetLong("|0SHow many footmen?", TradeList->Footmen, MaxInput);
+          break;
+        case '4' :  /* axemen */
+          if (GivingList)
+            MaxInput = PClan->Empire.Army.Axemen;
+          else
+            MaxInput = 1000000L;
+
+          TradeList->Axemen = GetLong("|0SHow many axemen?", TradeList->Axemen, MaxInput);
+          break;
+        case '5' :  /* knights */
+          if (GivingList)
+            MaxInput = PClan->Empire.Army.Knights;
+          else
+            MaxInput = 1000000L;
+
+          TradeList->Knights = GetLong("|0SHow many knights?", TradeList->Knights, MaxInput);
+          break;
+        case '0' :  /* done */
+          Done = TRUE;
+          break;
+        case 'V' :  /* view stats */
+          ClanStats(PClan, TRUE);
+          break;
+      }
+    }
+  }
+
+  void RejectTrade ( struct TradeData *TradeData )
+  {
+    struct clan *TmpClan;
+    char *szString;
+
+    TradeData->Active = FALSE;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    szString = MakeStr(255);
+
+    GetClan(TradeData->FromClanID, TmpClan);
+
+    TmpClan->Empire.VaultGold += TradeData->Giving.Gold;
+    TmpClan->Empire.Army.Followers += TradeData->Giving.Followers;
+    TmpClan->Empire.Army.Footmen += TradeData->Giving.Footmen;
+    TmpClan->Empire.Army.Axemen += TradeData->Giving.Axemen;
+    TmpClan->Empire.Army.Knights += TradeData->Giving.Knights;
+
+    /* this ensures the file is zeroed for cheaters -- improve later */
+    TradeData->Giving.Gold = 0L;
+    TradeData->Giving.Followers = 0L;
+    TradeData->Giving.Footmen = 0L;
+    TradeData->Giving.Axemen = 0L;
+    TradeData->Giving.Knights = 0L;
+    TradeData->Giving.Catapults = 0L;
+
+    sprintf(szString, "%s rejected your trade offer.", PClan->szName);
+    GenericMessage(szString, TradeData->FromClanID, PClan->ClanID, PClan->szName, FALSE);
+
+    Clan_Update(TmpClan);
+
+    FreeClan(TmpClan);
+    free(szString);
+  }
+
+
+  void Trades_CheckTrades ( void )
+  {
+    FILE *fpTradeFile;
+    long OldOffset;
+    struct clan *TmpClan;
+    _INT16 CurTradeData;
+    struct TradeData TradeData;
+    char szString[255];
+
+    fpTradeFile = fopen("trades.dat", "r+b");
+
+    if (fpTradeFile == NULL)
+      return;
+
+    for (CurTradeData = 0;;CurTradeData++)
+    {
+      if (fseek(fpTradeFile, (long)(CurTradeData * sizeof(struct TradeData)), SEEK_SET))
+        break;
+
+      OldOffset = ftell(fpTradeFile);
+
+      if (EncryptRead(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE) == 0)
+        break;
+
+      /* see if active */
+      if (TradeData.Active == FALSE)
+        continue;
+
+      /* if so, see if for this dude */
+      if (TradeData.ToClanID[0] != PClan->ClanID[0] ||
+        TradeData.ToClanID[1] != PClan->ClanID[1])
+      {
+        /* not for him, skip it */
+        continue;
+      }
+
+      /* list stuff */
+      sprintf(szString, "\n|0B%s wishes to trade with you.  They are offering the following:\n|0C",
+        TradeData.szFromClan);
+      rputs(szString);
+
+      if (TradeData.Giving.Gold)
+      {
+        sprintf(szString, "  %ld gold\n", TradeData.Giving.Gold);
+        rputs(szString);
+      }
+      if (TradeData.Giving.Followers)
+      {
+        sprintf(szString, "  %ld followers\n", TradeData.Giving.Followers);
+        rputs(szString);
+      }
+      if (TradeData.Giving.Footmen)
+      {
+        sprintf(szString, "  %ld footmen\n", TradeData.Giving.Footmen);
+        rputs(szString);
+      }
+      if (TradeData.Giving.Axemen)
+      {
+        sprintf(szString, "  %ld axemen\n", TradeData.Giving.Axemen);
+        rputs(szString);
+      }
+      if (TradeData.Giving.Knights)
+      {
+        sprintf(szString, "  %ld knights\n", TradeData.Giving.Knights);
+        rputs(szString);
+      }
+      if (TradeData.Giving.Catapults)
+      {
+        sprintf(szString, "  %ld catapults\n", TradeData.Giving.Catapults);
+        rputs(szString);
+      }
+      if (TradeData.Giving.Gold == 0 &&
+          TradeData.Giving.Followers == 0 &&
+          TradeData.Giving.Footmen == 0 &&
+          TradeData.Giving.Axemen == 0 &&
+          TradeData.Giving.Knights == 0)
+        rputs("  |12Nothing\n");
+
+
+      /* what they want for it */
+      rputs("\n|0BAnd they would like the following in return:\n|0C");
+
+      if (TradeData.Asking.Gold)
+      {
+        sprintf(szString, "  %ld gold\n", TradeData.Asking.Gold);
+        rputs(szString);
+      }
+      if (TradeData.Asking.Followers)
+      {
+        sprintf(szString, "  %ld followers\n", TradeData.Asking.Followers);
+        rputs(szString);
+      }
+      if (TradeData.Asking.Footmen)
+      {
+        sprintf(szString, "  %ld footmen\n", TradeData.Asking.Footmen);
+        rputs(szString);
+      }
+      if (TradeData.Asking.Axemen)
+      {
+        sprintf(szString, "  %ld archers\n", TradeData.Asking.Axemen);
+        rputs(szString);
+      }
+      if (TradeData.Asking.Knights)
+      {
+        sprintf(szString, "  %ld knights\n", TradeData.Asking.Knights);
+        rputs(szString);
+      }
+      if (TradeData.Asking.Catapults)
+      {
+        sprintf(szString, "  %ld catapults\n", TradeData.Asking.Catapults);
+        rputs(szString);
+      }
+      if (TradeData.Asking.Gold == 0 &&
+          TradeData.Asking.Followers == 0 &&
+          TradeData.Asking.Footmen == 0 &&
+          TradeData.Asking.Axemen == 0 &&
+          TradeData.Asking.Knights == 0)
+        rputs("  |12Nothing\n");
+
+      /* see if user CAN trade */
+      if (  (PClan->Empire.VaultGold < TradeData.Asking.Gold) ||
+            (PClan->Empire.Army.Followers < TradeData.Asking.Followers) ||
+            (PClan->Empire.Army.Footmen < TradeData.Asking.Footmen) ||
+            (PClan->Empire.Army.Axemen < TradeData.Asking.Axemen) ||
+            (PClan->Empire.Army.Knights < TradeData.Asking.Knights))
+      {
+        if (YesNo("\n|12You cannot currently accept the trade's requirements.\n\n|0SDo you wish to ignore this for now?")
+            == YES)
+          continue;
+
+          /* doesn't want to ignore it, delete it! */
+          RejectTrade(&TradeData);
+
+          fseek(fpTradeFile, OldOffset, SEEK_SET);
+          EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+      }
+      else if (((PClan->Empire.Army.Footmen+TradeData.Giving.Footmen) >
+          PClan->Empire.Buildings[B_BARRACKS]*20) ||
+          ((PClan->Empire.Army.Axemen+TradeData.Giving.Axemen) >
+          PClan->Empire.Buildings[B_BARRACKS]*10) ||
+          ((PClan->Empire.Army.Knights+TradeData.Giving.Knights) >
+          PClan->Empire.Buildings[B_BARRACKS]*5) )
+      {
+        if (YesNo("\n|12You cannot currently accept the trade's requirements.  You do\nnot have enough room in your barracks to hold the troops.\n\n|0SDo you wish to ignore this for now?")
+            == YES)
+          continue;
+
+        /* doesn't want to ignore it, delete it! */
+        RejectTrade(&TradeData);
+
+        fseek(fpTradeFile, OldOffset, SEEK_SET);
+        EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+      }
+      else
+      {
+        /* CAN trade */
+        if (NoYes("\n|0SDo you wish to make the trade?") == YES)
+        {
+          /* update both dudes' stats */
+
+          TmpClan = malloc(sizeof(struct clan));
+          CheckMem(TmpClan);
+
+          GetClan(TradeData.FromClanID, TmpClan);
+
+          TmpClan->Empire.VaultGold += TradeData.Asking.Gold;
+          TmpClan->Empire.Army.Followers += TradeData.Asking.Followers;
+          TmpClan->Empire.Army.Footmen += TradeData.Asking.Footmen;
+          TmpClan->Empire.Army.Axemen += TradeData.Asking.Axemen;
+          TmpClan->Empire.Army.Knights += TradeData.Asking.Knights;
+
+          sprintf(szString, "%s accepted your trade.  You received the following:\n\n\
+ %ld Gold\n %ld Followers\n %ld Footmen\n %ld Axemen\n %ld Knights\n %ld Catapults\n",
+          PClan->szName, TradeData.Asking.Gold,
+          TradeData.Asking.Followers, TradeData.Asking.Footmen,
+          TradeData.Asking.Axemen, TradeData.Asking.Knights,
+          TradeData.Asking.Catapults);
+
+          GenericMessage(szString, TradeData.FromClanID,
+            PClan->ClanID, PClan->szName, FALSE);
+
+          /* update this data */
+          Clan_Update(TmpClan);
+
+          FreeClan(TmpClan);
+
+          /* update this clan's data */
+          PClan->Empire.VaultGold += TradeData.Giving.Gold;
+          PClan->Empire.Army.Followers += TradeData.Giving.Followers;
+          PClan->Empire.Army.Footmen += TradeData.Giving.Footmen;
+          PClan->Empire.Army.Axemen += TradeData.Giving.Axemen;
+          PClan->Empire.Army.Knights += TradeData.Giving.Knights;
+
+          /* update this clan's data */
+          PClan->Empire.VaultGold -= TradeData.Asking.Gold;
+          PClan->Empire.Army.Followers -= TradeData.Asking.Followers;
+          PClan->Empire.Army.Footmen -= TradeData.Asking.Footmen;
+          PClan->Empire.Army.Axemen -= TradeData.Asking.Axemen;
+          PClan->Empire.Army.Knights -= TradeData.Asking.Knights;
+
+          /* now delete it */
+          TradeData.Active = FALSE;
+
+          fseek(fpTradeFile, OldOffset, SEEK_SET);
+          EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+        }
+        else if (YesNo("\n|0SDo you wish to ignore this trade for now and decide on it later?") == YES)
+        {
+          /* skip it */
+          continue;
+        }
+        else
+        {
+          /* no, just delete it then */
+          RejectTrade(&TradeData);
+
+          fseek(fpTradeFile, OldOffset, SEEK_SET);
+          EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+        }
+      }
+    }
+
+    fclose(fpTradeFile);
+  }
+
+  void Trades_MakeTrade ( void )
+  {
+    struct TradeData TradeData;
+    FILE *fpTradeFile;
+    _INT16 ClanID[2];
+    char szString[255];
+
+    /* ask for who to trade with */
+    if (GetClanID( ClanID, FALSE, FALSE, -1, -1 ) == FALSE)
+    {
+      return;
+    }
+
+    /* ask for what you want to trade */
+    TradeData.Giving.Gold = 0;
+    TradeData.Giving.Followers = 0;
+    TradeData.Giving.Footmen = 0;
+    TradeData.Giving.Axemen = 0;
+    TradeData.Giving.Knights = 0;
+    TradeData.Giving.Catapults = 0;
+    GetTradeList(&TradeData.Giving, TRUE, "\n |0BPlease enter the equipment/troops that you will offer.\n");
+
+    /* see what user wants in return */
+    TradeData.Asking.Gold = 0;
+    TradeData.Asking.Followers = 0;
+    TradeData.Asking.Footmen = 0;
+    TradeData.Asking.Axemen = 0;
+    TradeData.Asking.Knights = 0;
+    TradeData.Asking.Catapults = 0;
+    GetTradeList(&TradeData.Asking, FALSE, "\n |0BPlease enter the equipment/troops that you would like in return.\n");
+
+    /* if all zeros, abort */
+    if ((TradeData.Asking.Gold == 0 &&
+        TradeData.Asking.Followers == 0 &&
+        TradeData.Asking.Footmen == 0 &&
+        TradeData.Asking.Axemen == 0 &&
+        TradeData.Asking.Knights == 0 &&
+        TradeData.Asking.Catapults == 0) &&
+       (TradeData.Giving.Gold == 0 &&
+        TradeData.Giving.Followers == 0 &&
+        TradeData.Giving.Footmen == 0 &&
+        TradeData.Giving.Axemen == 0 &&
+        TradeData.Giving.Knights == 0 &&
+        TradeData.Giving.Catapults == 0))
+    {
+      rputs(ST_ABORTED);
+      return;
+    }
+
+    /* show tradelist */
+    rputs("|0BYou are offering the following:\n|0C");
+
+    if (TradeData.Giving.Gold)
+    {
+      sprintf(szString, "  %ld gold\n", TradeData.Giving.Gold);
+      rputs(szString);
+    }
+    if (TradeData.Giving.Followers)
+    {
+      sprintf(szString, "  %ld followers\n", TradeData.Giving.Followers);
+      rputs(szString);
+    }
+    if (TradeData.Giving.Footmen)
+    {
+      sprintf(szString, "  %ld footmen\n", TradeData.Giving.Footmen);
+      rputs(szString);
+    }
+    if (TradeData.Giving.Axemen)
+    {
+      sprintf(szString, "  %ld archers\n", TradeData.Giving.Axemen);
+      rputs(szString);
+    }
+    if (TradeData.Giving.Knights)
+    {
+      sprintf(szString, "  %ld knights\n", TradeData.Giving.Knights);
+      rputs(szString);
+    }
+    if (TradeData.Giving.Catapults)
+    {
+      sprintf(szString, "  %ld catapults\n", TradeData.Giving.Catapults);
+      rputs(szString);
+    }
+    if (TradeData.Giving.Gold == 0 &&
+        TradeData.Giving.Followers == 0 &&
+        TradeData.Giving.Footmen == 0 &&
+        TradeData.Giving.Axemen == 0 &&
+        TradeData.Giving.Knights == 0 &&
+        TradeData.Giving.Catapults == 0)
+      rputs("  |12Nothing\n");
+
+    rputs("\n|0BIn return for the following:\n|0C");
+
+    if (TradeData.Asking.Gold)
+    {
+      sprintf(szString, "  %ld gold\n", TradeData.Asking.Gold);
+      rputs(szString);
+    }
+    if (TradeData.Asking.Followers)
+    {
+      sprintf(szString, "  %ld followers\n", TradeData.Asking.Followers);
+      rputs(szString);
+    }
+    if (TradeData.Asking.Footmen)
+    {
+      sprintf(szString, "  %ld footmen\n", TradeData.Asking.Footmen);
+      rputs(szString);
+    }
+    if (TradeData.Asking.Axemen)
+    {
+      sprintf(szString, "  %ld archers\n", TradeData.Asking.Axemen);
+      rputs(szString);
+    }
+    if (TradeData.Asking.Knights)
+    {
+      sprintf(szString, "  %ld knights\n", TradeData.Asking.Knights);
+      rputs(szString);
+    }
+    if (TradeData.Asking.Catapults)
+    {
+      sprintf(szString, "  %ld catapults\n", TradeData.Asking.Catapults);
+      rputs(szString);
+    }
+    if (TradeData.Asking.Gold == 0 &&
+        TradeData.Asking.Followers == 0 &&
+        TradeData.Asking.Footmen == 0 &&
+        TradeData.Asking.Axemen == 0 &&
+        TradeData.Asking.Knights == 0 &&
+        TradeData.Asking.Catapults == 0)
+      rputs("  |12Nothing\n");
+
+    rputs("\n");
+
+    /* ask if he really wants to do this */
+    if (YesNo("|0SAre you sure you wish to trade the above?") == NO)
+    {
+      rputs(ST_ABORTED);
+      return;
+    }
+
+    /* if so, reduce his stats accordingly */
+    PClan->Empire.VaultGold       -= TradeData.Giving.Gold;
+    PClan->Empire.Army.Followers  -= TradeData.Giving.Followers;
+    PClan->Empire.Army.Footmen -= TradeData.Giving.Footmen;
+    PClan->Empire.Army.Axemen -= TradeData.Giving.Axemen;
+    PClan->Empire.Army.Knights -= TradeData.Giving.Knights;
+
+    TradeData.Active = TRUE;
+    TradeData.ToClanID[0] = ClanID[0];
+    TradeData.ToClanID[1] = ClanID[1];
+    TradeData.FromClanID[0] = PClan->ClanID[0];
+    TradeData.FromClanID[1] = PClan->ClanID[1];
+    strcpy(TradeData.szFromClan, PClan->szName);
+
+    fpTradeFile = fopen("trades.dat", "ab");
+
+    /* append it */
+    EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+    fclose(fpTradeFile);
+
+    rputs("\n|13Trade has been requested.\n\n");
+  }
+
+  void Trades_Maint ( void )
+  {
+    FILE *fpTradeFile, *fpNewTradeFile;
+    struct TradeData TradeData;
+
+    fpTradeFile = fopen("trades.dat", "rb");
+    if (fpTradeFile)
+    {
+      fpNewTradeFile = fopen("tmp.$$$", "wb");
+      if (!fpNewTradeFile)
+        return;
+
+      for (;;)
+      {
+        if (EncryptRead(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE) == 0)
+          break;
+
+        /* see if active */
+        if (TradeData.Active == FALSE)
+          continue;
+
+        // it's active, write it to new file
+        EncryptWrite(&TradeData, sizeof(struct TradeData), fpNewTradeFile, XOR_TRADE);
+      }
+
+      fclose(fpTradeFile);
+      fclose(fpNewTradeFile);
+
+      unlink("trades.dat");
+      rename("tmp.$$$", "trades.dat");
+    }
+
+  }
diff --git a/src/doors/clans-src/trades.h b/src/doors/clans-src/trades.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b5ca48fbf6555955ef65ccfd4965b71da6f3b0c
--- /dev/null
+++ b/src/doors/clans-src/trades.h
@@ -0,0 +1,7 @@
+
+  void Trades_MakeTrade ( void );
+  void Trades_CheckTrades ( void );
+
+  void Trades_Maint ( void );
+
+  void RejectTrade ( struct TradeData *TradeData );
diff --git a/src/doors/clans-src/tslicer.c b/src/doors/clans-src/tslicer.c
new file mode 100644
index 0000000000000000000000000000000000000000..0c24224b9aeff4720fd2ca19a93aa715fdb9ffaf
--- /dev/null
+++ b/src/doors/clans-src/tslicer.c
@@ -0,0 +1,48 @@
+/*
+ * TimeSlicer stuff
+ */
+
+#include "defines.h"
+#include "tasker.h"
+
+struct {
+  _INT16 Poll;
+  BOOL UseSlicer;
+  BOOL CurSlice;
+} TSlicer = { 0, FALSE, 0 };
+
+void t_slice()
+{
+}
+  void TSlicer_Update( void )
+  {
+    static BOOL SliceOn = FALSE;
+
+    /* release time slices */
+    if (!SliceOn && TSlicer.UseSlicer && TSlicer.CurSlice == TSlicer.Poll)
+    {
+      t_slice();
+      SliceOn = TRUE;
+      TSlicer.CurSlice = 0;
+    }
+    else
+    {
+      SliceOn = FALSE;
+      TSlicer.CurSlice++;
+    }
+
+    // FIXME: read in online.flg file and see if message in it
+  }
+
+  void TSlicer_SetPoll ( _INT16 Poll )
+  {
+    TSlicer.Poll = Poll;
+  }
+
+  void TSlicer_Init ( void )
+  {
+    TSlicer.UseSlicer = TRUE;
+    TSlicer.CurSlice = 0;
+
+    TSlicer_SetPoll(100);
+  }
diff --git a/src/doors/clans-src/tslicer.h b/src/doors/clans-src/tslicer.h
new file mode 100644
index 0000000000000000000000000000000000000000..f50673681a9d9d31972d432c98df9aa6e52c4705
--- /dev/null
+++ b/src/doors/clans-src/tslicer.h
@@ -0,0 +1,4 @@
+
+  void TSlicer_SetPoll ( _INT16 Poll );
+  void TSlicer_Init ( void );
+  void TSlicer_Update( void );
diff --git a/src/doors/clans-src/unix_wrappers.c b/src/doors/clans-src/unix_wrappers.c
new file mode 100644
index 0000000000000000000000000000000000000000..f0bae32c4b18c894507e85a5839708b445e89227
--- /dev/null
+++ b/src/doors/clans-src/unix_wrappers.c
@@ -0,0 +1,250 @@
+#include <stdio.h>		// Only need for printf() debugging.
+#include <stdlib.h>
+#include <sys/file.h>
+#include <fnmatch.h>
+#include "unix_wrappers.h"
+
+#if defined(__linux__) || defined(__NetBSD__)
+void srandomdev()
+{
+/*	int f;
+	unsigned int r;
+ 	f=open("/dev/random",O_RDONLY);
+ 	read(f,&r,sizeof(r));
+ 	close(f);*/
+ 	srand(time(0));
+}
+#endif
+
+off_t
+filelength(int file)
+{
+  struct stat file_stat;
+  fstat(file,&file_stat);
+  return file_stat.st_size;
+}
+
+int
+strrev(char *str)
+{
+  char str2[MAX_STRING_LEN];
+  size_t i,j;
+  j=0;
+  for(i=strlen(str)-1;i>-1;i--)
+  {
+	str2[j++]=str[i];
+  }
+  str2[strlen(str)]=0;
+  strcpy(str,str2);
+  return 0;
+}
+
+int
+strlwr(char *str)
+{
+  size_t i;
+  for(i=0;i<strlen(str);i++)
+  {
+    if(str[i]>64 && str[i]<=91) str[i]=str[i]|32;
+  }
+  return 0;
+}
+
+int
+strupr(char *str)
+{
+  size_t i;
+  for(i=0;i<strlen(str);i++)
+  {
+    if(str[i]>96 && str[i]<123) str[i] &= 223;
+  }
+  return 0;
+}
+
+int
+findfirst(char *pathname, struct ffblk *fblk, int attrib)
+{
+  char	path[MAXPATH+3];
+  struct dirent *dp;
+  struct stat	file_stat;
+
+  strcpy(&path[2],pathname);
+  if (path[2] != '/' && path[2] != '~')  {
+	path[0]='.';
+	path[1]='/';
+  }
+  else  {
+  	memmove(path, &path[2], strlen(&path[2])+1);
+  }
+  *(strrchr(path,'/')+1)=0;
+  fblk->dir_handle = opendir(path);
+  strcpy(fblk->pathname,strrchr(pathname,'/')+1);
+
+  while ((dp = readdir(fblk->dir_handle)) != NULL)
+    if (!fnmatch(fblk->pathname,dp->d_name,0)) {
+	  stat(dp->d_name,&file_stat);
+	  // Do this if it's ever needed (Not yet)
+	  (*fblk).lfn_ctime=0;
+	  (*fblk).lfn_cdate=0;
+	  (*fblk).lfn_atime=0;
+	  (*fblk).lfn_adate=0;
+	  (*fblk).ff_ftime=0;
+	  (*fblk).ff_fdate=0;
+	  (*fblk).ff_fsize=file_stat.st_size;
+
+	  if (file_stat.st_mode&S_IFDIR) (*fblk).ff_attrib=FA_DIREC;
+	    if(strrchr(dp->d_name,'/')!=NULL)
+		  strcpy((*fblk).ff_name,strrchr(dp->d_name,'/')+1);
+		else
+		  strcpy((*fblk).ff_name,dp->d_name);
+		if((*fblk).ff_name!=NULL)  {
+		  return(0);
+	  }
+    }
+
+  closedir(fblk->dir_handle);  
+  return(1);
+}	
+	
+int
+findnext(struct ffblk *fblk)
+{
+  struct dirent *dp;
+  struct stat	file_stat;
+
+  while ((dp = readdir(fblk->dir_handle)) != NULL)
+    if (!fnmatch(fblk->pathname,dp->d_name,0)) {
+	  stat(dp->d_name,&file_stat);
+	  // Do this if it's ever needed (Not yet)
+	  (*fblk).lfn_ctime=0;
+	  (*fblk).lfn_cdate=0;
+	  (*fblk).lfn_atime=0;
+	  (*fblk).lfn_adate=0;
+	  (*fblk).ff_ftime=0;
+	  (*fblk).ff_fdate=0;
+	  (*fblk).ff_fsize=file_stat.st_size;
+
+	  if (file_stat.st_mode&S_IFDIR) (*fblk).ff_attrib=FA_DIREC;
+	    if(strrchr(dp->d_name,'/')!=NULL)
+		  strcpy((*fblk).ff_name,strrchr(dp->d_name,'/')+1);
+		else
+		  strcpy((*fblk).ff_name,dp->d_name);
+		if((*fblk).ff_name!=NULL)  {
+		  return(0);
+	  }
+    }
+  
+  closedir(fblk->dir_handle);  
+  return(1);
+}
+
+int
+getdate(struct date *getme)
+{
+  time_t	currtime;
+  struct tm		*thetime;
+
+  currtime=time(NULL);
+  thetime=localtime(&currtime);
+  (*getme).da_year=(*thetime).tm_year+1900;
+  (*getme).da_day=(*thetime).tm_mday;
+  (*getme).da_mon=(*thetime).tm_mon+1;
+  return 0;
+}
+
+int
+gettime(struct tm *getme)
+{
+  time_t	currtime;
+  struct tm	*gottime;
+
+  currtime=time(NULL);
+  gottime=localtime(&currtime);
+  (*getme).tm_sec=(*gottime).tm_sec;
+  (*getme).tm_min=(*gottime).tm_min;
+  (*getme).tm_hour=(*gottime).tm_hour;
+  return 0;
+}
+
+int
+strset(char *str, char ch)
+{
+  int x;
+  for(x=0;x<sizeof(str);x++)
+  {
+    str[x]=ch;
+  }
+  str[sizeof(str)]=0;
+  return 0;
+}
+
+int
+lock(int file, off_t offset, off_t length)
+{
+  struct flock mylock;
+  mylock.l_start=offset;
+  mylock.l_len=length;
+  mylock.l_pid=0;
+  mylock.l_type=F_WRLCK;
+  mylock.l_whence=SEEK_SET;
+  return fcntl(file,F_SETLKW,mylock);
+}
+
+int
+unlock(int file, off_t offset, off_t length)
+{
+  struct flock mylock;
+  mylock.l_start=offset;
+  mylock.l_len=length;
+  mylock.l_pid=0;
+  mylock.l_type=F_UNLCK;
+  mylock.l_whence=SEEK_SET;
+  return fcntl(file,F_SETLKW,mylock);
+}
+
+long
+unix_random(long maxnum)
+{
+   if (maxnum == 0) return 0;
+   return (long)random()%maxnum;
+}
+
+FILE *
+_fsopen(char *pathname, char *mode, int flags)  {
+	FILE *thefile;
+	
+	thefile = fopen(pathname, mode);
+	if (thefile != NULL)  {
+		if (flags&SH_DENYWR) {
+			flock(fileno(thefile), LOCK_SH);
+			return(thefile);
+		}
+		if (flags&SH_DENYRW) {
+			flock(fileno(thefile), LOCK_EX);
+			return(thefile);
+		}
+	}
+	return(thefile);
+}
+
+void
+delay(unsigned msec)  {
+	struct timeval delaytime;
+	
+	delaytime.tv_sec=msec/1000;
+	delaytime.tv_usec=msec % 1000;
+	
+	select(0,NULL,NULL,NULL,&delaytime);
+}
+
+#ifdef NEED_GETCH
+char
+getch()  {
+	fd_set fds;
+	FD_ZERO(&fds);
+	FD_SET(fileno(stdin),&fds);
+
+	select(1, &fds, NULL, NULL, NULL);
+	return (char)getchar();
+}
+#endif
diff --git a/src/doors/clans-src/unix_wrappers.h b/src/doors/clans-src/unix_wrappers.h
new file mode 100644
index 0000000000000000000000000000000000000000..ac2126dcb45f752c6b73ec99533bf5d041767042
--- /dev/null
+++ b/src/doors/clans-src/unix_wrappers.h
@@ -0,0 +1,84 @@
+#include <signal.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <time.h>
+#define MAXDIR	PATH_MAX
+#define MAXPATH PATH_MAX
+
+// ToDo - Tune this better.
+#define KERN_SKIP	8
+
+// ToDo This is totally arbitrary. 
+#define MAX_STRING_LEN  1024
+
+struct __attribute__((packed)) date {
+	short da_year;
+	short da_mon;
+	short da_day;
+} PACKED;
+
+// ToDo needs some kind of REAL randomisation.
+#define randomize	srandomdev
+#define RANDOM		unix_random
+
+#define strnicmp	strncasecmp
+#define stricmp		strcasecmp
+
+struct ffblk {
+  char lfn_magic[6];        /* LFN: the magic "LFN32" signature */
+  short lfn_handle;         /* LFN: the handle used by findfirst/findnext */
+  unsigned short lfn_ctime; /* LFN: file creation time */
+  unsigned short lfn_cdate; /* LFN: file creation date */
+  unsigned short lfn_atime; /* LFN: file last access time (usually 0) */
+  unsigned short lfn_adate; /* LFN: file last access date */
+  char ff_reserved[5];      /* used to hold the state of the search */
+  unsigned char ff_attrib;  /* actual attributes of the file found */
+  unsigned short ff_ftime;  /* hours:5, minutes:6, (seconds/2):5 */
+  unsigned short ff_fdate;  /* (year-1980):7, month:4, day:5 */
+  off_t ff_fsize;			/* size of file */
+  char ff_name[MAXPATH];    /* name of file as ASCIIZ string */
+  DIR *dir_handle;
+  char pathname[MAXPATH];
+};
+#define FA_RDONLY	1
+#define FA_HIDDEN	2
+#define FA_SYSTEM	4
+#define FA_LABEL	8
+#define FA_DIREC	16
+#define FA_ARCH		32
+
+
+void srandomdev();
+off_t filelength(int file);
+int strrev(char *str);
+int strlwr(char *str);
+int strupr(char *str);
+int findfirst(char *pathname, struct ffblk *fblk, int attrib);
+int findnext(struct ffblk *fblk);
+int getdate(struct date *getme);
+int strset(char *str, char ch);
+int lock(int file, off_t offset, off_t length);
+int unlock(int file, off_t offset, off_t length);
+long unix_random(long maxnum);
+int gettime(struct tm *getme);
+#ifdef NEED_GETCH
+char getch(void);
+#endif
+
+#define SH_DENYWR	1
+#define SH_DENYRW	2
+#define O_BINARY	0
+
+FILE * _fsopen(char *pathname, char *mode, int flags);
+
+void delay(unsigned msec);
diff --git a/src/doors/clans-src/user.c b/src/doors/clans-src/user.c
new file mode 100644
index 0000000000000000000000000000000000000000..9c1a9e4914900682d3919350b575be3ea88bef67
--- /dev/null
+++ b/src/doors/clans-src/user.c
@@ -0,0 +1,3241 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+#include <stdio.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "door.h"
+#include "parsing.h"
+#include "help.h"
+#include "input.h"
+#include "game.h"
+#include "crc.h"
+#include "myopen.h"
+#include "items.h"
+#include "mail.h"
+#include "empire.h"
+#include "system.h"
+#include "quests.h"
+#include "alliance.h"
+#include "misc.h"
+#include "video.h"
+#include "news.h"
+#include "ibbs.h"
+#include "scores.h"
+#include "trades.h"
+
+
+struct user {
+  BOOL Initialized;     // TRUE if user clan malloc'd
+  BOOL UpdateUser;      // TRUE if user data should be written to file
+} User = { FALSE, FALSE };
+
+struct clan *PClan=NULL;
+extern struct Language *Language;
+extern struct config *Config;
+extern struct game Game;
+extern struct system System;
+extern struct Spell *Spells[MAX_SPELLS];
+extern struct PClass *PClasses[MAX_PCLASSES], *Races[MAX_PCLASSES];
+extern struct village Village;
+extern struct ibbs IBBS;
+
+
+// ------------------------------------------------------------------------- //
+  BOOL Disbanded(void)
+  {
+    // returns true if the user is in DISBAND.DAT
+    char szUserName[36];
+    FILE *fp;
+    BOOL Found = FALSE;
+
+    fp = _fsopen("disband.dat", "rb", SH_DENYWR);
+
+    if (!fp)  return FALSE;
+
+    for (;;)
+    {
+      if (!EncryptRead(szUserName, 36, fp, XOR_DISBAND)) break;
+
+      if (stricmp(szUserName, od_control.user_name) == 0)
+      {
+        Found = TRUE;
+        break;
+      }
+    }
+
+    fclose(fp);
+
+    return Found;
+  }
+
+
+// ------------------------------------------------------------------------- //
+  void AddToDisband(void)
+  {
+    // append user name to disband.dat
+    FILE *fp;
+
+    fp = _fsopen("disband.dat", "ab", SH_DENYRW);
+    if (fp)
+    {
+      EncryptWrite(od_control.user_name, 36, fp, XOR_DISBAND);
+      fclose(fp);
+    }
+  }
+
+
+// ------------------------------------------------------------------------- //
+  void DeleteClan ( _INT16 ClanID[2], char *szClanName, BOOL Eliminate )
+  {
+    FILE *fpOldPC, *fpNewPC, *OldMessage, *NewMessage;
+    FILE *fpTradeFile;
+    long OldOffset;
+    char /*szFileName[40],*/ szString[128];
+    _INT16 CurTradeData, iTemp, CurAlliance, CurMember;
+    struct TradeData TradeData;
+    struct clan *TmpClan;
+    struct Message Message;
+    BOOL FoundInPCFile = FALSE;   // set to true if he was ever on this board
+    BOOL FoundNewCreator;
+    struct Alliance *Alliances[MAX_ALLIANCES];
+
+
+    AddToDisband();
+
+    if (Game.Data->InterBBS)
+    {
+      // remove from list of clan names, remove from list of user names
+      RemoveFromUList(ClanID);
+
+      // remove from high scores list
+      RemoveFromIPScores(ClanID);
+    }
+
+    // if this is the ruler of town, remove him
+    if (ClanID[0] == Village.Data->RulingClanId[0] && ClanID[1] == Village.Data->RulingClanId[1])
+    {
+      Village.Data->RulingClanId[0] = -1;
+      Village.Data->RulingClanId[1] = -1;
+      Village.Data->RulingDays = 0;
+      Village.Data->GovtSystem = GS_DEMOCRACY;
+
+      Village.Data->szRulingClan[0] = 0;
+    }
+
+    // go through PC file
+    fpOldPC = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYWR);
+    if (fpOldPC)
+    {
+      fpNewPC = _fsopen(ST_NEWPCFILE, "w+b", SH_DENYWR);
+      if (!fpNewPC)
+      {
+        System_Error("Can't write to new.pc\n");
+      }
+
+      /* allocate memory */
+      TmpClan = (struct clan *) malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+
+      for (;;)
+      {
+        /* go through each clan and write his info to new file and
+           skip the clan in question if he is found */
+
+        if (EncryptRead(TmpClan, sizeof(struct clan), fpOldPC, XOR_USER) == 0)
+          break;
+
+        /* if this is him */
+        if (TmpClan->ClanID[0] == ClanID[0] && TmpClan->ClanID[1] == ClanID[1])
+        {
+          FoundInPCFile = TRUE;
+
+          if (Eliminate == FALSE)
+          {
+            // skip the guy since we're deleting him
+            // skip 6 members
+            fseek(fpOldPC, 6L*sizeof(struct pc), SEEK_CUR);
+            continue;
+          }
+          else
+          {
+            //==== eliminated, might as well get rid of his allies
+            // to clean things up
+            // see if this clan is allied with him, if so, remove from allies list
+            for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+              TmpClan->Alliances[iTemp] = -1;
+          }
+        }
+
+        // read in 6 members
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          TmpClan->Member[iTemp] = malloc(sizeof(struct pc));
+          CheckMem(TmpClan->Member[iTemp]);
+          EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fpOldPC, XOR_PC);
+        }
+
+        //=== modifications go here
+        // make it so that he is NOT voted for
+        if (TmpClan->ClanRulerVote[0] == ClanID[0] &&
+            TmpClan->ClanRulerVote[1] == ClanID[1])
+        {
+          TmpClan->ClanRulerVote[0] = TmpClan->ClanRulerVote[1] = -1;
+        }
+
+
+        // IN FUTURE: if ruler of an alliance, set new ruler if another
+        // member was found.  if none, remove alliance from list
+
+        //===
+
+        /* write new stuff to new file */
+        EncryptWrite(TmpClan, sizeof(struct clan), fpNewPC, XOR_USER);
+
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          EncryptWrite(TmpClan->Member[iTemp], sizeof(struct pc), fpNewPC, XOR_PC);
+          free(TmpClan->Member[iTemp]);
+        }
+      }
+
+      /* deallocate memory for PCs */
+      free(TmpClan);
+
+      fclose(fpOldPC);
+      fclose(fpNewPC);
+
+      /* delete old file, rename new one */
+      unlink(ST_CLANSPCFILE);
+      rename(ST_NEWPCFILE, ST_CLANSPCFILE);
+    }
+
+    // go through msg file, set all his mail (to/from him) as deleted
+
+    OldMessage = _fsopen("clans.msj", "rb", SH_DENYRW);
+    if (OldMessage)     // MSJ file exists, so go on
+    {
+      NewMessage = _fsopen("tmp.$$$", "wb", SH_DENYRW);
+      if (!NewMessage)
+      {
+        return;
+      }
+
+      for (;;)
+      {
+        if (!EncryptRead(&Message, sizeof(struct Message), OldMessage, XOR_MSG))
+          break;
+
+        if ((Message.FromClanID[0] == ClanID[0] &&
+           Message.FromClanID[1] == ClanID[1]) ||
+          (Message.ToClanID[0] == ClanID[0] &&
+           Message.ToClanID[1] == ClanID[1]) )
+        {
+          // delete this message by skipping over it
+          fseek(OldMessage, Message.Data.Length, SEEK_CUR);
+        }
+        else
+        {
+          Message.Data.MsgTxt = malloc(Message.Data.Length);
+          CheckMem(Message.Data.MsgTxt);
+
+          // write it to new file
+          EncryptRead(Message.Data.MsgTxt, Message.Data.Length, OldMessage, XOR_MSG);
+
+          EncryptWrite(&Message, sizeof(Message), NewMessage, XOR_MSG);
+          EncryptWrite(Message.Data.MsgTxt, Message.Data.Length, NewMessage, XOR_MSG);
+
+          free(Message.Data.MsgTxt);
+        }
+      }
+
+      fclose(NewMessage);
+      fclose(OldMessage);
+
+      // delete old, and rename new
+      unlink("clans.msj");
+      rename("tmp.$$$", "clans.msj");
+    }
+
+    // go through trades.dat, for each trade struct, see if trade is headed
+    // for him, if so, set trade as aborted, return goods to user sending
+
+    fpTradeFile = _fsopen("trades.dat", "r+b", SH_DENYRW);
+
+    if (fpTradeFile)
+    {
+      for (CurTradeData = 0;;CurTradeData++)
+      {
+        if (fseek(fpTradeFile, (long)(CurTradeData * sizeof(struct TradeData)), SEEK_SET))
+          break;
+
+        OldOffset = ftell(fpTradeFile);
+
+        if (EncryptRead(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE) == 0)
+          break;
+
+        /* see if active */
+        if (TradeData.Active == FALSE)
+          continue;
+
+        if (TradeData.ToClanID[0] == ClanID[0] && TradeData.ToClanID[1] == ClanID[1])
+        {
+          rputs(">");
+          // it's for this deleted player, so, rejecttrade
+          RejectTrade(&TradeData);
+          rputs("<");
+
+          // write it to file
+          fseek(fpTradeFile, OldOffset, SEEK_SET);
+          EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+        }
+        else if (TradeData.FromClanID[0] == ClanID[0] &&
+          TradeData.FromClanID[1] == ClanID[1])
+        {
+          rputs(".");
+          // trade is coming from this player, remove it
+          TradeData.Active = FALSE;
+          fseek(fpTradeFile, OldOffset, SEEK_SET);
+          EncryptWrite(&TradeData, sizeof(struct TradeData), fpTradeFile, XOR_TRADE);
+        }
+      }
+
+      fclose(fpTradeFile);
+    }
+
+
+    // add message to news
+    if (*szClanName && FoundInPCFile && Eliminate == FALSE &&
+      PClan->Eliminated == FALSE)
+    {
+      sprintf(szString, "|0A � |0CThe clan of |0D%s |0Chas disbanded!\n\n",
+        szClanName);
+      News_AddNews(szString);
+    }
+    else if (*szClanName && FoundInPCFile && Eliminate)
+    {
+      sprintf(szString, "|0A � |0CThe clan of |0D%s |0Chas been eliminated!\n\n",
+        szClanName);
+      News_AddNews(szString);
+    }
+
+
+    // remove from ALLY.DAT
+    GetAlliances(Alliances);
+
+    // see if this clan is the creator of an alliance
+    for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+    {
+      if (Alliances[CurAlliance] &&
+        Alliances[CurAlliance]->CreatorID[0] == ClanID[0] &&
+        Alliances[CurAlliance]->CreatorID[1] == ClanID[1])
+      {
+        // find a new "leader"
+        FoundNewCreator = FALSE;
+        for (CurMember = 0; CurMember < MAX_ALLIANCEMEMBERS; CurMember++)
+        {
+          // if this is an actual member AND it's not the deleted clan,
+          // see if
+          if ((Alliances[CurAlliance]->Member[CurMember][0] != -1 &&
+             Alliances[CurAlliance]->Member[CurMember][1] != -1) &&
+            !(Alliances[CurAlliance]->Member[CurMember][0] == ClanID[0] &&
+             Alliances[CurAlliance]->Member[CurMember][1] == ClanID[1]))
+          {
+            FoundNewCreator = TRUE;
+            Alliances[CurAlliance]->CreatorID[0] = Alliances[CurAlliance]->Member[CurMember][0];
+            Alliances[CurAlliance]->CreatorID[1] = Alliances[CurAlliance]->Member[CurMember][1];
+
+            // FIXME: write him a message in future?
+          }
+        }
+
+        if (FoundNewCreator == FALSE)
+        {
+          // delete this alliance since no new ruler
+          free(Alliances[CurAlliance]);
+          Alliances[CurAlliance] = NULL;
+        }
+      }
+    }
+
+    // remove from any and all alliances he was in
+    for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+    {
+      for (CurMember = 0; CurMember < MAX_ALLIANCEMEMBERS; CurMember++)
+      {
+        if (Alliances[CurAlliance] && Alliances[CurAlliance]->Member[CurMember][0] == ClanID[0] &&
+          Alliances[CurAlliance]->Member[CurMember][1] == ClanID[1])
+        {
+          Alliances[CurAlliance]->Member[CurMember][0] = -1;
+          Alliances[CurAlliance]->Member[CurMember][1] = -1;
+        }
+      }
+    }
+
+    // deinit alliances and update to file
+    UpdateAlliances(Alliances);
+
+    // free up mem used by alliances
+    for (CurAlliance = 0; CurAlliance < MAX_ALLIANCES; CurAlliance++)
+      if (Alliances[CurAlliance])
+        free(Alliances[CurAlliance]);
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  BOOL ClanExists ( _INT16 ClanID[2] )
+  {
+    FILE *fpPlayerFile;
+    _INT16 CurClan/*, iTemp*/;
+    long /*OldOffset,*/ Offset;
+    struct clan *TmpClan;
+    BOOL FoundClan = FALSE;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    fpPlayerFile = fopen(ST_CLANSPCFILE, "rb");
+    if (!fpPlayerFile)
+    {
+      free(TmpClan);
+      return FALSE;  /* failed to find clan */
+    }
+
+    for (CurClan = 0;; CurClan++)
+    {
+      /* go through file till you find clan he wants */
+
+      Offset = (long)CurClan * ((long)sizeof(struct clan) + 6L*sizeof(struct pc));
+      if (fseek(fpPlayerFile, Offset, SEEK_SET))
+        break;  /* couldn't fseek, so exit */
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+        break;  /* stop reading if no more players found */
+
+      /* skip if deleted clan */
+      if (TmpClan->ClanID[0] == -1)
+        continue;
+
+      /* if same Ids, found clan! */
+      if (TmpClan->ClanID[0] == ClanID[0] && TmpClan->ClanID[1] == ClanID[1])
+      {
+        FoundClan = TRUE;
+        break;
+      }
+    }
+    fclose(fpPlayerFile);
+
+    free(TmpClan);
+
+    return FoundClan;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+
+  char GetStat ( struct pc *PC, char Stat )
+    /*
+     * Returns value of attribute specfied and takes into account weapons
+     * and spells.
+     */
+  {
+    char StatValue;
+    _INT16 iTemp;
+
+    /* soon to contain other modifiers! */
+
+    StatValue = PC->Attributes[ (Stat + 0) ];
+
+    /* if other stats to add on to it, add it on here */
+    if (PC->Weapon)
+      StatValue += PC->MyClan->Items[ PC->Weapon - 1 ].Attributes[Stat + 0];
+    if (PC->Shield)
+      StatValue += PC->MyClan->Items[ PC->Shield - 1 ].Attributes[Stat + 0];
+    if (PC->Armor)
+      StatValue += PC->MyClan->Items[ PC->Armor - 1 ].Attributes[Stat + 0];
+
+    /* add on spell modifiers here */
+    for (iTemp = 0; iTemp < 10; iTemp++)
+    {
+      /* skip if no spell in that slot */
+      if (PC->SpellsInEffect[iTemp].SpellNum == -1)
+        continue;
+
+      /* spell found, add it to modifiers */
+      StatValue += Spells[ PC->SpellsInEffect[iTemp].SpellNum ]->Attributes[ Stat + 0 ];
+    }
+
+    return StatValue;
+  }
+
+  void ShowBaseStats( struct PClass *PClass )
+    /*
+     * Shows base stats for a given class.  Used for creating new PCs.
+     */
+  {
+    char szFullString[128], szString[128];
+    char *szAttributeNames[NUM_ATTRIBUTES];
+    _INT16 SpellStrLength = 0;
+    /* = {
+      "Agility",
+      "Dexterity",
+      "Strength",
+      "Wisdom",
+      "Armor Strength",
+      "Charisma"};
+    */
+    _INT16 iTemp, NumSpellsKnown;
+    BOOL AtLeastOneSpell = FALSE;
+
+    // Load attribute names
+    LoadStrings(10, 6, szAttributeNames);
+
+    rputs("|07Base Stats\n\n");
+
+    for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+    {
+      /* go through each one, listing it */
+      sprintf(szFullString, "|0C%-20s ", szAttributeNames[iTemp]);
+
+      if (PClass->Attributes[iTemp] < 0)
+        strcat(szFullString, "|04");
+      else if (PClass->Attributes[iTemp] == 0)
+        strcat(szFullString, "|0C");
+      else
+        strcat(szFullString, "|15");
+
+      sprintf(szString, "%-2d      ", PClass->Attributes[iTemp]);
+      strcat(szFullString, szString);
+      rputs(szFullString);
+
+      if ((iTemp+1)%2 == 0)
+        rputs("\n");
+    }
+
+    strcpy(szFullString, "|0CHitpoints            ");
+    if (PClass->MaxHP < 0)
+      strcat(szFullString, "|04");
+    else if (PClass->MaxHP == 0)
+      strcat(szFullString, "|0C");
+    else
+      strcat(szFullString, "|15");
+    sprintf(szString, "%-3d     ", PClass->MaxHP);
+    strcat(szFullString, szString);
+    rputs(szFullString);
+
+    strcpy(szFullString, "|0CSkill Points         ");
+    if (PClass->MaxSP < 0)
+      strcat(szFullString, "|04");
+    else if (PClass->MaxSP == 0)
+      strcat(szFullString, "|0C");
+    else
+      strcat(szFullString, "|15");
+    sprintf(szString, "%-3d\n", PClass->MaxSP);
+    strcat(szFullString, szString);
+    rputs(szFullString);
+
+    strcpy(szFullString, "|0CGold                 ");
+    if (PClass->Gold < 0)
+      strcat(szFullString, "|04");
+    else if (PClass->Gold == 0)
+      strcat(szFullString, "|0C");
+    else
+      strcat(szFullString, "|15");
+    sprintf(szString, "%-3d\n", PClass->Gold);
+    strcat(szFullString, szString);
+    rputs(szFullString);
+
+    rputs("\n");
+
+    /* show spells known */
+    rputs(ST_SPELLSKNOWN);
+
+    NumSpellsKnown = 0;
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+    {
+      if (PClass->SpellsKnown[iTemp])
+      {
+        if (AtLeastOneSpell)
+        {
+          rputs(", ");
+          SpellStrLength += 2;
+        }
+
+        sprintf(szString, "%s", Spells[ PClass->SpellsKnown[iTemp] - 1]->szName);
+        rputs(szString);
+        SpellStrLength += strlen(szString);
+        NumSpellsKnown++;
+
+        AtLeastOneSpell = TRUE;
+
+        if (SpellStrLength > 60)
+        {
+          rputs("\n");
+          SpellStrLength = 0;
+          AtLeastOneSpell = FALSE;
+        }
+      }
+    }
+
+    if (NumSpellsKnown == 0)
+      rputs("|07None.");
+
+    rputs("\n\n\n");
+  }
+
+  _INT16 GetClass( struct PClass *PClass[MAX_PCLASSES], char *szHelp )
+    /*
+     * Returns a class as chosen by the user.  Used for creating new PCs.
+     */
+  {
+    _INT16 ClassChosen, iTemp;
+    char szKeys[MAX_PCLASSES + 2], szString[128], Choice;
+
+    /* so we have szKeys[] = "?ABCDEFGHI..." */
+    szKeys[0] = '?';
+    for (iTemp = 0; iTemp < MAX_PCLASSES; iTemp++)
+      szKeys[iTemp + 1] = 'A' + iTemp;
+    szKeys[iTemp + 1] = 0;
+
+    rputs("\n");
+
+    for (;;)
+    {
+      /* show options */
+      for (iTemp = 0; iTemp < MAX_PCLASSES; iTemp++)
+      {
+        if (PClass[iTemp] == NULL)
+        {
+          szKeys[iTemp + 1] = 0;
+          break;
+        }
+
+        sprintf(szString, ST_GETCLASS0, szKeys[iTemp + 1], PClass[iTemp]->szName);
+        rputs(szString);
+      }
+      /* help [?] option */
+      rputs(ST_GETCLASS1);
+
+      /* get input -- this asks for Enter Choice */
+      rputs(ST_GETCLASS2);
+
+      Choice = od_get_answer(szKeys);
+
+      if (Choice == '?')
+      {
+        rputs("Help\n");
+        Help(szHelp, ST_RACESHLP);
+        door_pause();
+      }
+      else
+      {
+        ClassChosen = Choice - 'A';
+        rputs(PClass[ClassChosen]->szName);
+        rputs("\n");
+
+        /* show info */
+        Help(PClass[ClassChosen]->szName, ST_RACESHLP);
+
+        /* show base stats */
+        ShowBaseStats(PClass[ClassChosen]);
+
+        if (YesNo(ST_CHOOSECLASS) == YES)
+          break;
+      }
+    }
+
+    return ClassChosen;
+  }
+
+  void ChooseDefaultAction ( struct pc *PC )
+    /*
+     * This allows the user to choose a default action for the PC specified.
+     */
+  {
+    char *pszOptions[MAX_SPELLS + 1];       // add 1 for "Attack" command
+    _INT16 iTemp, NumOptions, WhichOption;
+
+    if (!PClan->DefActionHelp)
+    {
+      PClan->DefActionHelp = TRUE;
+      Help("Default Action", ST_NEWBIEHLP);
+    }
+
+    for (iTemp = 0; iTemp < MAX_SPELLS+1; iTemp++)
+      pszOptions[iTemp] = NULL;
+
+    pszOptions[0] = "Attack";
+
+    NumOptions = 1;
+
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+    {
+      if (PC->SpellsKnown[iTemp])
+      {
+        pszOptions[iTemp + 1] = Spells[ PC->SpellsKnown[iTemp] - 1]->szName;
+        NumOptions++;
+      }
+    }
+
+    // choose one
+    GetStringChoice(pszOptions, NumOptions, ST_DEFACTION2, &WhichOption,
+      TRUE, DT_LONG, FALSE);
+
+    if (WhichOption == 0)
+      PC->DefaultAction = 0;
+    else
+      PC->DefaultAction = WhichOption + 9;
+  }
+
+
+  void ShowPlayerStats ( struct pc *PC, BOOL AllowModify )
+    /*
+     * Shows statistics for the given PC.
+     */
+  {
+    _INT16 iTemp, NumSpellsKnown, SpellNum;
+    BOOL AtLeastOneSpell, NewLine, Done;
+    _INT16 SpellStrLength = 0, CurAttr, CurSpell;
+    char szString[255], cInput;
+    long XPRequired[MAX_LEVELS];
+    _INT16 Level;
+    char *szAttrNames[NUM_ATTRIBUTES];
+
+    // load attribute names
+    LoadStrings(10, 6, szAttrNames);
+
+    /* figure XP required per level */
+    for (Level = 1; Level < MAX_LEVELS; Level++)
+    {
+      XPRequired[Level] = 50;
+
+      for (iTemp = 1; iTemp <= Level; iTemp++)
+        XPRequired[Level] += ((iTemp-1)*75);
+    }
+
+    if (AllowModify == FALSE)
+      Done = TRUE;
+    else
+      Done = FALSE;
+
+    do
+    {
+      SpellStrLength = 0;
+      NewLine = FALSE;
+      AtLeastOneSpell = FALSE;
+      od_clr_scr();
+
+      sprintf(szString, ST_P2STATS0, PC->szName);
+
+      switch(PC->Status)
+      {
+        case Dead :
+          strcat(szString, "|04(Dead)");
+          break;
+        case Unconscious :
+          strcat(szString, "|04(Unconscious)");
+          break;
+        case Here :
+          strcat(szString, "|0M(Alive)");
+          break;
+      }
+
+      PadString(szString, 43);
+      strcat(szString, ST_P2STATS1);
+      rputs(szString);
+
+      sprintf(szString, ST_P2STATS2, PC->Level);
+      PadString(szString, 43);
+      rputs(szString);
+
+      if (PC->Weapon)
+        sprintf(szString, ST_P2STATS3, PC->MyClan->Items[ PC->Weapon-1 ].szName);
+      else
+        sprintf(szString, ST_P2STATS3, "Nothing");
+      rputs(szString);
+
+
+      sprintf(szString, ST_P2STATS4, PC->Experience, XPRequired[ PC->Level + 1 ]-PC->Experience,
+        PC->TrainingPoints);
+      PadString(szString, 43);
+      rputs(szString);
+
+      if (PC->Armor)
+        sprintf(szString, ST_P2STATS5, PC->MyClan->Items[ PC->Armor-1 ].szName);
+      else
+        sprintf(szString, ST_P2STATS5, "Nothing");
+      rputs(szString);
+
+
+      if (PC->WhichRace != -1)
+      {
+        sprintf(szString, ST_P2STATS6, Races[ PC->WhichRace ]->szName,
+          PClasses[ PC->WhichClass ]->szName);
+      }
+      else
+      {
+        sprintf(szString, ST_P2STATS6, "Unknown", "Unknown");
+      }
+      PadString(szString, 43);
+      rputs(szString);
+
+      // shield
+      if (PC->Shield)
+        sprintf(szString, ST_P2STATS7, PC->MyClan->Items[ PC->Shield-1 ].szName);
+      else
+        sprintf(szString, ST_P2STATS7, "Nothing");
+      rputs(szString);
+
+      sprintf(szString, ST_P2STATS8, PC->HP, PC->MaxHP);
+      rputs(szString);
+      sprintf(szString, ST_P2STATS9, PC->SP, PC->MaxSP);
+      rputs(szString);
+      sprintf(szString, ST_P2STATS14, PC->TrainingPoints);
+      rputs(szString);
+
+      rputs(ST_P2STATS10);
+
+      NumSpellsKnown = 0;
+      for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      {
+        if (PC->SpellsKnown[iTemp])
+          NumSpellsKnown++;
+      }
+
+      for (CurAttr = 0, CurSpell = 0; CurAttr < NUM_ATTRIBUTES; CurAttr++)
+      {
+        sprintf(szString, "|0L %-19s |0M(%-2d) |0N%-2d",
+          szAttrNames[CurAttr], PC->Attributes[CurAttr], GetStat(PC, (char)CurAttr));
+
+        PadString(szString, 43);
+        rputs(szString);
+
+        // update spells shown
+        if (CurAttr == 0 && NumSpellsKnown == 0)
+          rputs("None\n");
+
+        else
+        {
+          AtLeastOneSpell = FALSE;
+          SpellStrLength = 0;
+
+          while (CurSpell < MAX_SPELLS)
+          {
+            if (PC->SpellsKnown[CurSpell])
+            {
+              if ((SpellStrLength + strlen(Spells[ PC->SpellsKnown[CurSpell] - 1]->szName)) > 27)
+              {
+                // don't display the current spell now, but wait
+                // till next iteration
+                break;
+              }
+
+              if (AtLeastOneSpell)
+              {
+                rputs(", ");
+                SpellStrLength += 2;
+              }
+              AtLeastOneSpell = TRUE;
+
+
+              sprintf(szString, "%s", Spells[ PC->SpellsKnown[CurSpell] - 1]->szName);
+              rputs(szString);
+              SpellStrLength += strlen(szString);
+
+              if (SpellStrLength > 30)
+              {
+                // done!
+                CurSpell++;
+                break;
+              }
+            }
+
+            CurSpell++;
+          }
+          rputs("\n");
+        }
+      }
+
+      rputs(ST_P2STATS11);
+      if (PC->DefaultAction == 0)
+        rputs("Attack\n");
+	      else if (PC->DefaultAction >= 1)
+      {
+        SpellNum = PC->SpellsKnown[PC->DefaultAction - 10] - 1;
+
+        sprintf(szString, "%s\n", Spells[SpellNum]->szName);
+        rputs(szString);
+      }
+
+      rputs(ST_P2STATS12);
+
+      if (AllowModify)
+      {
+        rputs(ST_P2STATS13);
+
+        cInput = toupper(od_get_key(TRUE));
+
+        if (cInput == 'C')
+        {
+          rputs("Change Default Acton\n\n");
+          ChooseDefaultAction(PC);
+        }
+        else
+          break;
+      }
+
+    } while (!Done);
+
+  }
+
+  void ListItems ( struct clan *Clan )
+    /*
+     * Lists Items for the given clan.
+     */
+  {
+    _INT16 iTemp, iTemp2, Length, LastItem = 0, FoundItem = FALSE;
+    _INT16 CurItem;
+    char szString[100], szOwner[30];
+
+    // rputs("|0LNumber |0MItemName       |0N(Used by)\n\n");
+
+    rputs("|0B # Name|07                 |0CUsed By|07      ");
+    rputs("|0B # Name|07                 |0CUsed By|07\n");
+    rputs("|0A屯哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯|07   ");
+    rputs("|0A屯哪哪哪哪哪哪哪哪哪哪哪哪哪哪哪屯|07\n");
+
+    /* show all the items here */
+    for (iTemp = 0, CurItem = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+    {
+      if (Clan->Items[iTemp].Available)
+      {
+        FoundItem = TRUE;
+        /* see if owned */
+        if (Clan->Items[iTemp].UsedBy)
+        {
+          strcpy(szOwner, Clan->Member[ Clan->Items[iTemp].UsedBy - 1]->szName);
+          szOwner[10] = 0;
+
+          sprintf(szString, "|0L%2d |0M%-20s |0N%s", iTemp+1, Clan->Items[iTemp].szName,
+            szOwner);
+        }
+        else
+          sprintf(szString, "|0L%2d |0M%-20s |0N", iTemp+1, Clan->Items[iTemp].szName);
+
+  #define LEN (37+9)    // add 9 for the | codes!
+
+        /* add or remove spaces to filler it */
+        if (strlen(szString) > LEN)
+        {
+          szString[LEN] = 0;
+        }
+        else
+        {
+          /* add spaces */
+          szString[LEN] = 0;
+          Length = strlen(szString);
+          for (iTemp2 = LEN-1; iTemp2 >= Length; iTemp2--)
+            szString[iTemp2] = ' ';
+        }
+        rputs(szString);
+        if (CurItem%2 != 0)
+          rputs("\n");
+        CurItem++;
+
+        LastItem = iTemp;
+      }
+    }
+    if (FoundItem == FALSE)
+      rputs(" |04No items in inventory.");
+
+    if (LastItem%2 == 0)
+      rputs("\n");
+
+    rputs("\n");
+  }
+
+
+  void ItemEquipResults ( struct pc *PC, struct item_data *Item, BOOL Equipping )
+    /*
+     * This functions outputs results of equipping an item.
+     */
+  {
+    char *szVerb;
+    char *szString, Gain,
+         *szAttrNames[NUM_ATTRIBUTES];
+    _INT16 CurStat;
+
+    szString = MakeStr(128);
+    LoadStrings(10, 6, szAttrNames);
+
+    // go through each stat, say if gained or lost
+    for (CurStat = 0; CurStat < NUM_ATTRIBUTES; CurStat++)
+    {
+      Gain = Item->Attributes[CurStat];
+
+      if (Equipping == FALSE)
+        Gain = -Gain;
+
+      if (Gain < 0)
+        szVerb = "|04decreases|03";
+      else
+        szVerb = "|11increases|03";
+
+      if (Gain == 0)  // no change
+        continue;
+
+      // make it positive again to display it
+      if (Gain < 0)
+        Gain = -Gain;
+
+      sprintf(szString, "|03%s %s by %d\n", szAttrNames[ CurStat], szVerb, Gain);
+      rputs(szString);
+    }
+
+    free(szString);
+  }
+
+  void ItemStats ( void )
+    /*
+     * Shows item statistics for PClan.
+     */
+  {
+    /* modify item stats, assume it's the player */
+    _INT16 ItemIndex, OneItemFound;
+    _INT16 DefaultItemIndex, iTemp, WhoEquip;
+    char szKeys[11], szString[100], /*szTemp[60],*/ szItemName[25];
+    BOOL DoneEquipping, EquippedAlready;
+
+    for (;;)
+    {
+      rputs(ST_ISTATS0);
+
+      switch (od_get_answer("?XEDSLQ\r\n R"))
+      {
+        case 'R' :  // read book
+          rputs("Read book\n");
+          ReadBook();
+          break;
+        case '?' :
+          rputs("Help\n\n");
+          Help("Item Help", ST_MENUSHLP);
+          break;
+        case ' ' :
+        case '\r' :
+        case '\n' :
+        case 'Q' :
+          return;
+        case 'X' :  /* examine item */
+          rputs(ST_ISTATS1);
+
+          /* see if anything to examine */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            rputs(ST_ISTATS2);
+            break;
+          }
+
+          /* find first item in inventory */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            DefaultItemIndex = 1;
+          }
+          else
+            DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS3, DefaultItemIndex, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+          ShowItemStats(&PClan->Items[ItemIndex], PClan);
+          break;
+        case 'L' :
+          rputs(ST_ISTATS5);
+          ListItems(PClan);
+          break;
+        case 'D' :  /* drop item */
+          rputs(ST_ISTATS6);
+
+          /* see if anything to drop */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            rputs(ST_ISTATS2);
+            break;
+          }
+
+          /* find first item which is not equipped */
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+            if (PClan->Items[iTemp].Available &&
+              PClan->Items[iTemp].UsedBy == 0)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD)
+          {
+            DefaultItemIndex = 1;
+          }
+          else
+            DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS7, DefaultItemIndex, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+          /* if that item is in use, tell him */
+          if (PClan->Items[ItemIndex].UsedBy != 0)
+          {
+            rputs(ST_ISTATS8);
+            break;
+          }
+
+          /* still wanna drop it? */
+          sprintf(szString, ST_ISTATS9, PClan->Items[ItemIndex].szName);
+
+          if (NoYes(szString) == YES)
+          {
+            /* drop it */
+            sprintf(szString, ST_ISTATS10, PClan->Items[ItemIndex].szName);
+            rputs(szString);
+
+            PClan->Items[ItemIndex].szName[0] = 0;
+            PClan->Items[ItemIndex].Available = FALSE;
+          }
+          break;
+        case 'S' :
+          rputs(ST_ISTATS11);
+
+          /* find first item which is equipped */
+          OneItemFound = FALSE;
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+                      if (PClan->Items[iTemp].Available &&
+                          PClan->Items[iTemp].cType != I_SCROLL &&
+                          PClan->Items[iTemp].cType != I_BOOK)
+              OneItemFound = TRUE;
+
+            if (PClan->Items[iTemp].Available &&
+                          PClan->Items[iTemp].UsedBy != 0 &&
+                          PClan->Items[iTemp].cType != I_SCROLL &&
+                          PClan->Items[iTemp].cType != I_BOOK)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD && OneItemFound == TRUE)
+          {
+            rputs(ST_ISTATS12);
+            break;
+          }
+          else if (OneItemFound == FALSE)
+          {
+            rputs(ST_ISTATS2);
+            break;
+          }
+
+          DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS13, DefaultItemIndex, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+
+          /* see if not equipped */
+          if (PClan->Items[ItemIndex].UsedBy == 0)
+          {
+            rputs(ST_ISTATS14);
+            break;
+          }
+
+          /* if equipped, take it away from whoever using it */
+          switch(PClan->Items[ ItemIndex ].cType)
+          {
+            case I_WEAPON :
+              sprintf(szString, ST_ISTATS15,
+                PClan->Member[PClan->Items[ItemIndex].UsedBy-1]->szName, PClan->Items[ItemIndex].szName);
+              rputs(szString);
+
+              ItemEquipResults(PClan->Member[PClan->Items[ItemIndex].UsedBy-1], &PClan->Items[ItemIndex], FALSE);
+
+              PClan->Member[PClan->Items[ItemIndex].UsedBy-1]->Weapon = 0;
+              PClan->Items[ItemIndex].UsedBy = 0;
+              break;
+            case I_ARMOR :
+              sprintf(szString, ST_ISTATS16,
+                PClan->Member[PClan->Items[ItemIndex].UsedBy-1]->szName, PClan->Items[ItemIndex].szName);
+              rputs(szString);
+
+              ItemEquipResults(PClan->Member[PClan->Items[ItemIndex].UsedBy-1], &PClan->Items[ItemIndex], FALSE);
+
+              PClan->Member[PClan->Items[ItemIndex].UsedBy-1]->Armor = 0;
+              PClan->Items[ItemIndex].UsedBy = 0;
+              break;
+            case I_SHIELD :
+              sprintf(szString, ST_ISTATS17,
+                PClan->Member[PClan->Items[ItemIndex].UsedBy-1]->szName, PClan->Items[ItemIndex].szName);
+              rputs(szString);
+
+              ItemEquipResults(PClan->Member[PClan->Items[ItemIndex].UsedBy-1], &PClan->Items[ItemIndex], FALSE);
+
+              PClan->Member[PClan->Items[ItemIndex].UsedBy-1]->Shield = 0;
+              PClan->Items[ItemIndex].UsedBy = 0;
+              break;
+          }
+          break;
+        case 'E' :
+          rputs(ST_ISTATS18);
+          /* find first item which is not equipped yet */
+          OneItemFound = FALSE;
+          for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+          {
+                      if (PClan->Items[iTemp].Available &&
+                          PClan->Items[iTemp].cType != I_SCROLL &&
+                          PClan->Items[iTemp].cType != I_BOOK)
+              OneItemFound = TRUE;
+
+            if (PClan->Items[iTemp].Available &&
+                          PClan->Items[iTemp].UsedBy == 0 &&
+                          PClan->Items[iTemp].cType != I_SCROLL &&
+                          PClan->Items[iTemp].cType != I_BOOK)
+              break;
+          }
+          if (iTemp == MAX_ITEMS_HELD && OneItemFound == TRUE)
+          {
+            rputs(ST_ISTATS19);
+            break;
+          }
+          else if (OneItemFound == FALSE)
+          {
+            rputs(ST_ISTATS2);
+            break;
+          }
+          DefaultItemIndex = iTemp+1;
+
+          ItemIndex = (_INT16) GetLong(ST_ISTATS20, DefaultItemIndex, MAX_ITEMS_HELD);
+          if (ItemIndex == 0)
+            break;
+          ItemIndex--;
+
+          /* if that item is non-existant, tell him */
+          if (PClan->Items[ItemIndex].Available == FALSE)
+          {
+            rputs(ST_ISTATS4);
+            break;
+          }
+
+          /* see if already equipped */
+          if (PClan->Items[ItemIndex].UsedBy != 0)
+          {
+            rputs(ST_ISTATS21);
+            break;
+          }
+
+          if (PClan->Items[ ItemIndex ].cType == I_SCROLL ||
+            PClan->Items[ ItemIndex ].cType == I_BOOK ||
+            PClan->Items[ ItemIndex ].cType == I_OTHER)
+          {
+            rputs("|04Can't equip that!\n");
+            break;
+          }
+
+          DoneEquipping = FALSE;
+          while (!DoneEquipping)
+          {
+            /* if not, ask who to equip it on */
+            szKeys[0] = '\r';
+            szKeys[1] = '\n';
+            szKeys[2] = 0;
+            rputs("\n");
+            for (iTemp = 0; iTemp < 6; iTemp++)
+            {
+              EquippedAlready = FALSE;
+              if (PClan->Member[iTemp])
+              {
+                strcpy(szItemName, "Nothing");
+
+                // see if equipped already
+                switch(PClan->Items[ ItemIndex ].cType)
+                {
+                  case I_WEAPON :
+                    if (PClan->Member[iTemp]->Weapon)
+                    {
+                      EquippedAlready = TRUE;
+                      strcpy(szItemName,
+                        PClan->Items[PClan->Member[iTemp]->Weapon-1].szName);
+                    }
+                    break;
+                  case I_ARMOR :
+                    if (PClan->Member[iTemp]->Armor)
+                    {
+                      EquippedAlready = TRUE;
+                      strcpy(szItemName,
+                        PClan->Items[PClan->Member[iTemp]->Armor-1].szName);
+                    }
+                    break;
+                  case I_SHIELD :
+                    if (PClan->Member[iTemp]->Shield)
+                    {
+                      EquippedAlready = TRUE;
+                      strcpy(szItemName,
+                        PClan->Items[PClan->Member[iTemp]->Shield-1].szName);
+                    }
+                    break;
+                }
+
+                sprintf(szString, ST_ISTATS22,
+                  iTemp+'A',
+                  ItemPenalty(PClan->Member[iTemp], &PClan->Items[ItemIndex]) ? "|08" : "|0C",
+                  PClan->Member[iTemp]->szName,
+                  szItemName);
+
+                // append race/class
+                /* show race/class */
+  /*
+                if (PClan->Member[iTemp]->WhichRace != -1)
+                  sprintf(szTemp, "%s/%s\n",
+                    Races[PClan->Member[iTemp]->WhichRace]->szName,
+                    PClasses[PClan->Member[iTemp]->WhichClass]->szName);
+                else
+                  strcpy(szTemp, "[unknown]\n");
+                strcat(szString, szTemp);
+  */
+
+                rputs(szString);
+                szKeys[ strlen(szKeys) +1 ] = 0;
+                szKeys[ strlen(szKeys) ] = iTemp + 'A';
+              }
+            }
+            strcat(szKeys, "Q");
+            rputs(ST_ISTATS23);
+
+
+            sprintf(szString, ST_ISTATS24, PClan->Items[ItemIndex].szName);
+            rputs(szString);
+
+            WhoEquip = od_get_answer(szKeys);
+
+            if (WhoEquip == '\r' || WhoEquip == 'Q' || WhoEquip == '\n')
+            {
+              rputs(ST_ABORTED);
+              break;
+            }
+            else
+              WhoEquip -= 'A';
+
+            /* if that guy is not a permanent member, in future, say you
+               can't equip him */
+
+            /* see if he has access to use that weapon, probably does :) */
+            sprintf(szString, "|15%s\n\n", PClan->Member[WhoEquip]->szName);
+            rputs(szString);
+
+            if (ItemPenalty(PClan->Member[WhoEquip], &PClan->Items[ ItemIndex ]))
+            {
+              rputs("\n|04That player cannot use that item\n");
+              continue;
+            }
+
+
+            /* see if that guy has something equipped, if so, tell user */
+            switch(PClan->Items[ ItemIndex ].cType)
+            {
+              case I_WEAPON :
+                if (PClan->Member[WhoEquip]->Weapon)
+                {
+                  sprintf(szString, ST_ISTATS25,
+                    PClan->Items[ PClan->Member[WhoEquip]->Weapon-1].szName );
+                  if (YesNo(szString) == YES)
+                  {
+                    iTemp = PClan->Member[WhoEquip]->Weapon-1;
+                    sprintf(szString, ST_ISTATS15,
+                      PClan->Member[WhoEquip]->szName, PClan->Items[iTemp].szName);
+                    rputs(szString);
+
+                    ItemEquipResults(PClan->Member[WhoEquip], &PClan->Items[iTemp], FALSE);
+
+                    PClan->Member[WhoEquip]->Weapon = 0;
+                    PClan->Items[iTemp].UsedBy = 0;
+                    DoneEquipping = TRUE;
+                  }
+                  else
+                  {
+                    rputs(ST_ABORTED);
+                    break;
+                  }
+                }
+
+                sprintf(szString, ST_ISTATS26, PClan->Member[WhoEquip]->szName, PClan->Items[ItemIndex].szName);
+                rputs(szString);
+
+                PClan->Member[WhoEquip]->Weapon = ItemIndex + 1;
+                PClan->Items[ItemIndex].UsedBy = WhoEquip + 1;
+                // tell them what happened to his stats
+                ItemEquipResults(PClan->Member[WhoEquip], &PClan->Items[ItemIndex], TRUE);
+                DoneEquipping = TRUE;
+                break;
+              case I_ARMOR :
+                if (PClan->Member[WhoEquip]->Armor)
+                {
+                  sprintf(szString, ST_ISTATS27,
+                    PClan->Items[ PClan->Member[WhoEquip]->Armor-1].szName );
+                  if (YesNo(szString) == YES)
+                  {
+                    iTemp = PClan->Member[WhoEquip]->Armor-1;
+                    sprintf(szString, ST_ISTATS15,
+                      PClan->Member[WhoEquip]->szName, PClan->Items[iTemp].szName);
+                    rputs(szString);
+
+                    ItemEquipResults(PClan->Member[WhoEquip], &PClan->Items[iTemp], FALSE);
+
+                    PClan->Member[WhoEquip]->Armor = 0;
+                    PClan->Items[iTemp].UsedBy = 0;
+                    DoneEquipping = TRUE;
+                  }
+                  else
+                  {
+                    rputs(ST_ABORTED);
+                    break;
+                  }
+                }
+                sprintf(szString, ST_ISTATS28, PClan->Member[WhoEquip]->szName, PClan->Items[ItemIndex].szName);
+                rputs(szString);
+
+                PClan->Member[WhoEquip]->Armor = ItemIndex + 1;
+                PClan->Items[ItemIndex].UsedBy = WhoEquip + 1;
+                // tell them what happened to his stats
+                ItemEquipResults(PClan->Member[WhoEquip], &PClan->Items[ItemIndex], TRUE);
+                DoneEquipping = TRUE;
+                break;
+              case I_SHIELD :
+                if (PClan->Member[WhoEquip]->Shield)
+                {
+                  sprintf(szString, ST_ISTATS29,
+                    PClan->Items[ PClan->Member[WhoEquip]->Shield-1].szName );
+                  if (YesNo(szString) == YES)
+                  {
+                    iTemp = PClan->Member[WhoEquip]->Shield-1;
+                    sprintf(szString, ST_ISTATS15,
+                      PClan->Member[WhoEquip]->szName, PClan->Items[iTemp].szName);
+                    rputs(szString);
+
+                    ItemEquipResults(PClan->Member[WhoEquip], &PClan->Items[iTemp], FALSE);
+
+                    PClan->Member[WhoEquip]->Shield = 0;
+                    PClan->Items[iTemp].UsedBy = 0;
+                    DoneEquipping = TRUE;
+                  }
+                  else
+                  {
+                    rputs(ST_ABORTED);
+                    break;
+                  }
+                }
+                sprintf(szString, ST_ISTATS30, PClan->Member[WhoEquip]->szName, PClan->Items[ItemIndex].szName);
+                rputs(szString);
+
+                PClan->Member[WhoEquip]->Shield = ItemIndex + 1;
+                PClan->Items[ItemIndex].UsedBy = WhoEquip + 1;
+                // tell them what happened to his stats
+                ItemEquipResults(PClan->Member[WhoEquip], &PClan->Items[ItemIndex], TRUE);
+                DoneEquipping = TRUE;
+                break;
+            }
+          }
+          break;
+      }
+    }
+  }
+
+  _INT16 NumClansInVillage ( void )
+  {
+    FILE *fp;
+    struct clan *TmpClan;
+    _INT16 NumClans;
+
+    fp = fopen(ST_CLANSPCFILE, "rb");
+    if (!fp)
+      return 0;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    for (NumClans = 0;;)
+    {
+      if (EncryptRead(TmpClan, sizeof(struct clan), fp, XOR_USER) == 0)
+        break;
+
+      if (TmpClan->ClanID[0] != -1)  /* means is active */
+        NumClans++;
+
+      /* skip his 6 PCs */
+      fseek(fp, 6*sizeof(struct pc), SEEK_CUR);
+    }
+
+
+    fclose(fp);
+
+    free(TmpClan);
+    return (NumClans);
+  }
+
+  void ShowVillageStats ( void )
+  {
+    char szString[255], szRuler[25];
+
+    od_clr_scr();
+    if (Game.Data->InterBBS)
+      sprintf(szString, ST_VSTATHEADER, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszVillageName);
+    else
+      sprintf(szString, ST_VSTATHEADER, Village.Data->szName);
+    rputs(szString);
+
+    rputs(ST_LONGDIVIDER);
+
+    if (Village.Data->szRulingClan[0] == 0)
+      strcpy(szRuler, "None");
+    else
+      strcpy(szRuler, Village.Data->szRulingClan);
+
+    sprintf(szString, ST_VSTATS1, NumClansInVillage(), szRuler);
+    rputs(szString);
+
+    sprintf(szString, ST_VSTATS2, Village.Data->TaxRate);
+    rputs(szString);
+
+    sprintf(szString, ST_VSTATS4, Village.Data->GST);
+    rputs(szString);
+
+    sprintf(szString, ST_VSTATS7, Village.Data->Empire.VaultGold);
+    rputs(szString);
+
+      sprintf(szString, ST_TMENUSTAT8, Village.Data->ConscriptionRate);
+      rputs(szString);
+/*    sprintf(szString, ST_TMENUSTAT9, Village.Data->GovtSystem == GS_DEMOCRACY ?
+        "Democracy" : "Dictatorship");
+      rputs(szString);
+
+      sprintf(szString, ST_TMENUSTAT10, Village.Data->ShowEmpireStats ?
+        "Available" : "Unavailable");
+      rputs(szString);
+*/
+
+    // == 0 means game in progress
+    if (Game.Data->GameState == 0)
+    {
+      sprintf(szString, ST_VSTATS8, DaysBetween(Game.Data->szDateGameStart, System.szTodaysDate),
+        Game.Data->szDateGameStart, "Disabled");
+      rputs(szString);
+    }
+    else if (Game.Data->GameState == 1)
+    {
+      if (Game.Data->szDateGameStart[0] != 0)
+      {
+        sprintf(szString, ST_VSTATS9, Game.Data->szDateGameStart);
+        rputs(szString);
+      }
+      else
+        rputs(ST_VSTATS10);
+    }
+
+    rputs(ST_LONGDIVIDER);
+    door_pause();
+  }
+
+
+  void ClanStats ( struct clan *Clan, BOOL AllowModify )
+    /*
+     * Shows stats for given Clan with option to modify values.
+     */
+  {
+    _INT16 iTemp, TotalItems, ItemsShown, Length, iTemp2;
+    char szString[160], szStats[160];
+    BOOL DoneLooking = FALSE;
+    char szShortName[25], cKey;
+
+    /* show stats for clan */
+
+    while (DoneLooking == FALSE)
+    {
+      od_clr_scr();
+
+      // sprintf(szString, ST_CSTATS0, Clan->szName, Clan->ClanID[0], Clan->ClanID[1]);
+      // using color sprintf(szString, ST_CSTATS0, Clan->szName, Clan->Color, Clan->Symbol);
+      sprintf(szString, ST_CSTATS0, Clan->szName, Clan->Symbol);
+      rputs(szString);
+
+      rputs(ST_LONGDIVIDER);
+      sprintf(szString, ST_CSTATS1, Clan->szDateOfLastGame);
+      rputs(szString);
+
+      sprintf(szString, ST_CSTATS2, Clan->Empire.VaultGold);
+      rputs(szString);
+
+      sprintf(szString, ST_CSTATS3, Clan->MineLevel);
+      rputs(szString);
+
+      /* members */
+      for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      {
+        if (Clan->Member[iTemp])
+        {
+          strcpy(szShortName, Clan->Member[iTemp]->szName);
+          szShortName[8] = 0;
+          sprintf(szString, " |0P(|0Q%d|0P) |0L%-8s |0M%3d /%3d HP   ", iTemp+1, szShortName, Clan->Member[iTemp]->HP, Clan->Member[iTemp]->MaxHP);
+          rputs(szString);
+
+          /* show race/class */
+          if (Clan->Member[iTemp]->WhichRace != -1)
+            sprintf(szString, "|0N%s/%s  ", Races[Clan->Member[iTemp]->WhichRace]->szName, PClasses[Clan->Member[iTemp]->WhichClass]->szName);
+          else
+            strcpy(szString, "|0N[unknown]  ");
+
+          /* add or remove spaces to filler it */
+          if (strlen(szString) > 20)
+          {
+            szString[20] = 0;
+          }
+          else
+          {
+            /* add spaces */
+            szString[20] = 0;
+            Length = strlen(szString);
+            for (iTemp2 = 19; iTemp2 >= Length; iTemp2--)
+              szString[iTemp2] = ' ';
+          }
+          rputs(szString);
+
+          /* show items that guys has, if any */
+          TotalItems = 0;
+          if (Clan->Member[iTemp]->Weapon)
+            TotalItems++;
+          if (Clan->Member[iTemp]->Armor)
+            TotalItems++;
+          if (Clan->Member[iTemp]->Shield)
+            TotalItems++;
+
+          if (TotalItems > 0)
+          {
+            strcpy(szStats, "|0O(");  /* begin stats */
+
+            ItemsShown = 0;
+
+            /* show first item */
+            if (Clan->Member[iTemp]->Weapon)
+            {
+              sprintf(szString, "%s", Clan->Items[ Clan->Member[iTemp]->Weapon - 1].szName);
+              strcat(szStats, szString);
+
+              ItemsShown++;
+
+              if (TotalItems > ItemsShown)
+                strcat(szStats, ", ");
+            }
+
+            if (Clan->Member[iTemp]->Armor)
+            {
+              sprintf(szString, "%s", Clan->Items[ Clan->Member[iTemp]->Armor - 1].szName);
+              strcat(szStats, szString);
+
+              ItemsShown++;
+
+              if (TotalItems > ItemsShown)
+                strcat(szStats, ", ");
+            }
+
+            if (Clan->Member[iTemp]->Shield)
+            {
+              sprintf(szString, "%s", Clan->Items[ Clan->Member[iTemp]->Shield - 1].szName);
+              strcat(szStats, szString);
+
+              ItemsShown++;
+            }
+            /* truncate it */
+            szStats[36] = 0;
+            strcat(szStats, ")\n");
+
+            rputs(szStats);
+          }
+          else
+            rputs("|0O(Nothing equipped)\n");
+        }
+      }
+
+      rputs("\n");
+
+      /* show army stats */
+      sprintf(szString, ST_CSTATS5, Clan->Empire.Army.Followers);
+      rputs(szString);
+
+      if (Clan->Protection)
+      {
+        sprintf(szString, "|0L This clan will remain in protection for %d more day(s)\n", Clan->Protection);
+        rputs(szString);
+      }
+
+      rputs(ST_LONGDIVIDER);
+      rputs(ST_CSTATS4);
+
+      switch(cKey = od_get_answer("123456I\r\nQASV E"))
+      {
+        case '1' :  // first member
+        case '2' :  // first member
+        case '3' :  // first member
+        case '4' :  // first member
+        case '5' :  // first member
+        case '6' :  // first member
+          if (Clan->Member[ cKey - '1' ] == NULL)
+            break;
+          ShowPlayerStats(Clan->Member[ cKey - '1'], AllowModify);
+          if (AllowModify == FALSE)
+            door_pause();
+          break;
+        case 'E' :  // empire stats
+          rputs("Empire\n\n");
+          if (Game.Data->ClanEmpires == TRUE)
+          {
+            if (AllowModify == FALSE)
+              rputs("You are unable to find any info on that.\n%P");
+            else
+              Empire_Stats(&Clan->Empire);
+          }
+          else
+            rputs("Clan Empires disabled.\n%P");
+          break;
+        case ' ' :
+        case 'Q' :
+        case '\n' :
+        case '\r' :
+          DoneLooking = TRUE;
+          break;
+        case 'I' :
+          rputs("Inventory\n\n");
+          ListItems(Clan);
+          if (AllowModify)
+            ItemStats();
+          else
+            door_pause();
+          break;
+        case 'A' :  /* alliances */
+          rputs("Allies\n\n");
+
+          /* show alliances */
+          ShowAlliances( Clan );
+          break;
+        case 'S' :  /* change symbol */
+          rputs("Symbol\n\n");
+
+          if (AllowModify == FALSE)
+          {
+            sprintf(szString, "|0GClan's current symbol is %s\n\n", Clan->Symbol);
+            rputs(szString);
+            door_pause();
+            break;
+          }
+
+          if (Clan->Symbol[0] == 0)
+          {
+            rputs("|0SYour clan has not yet chosen a symbol\n\n");
+            Help("Clan Symbol", ST_CLANSHLP);
+            rputs("\n%P");
+          }
+          else
+          {
+            rputs("Clan Symbol\n\n");
+            // sprintf(szString, "|0SYour current symbol is |%02d%s\n\n", Clan->Color, Clan->Symbol);
+            sprintf(szString, "|0SYour current symbol is %s\n\n", Clan->Symbol);
+            rputs(szString);
+          }
+
+          rputs("|0SPlease type your new symbol or press enter to keep it the same\n|0E> |0F");
+          GetStr(Clan->Symbol, 20, TRUE);
+
+          sprintf(szString, "|0SYour clan symbol is now %s\n\n", Clan->Symbol);
+          rputs(szString);
+          door_pause();
+          break;
+        case 'V' :  /* Village stats */
+          ShowVillageStats();
+          break;
+      }
+    }
+    rputs("%C");
+  }
+
+
+  void PC_Create( struct pc *PC, BOOL ClanLeader )
+    /*
+     * Used to create a new PC.
+     */
+  {
+    char szString[128];
+    _INT16 iTemp, LastSpellSlot;
+
+    for (;;)
+    {
+      // rputs("|11Please choose a race for this character.\n");
+      rputs(ST_STUFF6);
+      PC->WhichRace = GetClass(Races, "Races");
+      // rputs("|11Please choose a class for this character.\n");
+      rputs(ST_STUFF7);
+      PC->WhichClass = GetClass(PClasses, "Classes");
+
+      /* init stats */
+      for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+        PC->Attributes[iTemp] = Races[ PC->WhichRace ]->Attributes[iTemp];
+
+      PC->MaxHP = Races[ PC->WhichRace ]->MaxHP;
+      if (ClanLeader)
+        PC->MaxHP += RANDOM(10);
+
+      PC->MaxSP = Races[ PC->WhichRace ]->MaxSP;
+
+      for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+        PC->Attributes[iTemp] += PClasses[ PC->WhichClass ]->Attributes[iTemp];
+
+      PC->MaxHP += PClasses[ PC->WhichClass ]->MaxHP;
+      PC->MaxSP += PClasses[ PC->WhichClass ]->MaxSP;
+      PC->Difficulty = -1;  // no difficulty
+
+      /* randomize stats a bit */
+      for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+        PC->Attributes[iTemp] += RANDOM(1);
+
+      // if clan leader, add on some random stats
+      if (ClanLeader)
+        for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+          PC->Attributes[iTemp] += RANDOM(3);
+
+      PC->MaxHP += RANDOM(5);
+      PC->MaxSP += RANDOM(5);
+      PC->HP = PC->MaxHP;
+      PC->SP = PC->MaxSP;
+
+      PC->Weapon = 0;
+      PC->Armor = 0;
+      PC->Shield = 0;
+      PC->Status = Here;
+      PC->Experience = 0;
+      PC->Level = 0;
+      PC->TrainingPoints = 0;
+
+      /* no spells known */
+      for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+        PC->SpellsKnown[iTemp] = 0;
+
+      /* "give" him spells from his race */
+      for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      {
+        if (Races[ PC->WhichRace ]->SpellsKnown[iTemp] == 0)
+          break;
+
+        PC->SpellsKnown[iTemp] = Races[ PC->WhichRace ]->SpellsKnown[iTemp];
+      }
+      LastSpellSlot = iTemp;
+      for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      {
+        if (PClasses[ PC->WhichClass ]->SpellsKnown[iTemp] == 0)
+          break;
+
+        PC->SpellsKnown[LastSpellSlot + iTemp] = PClasses[ PC->WhichClass ]->SpellsKnown[iTemp];
+      }
+      PC->DefaultAction = 0;
+
+      /* show stats */
+      // rputs("|13Stats generated for this player\n");
+      rputs(ST_STUFF8);
+
+      strcpy(PC->szName, "New Player");
+
+      /* set all spells to 0 */
+      for (iTemp = 0; iTemp < 10; iTemp++)
+        PC->SpellsInEffect[iTemp].SpellNum = -1;
+
+      ShowPlayerStats(PC, FALSE);
+
+      /* are these ok? */
+      if (YesNo("|03Use these stats?") == YES)
+        break;
+    }
+
+    /* ask for name */
+    for (;;)
+    {
+      // rputs("\n|02Enter the name of this member\n|10> |07");
+      rputs(ST_STUFF9);
+
+      szString[0] = 0;
+      GetStr(szString, 12, FALSE);
+
+      RemovePipes(szString, PC->szName);
+      Strip(PC->szName);
+
+      if (PC->szName[0] == 0)
+        continue;
+      else
+        break;
+    }
+
+    PC->MyClan = PClan;
+    PC->Undead = FALSE;
+    PC->DefaultAction = 0;
+
+    // sprintf(szString, |10%s joins the clan.\n%%P, PC->szName);
+    sprintf(szString, ST_STUFF10, PC->szName);
+    rputs(szString);
+  }
+
+
+  BOOL NameInUse ( char *szName )
+    /*
+     * Returns true if the given Clan name is already in use.
+     */
+  {
+    FILE *fpPCFile;
+    struct clan *TmpClan;
+    _INT16 CurClan = 0;
+    long Offset;
+
+    fpPCFile = fopen(ST_CLANSPCFILE, "rb");
+    if (fpPCFile)
+    {
+      TmpClan = malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+
+      /* go through list */
+      for (CurClan = 0;; CurClan++)
+      {
+        Offset = (long) CurClan * ((long)sizeof(struct clan) + 6L*sizeof(struct pc));
+        if (fseek(fpPCFile, Offset, SEEK_SET))
+          break;  /* couldn't fseek, so exit */
+
+        if (EncryptRead(TmpClan, sizeof(struct clan), fpPCFile, XOR_USER) == 0)
+          break;  /* stop reading if no more players found */
+
+        /* see if this player has same name as user online */
+        /* strip names */
+        if (stricmp(szName, TmpClan->szName) == 0)
+        {
+          /* are the same, found another player with name, close file */
+          fclose(fpPCFile);
+          free(TmpClan);
+          return TRUE;
+        }
+      }
+
+      /* no players found with same name */
+      fclose(fpPCFile);
+
+      free(TmpClan);
+    }
+
+    // look through names list to see if that name is in use
+    if (Game.Data->InterBBS && IBBS_InList(szName, TRUE))
+    {
+      // found this clanname in the list of clannames of the league
+      // don't allow him to use it
+      return TRUE;
+    }
+
+    return FALSE;
+  }
+
+  BOOL ChooseClanName ( char *szName )
+    /*
+     * Allows user to choose a clan name.
+     */
+  {
+    char szString[30];
+
+    for (;;)
+    {
+      // rputs("\n|02What will you call your clan?\n|10> |07");
+      rputs(ST_STUFF3);
+      szString[0] = 0;
+      GetStr(szString, 24, FALSE);
+
+      RemovePipes(szString, szName);
+      Strip(szName);
+
+      if (szName[0] == 0)
+      {
+        rputs(ST_ABORTED);
+        return FALSE;
+      }
+
+      if (szName[0] == '?')
+      {
+        rputs("|12Invalid name!\n");
+      }
+
+      /* see if that name is in use */
+      else if (NameInUse(szName) == FALSE)
+      {
+        rputs("|0F");
+        rputs(szName);
+        if (YesNo("|16|0E : |0SUse this name?") == YES)
+        {
+          return TRUE;
+        }
+        rputs("\n");
+      }
+      else
+      {
+        rputs("|12That name is in use, please choose again.\n\n");
+      }
+    }
+  }
+
+
+  void User_ResetHelp ( void )
+    /*
+     * Resets help database for clan
+     */
+  {
+    PClan->DefActionHelp = FALSE;
+    PClan->CommHelp      = FALSE;
+    PClan->MineHelp      = FALSE;
+    PClan->MineLevelHelp = FALSE;
+    PClan->CombatHelp    = FALSE;
+    PClan->TrainHelp     = FALSE;
+    PClan->MarketHelp    = FALSE;
+    PClan->PawnHelp      = FALSE;
+    PClan->WizardHelp    = FALSE;
+    PClan->EmpireHelp    = FALSE;
+    PClan->DevelopHelp   = FALSE;
+  }
+
+  BOOL User_Create ( void )
+    /*
+     * Creates a new clan for the player.
+     */
+  {
+    FILE *fpPlayerFile;
+    struct pc *TmpPC;
+    struct UserInfo User;
+    _INT16 iTemp;
+    char szString[128];
+
+    strcpy(PClan->szUserName, od_control.user_name);
+
+    Help("Welcome", ST_CLANSHLP);
+
+    // (YesNo("|0SDo you wish to join this game of clans?") == NO)
+    if (YesNo(ST_STUFF1) == NO)
+    {
+      rputs(ST_ABORTED);
+      return FALSE;
+    }
+
+    if (!ChooseClanName(PClan->szName))
+      return FALSE;
+
+
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+
+    // initialize clan data
+    PClan->Symbol[0] = 0;
+
+    for (iTemp = 0; iTemp < 8; iTemp++)
+    {
+      PClan->QuestsDone[iTemp] = 0;
+      PClan->QuestsKnown[iTemp] = 0;
+    }
+
+    PClan->WorldStatus = WS_STAYING;
+    PClan->DestinationBBS = -1;
+
+    PClan->Points = 0;
+    strcpy(PClan->szDateOfLastGame, System.szTodaysDate);
+
+    // Reset help database for him
+    User_ResetHelp();
+
+    PClan->QuestToday = FALSE;
+    PClan->VaultWithdrawals = 0;
+    PClan->AttendedMass = FALSE;
+    PClan->GotBlessing = FALSE;
+    PClan->Prayed = FALSE;
+    PClan->FightsLeft = Game.Data->MineFights;
+    PClan->ClanFights = Game.Data->ClanFights;
+    PClan->WasRulerToday = FALSE;
+    PClan->ClanWars = 0;
+    PClan->ChatsToday = 0;
+    ClearFlags(PClan->PFlags);
+    ClearFlags(PClan->DFlags);
+    PClan->ResUncToday = 0;
+    PClan->ResDeadToday = 0;
+    PClan->MineLevel = 1;
+    PClan->PublicMsgIndex = 0;
+    PClan->MadeAlliance = FALSE;
+    PClan->Eliminated = FALSE;
+    PClan->WasRulerToday = FALSE;
+    PClan->FirstDay = TRUE;
+    PClan->Protection = Game.Data->DaysOfProtection;
+
+    PClan->Empire.VaultGold = 0;
+    PClan->TradesToday = 0;
+    PClan->ClanRulerVote[0] = -1;
+    PClan->ClanRulerVote[1] = -1;
+
+    // initialize empire
+
+    // set up no alliances
+    for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+      PClan->Alliances[iTemp] = -1;
+
+    /* NULL-pointer each member of clan for now */
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      PClan->Member[iTemp] = NULL;
+
+    for (iTemp = 0; iTemp < MAX_ITEMS_HELD; iTemp++)
+      PClan->Items[iTemp].Available = FALSE;
+
+
+    // Figure out ID
+    PClan->ClanID[0] = Config->BBSID;
+    PClan->ClanID[1] = Game.Data->NextClanID;
+    Game.Data->NextClanID++;
+
+    // init empire
+    Empire_Create(&PClan->Empire, TRUE);
+    strcpy(PClan->Empire.szName, PClan->szName);
+    PClan->Empire.OwnerType = EO_CLAN;
+    PClan->Empire.AllianceID = -1;
+
+    // Create the players
+    for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+    {
+      od_clr_scr();
+
+      // creating clansmen x of
+      sprintf(szString, ST_STUFF5, iTemp + 1, Game.Data->MaxPermanentMembers);
+      rputs(szString);
+
+      if (iTemp == 0)
+      {
+        /* first clansman is the "leader" of the four */
+        Help("Clan Leader", ST_NEWBIEHLP);
+        rputs("\n%P");
+      }
+
+      if (iTemp == 0)
+        PC_Create(TmpPC, TRUE);
+      else
+        PC_Create(TmpPC, FALSE);
+
+
+      PClan->Member[iTemp] = malloc(sizeof(struct pc));
+      CheckMem(PClan->Member[iTemp]);
+      *PClan->Member[iTemp] = *TmpPC;
+
+      // give 'em gold dude
+      PClan->Empire.VaultGold  += PClasses[ TmpPC->WhichClass ]->Gold;
+      PClan->Empire.VaultGold += Races[ TmpPC->WhichRace ]->Gold;
+    }
+
+    /* open player file for append */
+    fpPlayerFile = _fsopen(ST_CLANSPCFILE, "r+b", SH_DENYRW);
+    if (!fpPlayerFile)
+    {
+      fpPlayerFile = _fsopen(ST_CLANSPCFILE, "wb", SH_DENYRW);
+      if (!fpPlayerFile)
+      {
+        // !!!
+        // DisplayStr("User_Create: creating new file\n");
+        /* !!! */
+        rputs("!! Chkpt 1\n");
+        rputs(ST_ERRORPC);
+        free(TmpPC);
+        return FALSE;
+      }
+    }
+    else
+    {
+      // !!!
+      // DisplayStr("User_Create: appending to file\n");
+      fseek(fpPlayerFile, 0L, SEEK_END);
+    }
+
+    // figure out CRC first
+    PClan->CRC = CRCValue(PClan, sizeof(struct clan) - sizeof(long));
+
+    /* write it to file */
+    EncryptWrite(PClan, sizeof(struct clan), fpPlayerFile, XOR_USER);
+    for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+    {
+      PClan->Member[iTemp]->CRC = CRCValue(PClan->Member[iTemp], sizeof(struct pc) - sizeof(long));
+
+      EncryptWrite(PClan->Member[iTemp], sizeof(struct pc), fpPlayerFile, XOR_PC);
+    }
+
+    /* write null players to complete it */
+    TmpPC->szName[0] = 0;
+    TmpPC->Status = Dead;
+    for (iTemp = Game.Data->MaxPermanentMembers; iTemp < 6; iTemp++)
+    {
+      TmpPC->CRC = CRCValue(TmpPC, sizeof(struct pc) - sizeof(long));
+
+      EncryptWrite(TmpPC, sizeof(struct pc), fpPlayerFile, XOR_PC);
+    }
+
+    fclose(fpPlayerFile);
+
+    // !!!
+    // DisplayStr("User_Create: done writing to file\n%P");
+
+    free(TmpPC);
+
+    /* write news */
+    sprintf(szString, ST_NEWSNEWCLAN, PClan->szName);
+    News_AddNews(szString);
+
+
+    // add to league
+    if (Game.Data->InterBBS)
+    {
+      User.ClanID[0] = PClan->ClanID[0];
+      User.ClanID[1] = PClan->ClanID[1];
+      strcpy(User.szMasterName, PClan->szUserName);
+      strcpy(User.szName, PClan->szName);
+      User.Deleted = FALSE;
+      IBBS_LeagueNewUser(&User);
+    }
+
+
+
+    return TRUE;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void User_Destroy ( void )
+    /*
+     * Destroys the clan in memory.
+     */
+  {
+    _INT16 iTemp;
+
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      if (PClan->Member[iTemp])
+        free(PClan->Member[iTemp]);
+
+    free(PClan);
+    User.Initialized = FALSE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void CopyPC( struct pc *PCDest, struct pc *PCSrc )
+  {
+    _INT16 iTemp;
+
+    strcpy(PCDest->szName, PCSrc->szName);
+    PCDest->HP = PCSrc->HP;
+    PCDest->SP = PCSrc->SP;
+    PCDest->MaxHP = PCSrc->MaxHP;
+    PCDest->MaxSP = PCSrc->MaxSP;
+
+    /* copy all attributes */
+    for (iTemp = 0; iTemp < NUM_ATTRIBUTES; iTemp++)
+      PCDest->Attributes[iTemp] = PCSrc->Attributes[iTemp];
+
+    PCDest->Status = PCSrc->Status;
+    PCDest->Weapon = PCSrc->Weapon;
+    PCDest->Shield = PCSrc->Shield;
+    PCDest->Armor = PCSrc->Armor;
+    PCDest->MyClan = PCSrc->MyClan;
+    PCDest->WhichRace = PCSrc->WhichRace;
+    PCDest->WhichClass = PCSrc->WhichClass;
+    PCDest->Experience = PCSrc->Experience;
+    PCDest->Level = PCSrc->Level;
+    PCDest->TrainingPoints = PCSrc->TrainingPoints;
+    PCDest->Difficulty = PCSrc->Difficulty;
+    PCDest->Undead = PCSrc->Undead;
+    PCDest->DefaultAction = PCSrc->DefaultAction;
+
+    PCDest->CRC = PCSrc->CRC;
+
+    for (iTemp = 0; iTemp < MAX_SPELLS; iTemp++)
+      PCDest->SpellsKnown[iTemp] = PCSrc->SpellsKnown[iTemp];
+
+    for (iTemp = 0; iTemp < 10; iTemp++)
+      PCDest->SpellsInEffect[iTemp] = PCSrc->SpellsInEffect[iTemp];
+  }
+
+  BOOL User_Read ( void )
+    /*
+     * Reads the PClan from file which corresponds to the user online.
+     * Returns FALSE if clan was not found (i.e. not in game yet)
+     */
+  {
+    // search for user which matches current user logged in
+
+    FILE *fpPlayerFile;
+    struct clan *TmpClan;
+    struct pc *TmpPC;
+    _INT16 CurClan, CurMember, iTemp;
+    long Offset;
+
+    fpPlayerFile = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYRW);
+    if (!fpPlayerFile)
+    {
+      /* file not found, so clan not found! */
+      return FALSE;
+    }
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+    for (CurClan = 0;;CurClan++)
+    {
+      /* seek to the current player */
+      Offset = (long) CurClan * ((long)sizeof(struct clan) + 6L*sizeof(struct pc));
+
+      if (fseek(fpPlayerFile, Offset, SEEK_SET))
+        break;  /* couldn't fseek, so exit */
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+        break;  /* stop reading if no more players found */
+
+      // !!!
+      // DisplayStr("Read in "); DisplayStr(TmpClan->szUserName); DisplayStr("\n");
+      // getch();
+
+      /* see if this player has same name as user online */
+      if (stricmp(od_control.user_name, TmpClan->szUserName) == 0)
+      {
+
+        /* are the same, found player, copy it, return TRUE */
+        *PClan = *TmpClan;
+
+        /* read in the other guys, members, etc. */
+        for (CurMember = 0; CurMember < MAX_MEMBERS; CurMember++)
+          PClan->Member[CurMember] = NULL;
+
+        for (CurMember = 0; CurMember < 6; CurMember++)
+        {
+          /* read 'em in */
+          EncryptRead(TmpPC, sizeof(struct pc), fpPlayerFile, XOR_PC);
+
+          // [0] != 0 if member exists
+          if (TmpPC->szName[0])
+          {
+            PClan->Member[CurMember] = malloc(sizeof (struct pc));
+            CheckMem(PClan->Member[CurMember]);
+
+            // CopyPC(PClan->Member[CurMember], TmpPC);
+            *PClan->Member[CurMember] = *TmpPC;
+            PClan->Member[CurMember]->MyClan = PClan;
+
+            /* set all spells to 0 */
+            for (iTemp = 0; iTemp < 10; iTemp++)
+              PClan->Member[CurMember]->SpellsInEffect[iTemp].SpellNum = -1;
+
+          }
+        }
+
+        fclose(fpPlayerFile);
+        free(TmpClan);
+        free(TmpPC);
+        return TRUE;
+      }
+
+    }
+
+    /* was not found, so return FALSE) */
+    fclose(fpPlayerFile);
+
+    free(TmpClan);
+    free(TmpPC);
+
+    return FALSE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Clan_Update ( struct clan *Clan )
+    /*
+     * Writes Clan to file in the appropriate place.
+     *
+     * PRE: Clan MUST already reside in the .PC file!
+     */
+  {
+    FILE *fpPlayerFile;
+    _INT16 CurClan, iTemp;
+    long OldOffset, Offset;
+    struct clan *TmpClan;
+    struct pc *TmpPC;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+    TmpPC = malloc(sizeof(struct pc));
+    CheckMem(TmpPC);
+
+    fpPlayerFile = fopen(ST_CLANSPCFILE, "r+b");
+    if (!fpPlayerFile)
+    {
+        /* !! */
+        rputs("!! Chkpt 2\n");
+        rputs(ST_ERRORPC);
+        free(TmpClan);
+        free(TmpPC);
+        return;  /* failed to find clan */
+    }
+
+    for (CurClan = 0;; CurClan++)
+    {
+      /* go through file till you find clan he wants */
+
+      Offset = (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc));
+      if (fseek(fpPlayerFile, Offset, SEEK_SET))
+        break;  /* couldn't fseek, so exit */
+
+      OldOffset = ftell(fpPlayerFile);
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+        break;  /* stop reading if no more players found */
+
+      /* skip if deleted clan */
+      if (TmpClan->ClanID[0] == -1)
+        continue;
+
+      /* if same Ids, seek back and write to file */
+      if (TmpClan->ClanID[0] == Clan->ClanID[0] &&
+          TmpClan->ClanID[1] == Clan->ClanID[1])
+      {
+        fseek(fpPlayerFile, OldOffset, SEEK_SET);
+
+        Clan->CRC = CRCValue(Clan, sizeof(struct clan) - sizeof(long));
+        EncryptWrite(Clan, sizeof(struct clan), fpPlayerFile, XOR_USER);
+
+        // fwrite(Clan, sizeof(struct clan), 1, fpPlayerFile);
+
+        // fwrite players
+        TmpPC->szName[0] = 0;
+        TmpPC->Status = Dead;
+        TmpPC->CRC = CRCValue(TmpPC, sizeof(struct pc) - sizeof(long));
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          if (Clan->Member[iTemp] && Clan->Member[iTemp]->Undead == FALSE)
+          {
+            Clan->Member[iTemp]->CRC = CRCValue(Clan->Member[iTemp], sizeof(struct pc) - sizeof(long));
+            EncryptWrite(Clan->Member[iTemp], sizeof(struct pc), fpPlayerFile, XOR_PC);
+
+            // fwrite(Clan->Member[iTemp], sizeof(struct pc), 1, fpPlayerFile);
+          }
+          else
+            EncryptWrite(TmpPC, sizeof(struct pc), fpPlayerFile, XOR_PC);
+            // fwrite(TmpPC, sizeof(struct pc), 1, fpPlayerFile);
+        }
+        break;
+      }
+    }
+    fclose(fpPlayerFile);
+
+    free(TmpPC);
+    free(TmpClan);
+
+  }
+
+
+  void User_Write ( void )
+    /*
+     * The current user online is written to file.
+     *
+     * PRE: User has been written to file already once.
+     */
+  {
+
+    // updates the current user information to file
+    if (User.Initialized)
+    {
+      Clan_Update(PClan);
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void User_FirstTimeToday ( void )
+    /*
+     * Run whenever user plays first time that day.
+     *
+     */
+  {
+    _INT16 iTemp;
+
+    PClan->Points += 25;
+
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (PClan->Member[iTemp] && PClan->Member[iTemp]->Status != Dead)
+      {
+        PClan->Member[iTemp]->HP = PClan->Member[iTemp]->MaxHP;
+        PClan->Member[iTemp]->SP = PClan->Member[iTemp]->MaxSP;
+
+        if (PClan->Member[iTemp]->Status == Unconscious)
+          PClan->Member[iTemp]->Status = Here;
+      }
+    }
+
+    strcpy(PClan->szDateOfLastGame, System.szTodaysDate);
+  }
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 NumMembers ( struct clan *Clan, BOOL OnlyOnesHere )
+    /*
+     * Returns the number of members in the clan.
+     *
+     * PRE: OnlyOnesHere is TRUE if only the alive members are to be checked.
+     */
+  {
+    _INT16 iTemp;
+    _INT16 Members = 0;
+
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+    {
+      if (Clan->Member[iTemp])
+      {
+        if (OnlyOnesHere && Clan->Member[iTemp]->Status != Here)
+          continue;
+
+        Members++;
+      }
+    }
+
+    return Members;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  BOOL GetClanID ( _INT16 ID[2], BOOL OnlyLiving, BOOL IncludeSelf,
+                   _INT16 WhichAlliance, BOOL InAllianceOnly )
+  {
+    FILE *fpPlayerFile;
+    /*char szFragName[30], szString[128];*/
+    char *apszClanNames[50];
+    _INT16 CurClan, ClanIDs[50][2], WhichClan, NumClans, *ClanIndex, iTemp;
+    BOOL AllianceFound;
+    struct clan *TmpClan;
+    struct pc *TmpPC;
+    BOOL FoundClan = FALSE, AtLeastOneLiving = FALSE;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    for (CurClan = 0; CurClan < 50; CurClan++)
+      apszClanNames[CurClan] = NULL;
+
+    ClanIndex = malloc(sizeof(_INT16)*50);
+    CheckMem(ClanIndex);
+
+    // get list of all clan names from file, write to
+    NumClans = 0;
+    for (CurClan = 0; CurClan < 50; CurClan++)
+    {
+      fpPlayerFile = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYRW);
+      if (!fpPlayerFile)
+      {
+        /* !! */
+        rputs("!! Chkpt 3\n");
+        rputs(ST_ERRORPC);
+        break;
+      }
+      if (fseek(fpPlayerFile, (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET))
+      {
+        fclose(fpPlayerFile);
+        break;  /* couldn't fseek, so exit */
+      }
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+      {
+        fclose(fpPlayerFile);
+        break;  /* stop reading if no more players found */
+      }
+
+      // see if any of the members are alive
+      if (OnlyLiving)
+      {
+        TmpPC = malloc(sizeof(struct pc));
+        CheckMem(TmpPC);
+
+        AtLeastOneLiving = FALSE;
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          EncryptRead(TmpPC, sizeof(struct pc), fpPlayerFile, XOR_PC);
+
+          if (TmpPC->szName[0] && TmpPC->Status == Here)
+          {
+            AtLeastOneLiving = TRUE;
+            break;
+          }
+        }
+        free(TmpPC);
+      }
+
+      fclose(fpPlayerFile);
+
+      /* skip if deleted clan or eliminated */
+      if (TmpClan->ClanID[0] == -1)
+        continue;
+
+      /* skip if your clan */
+      if (IncludeSelf == FALSE &&
+          TmpClan->ClanID[0] == PClan->ClanID[0] &&
+          TmpClan->ClanID[1] == PClan->ClanID[1])
+        continue;
+
+      /* skip if not in alliance and alliance used */
+      if (WhichAlliance != -1)
+      {
+        AllianceFound = FALSE;
+        for (iTemp = 0; iTemp < MAX_ALLIES; iTemp++)
+        {
+          if (TmpClan->Alliances[iTemp] == WhichAlliance)
+          {
+            AllianceFound = TRUE;
+            break;
+          }
+        }
+        // not in alliance so skip AND we want in alliance only
+        if (!AllianceFound && InAllianceOnly)
+          continue;
+
+        // skip also if we don't want those in the alliance to be listed
+        else if (AllianceFound && !InAllianceOnly)
+          continue;
+      }
+
+      // skip if no one alive
+      if (AtLeastOneLiving == FALSE && OnlyLiving)
+        continue;
+
+      apszClanNames[NumClans] = malloc(strlen(TmpClan->szName) + 1);
+      CheckMem(apszClanNames[NumClans]);
+      strcpy(apszClanNames[NumClans], TmpClan->szName);
+
+      // add to our list
+      ClanIDs[NumClans][0] = TmpClan->ClanID[0];
+      ClanIDs[NumClans][1] = TmpClan->ClanID[1];
+
+      NumClans++;
+    }
+
+    if (NumClans != 0)
+      GetStringChoice(apszClanNames, NumClans,
+        "|0SEnter the name of the clan\n|0E> |0F",
+        &WhichClan, TRUE, DT_WIDE, TRUE);
+    else
+    {
+      rputs("No clans found!\n");
+      WhichClan = -1;
+    }
+
+    if (WhichClan == -1)
+    {
+      FoundClan = FALSE;
+      rputs(ST_ABORTED);
+    }
+    else
+    {
+      FoundClan = TRUE;
+      ID[0] = ClanIDs[ WhichClan ][0];
+      ID[1] = ClanIDs[ WhichClan ][1];
+    }
+
+    for (CurClan = 0; CurClan < 50; CurClan++)
+    {
+      // free up clan names
+      if (apszClanNames[CurClan])
+        free(apszClanNames[CurClan]);
+    }
+
+    free(TmpClan);
+    free(ClanIndex);
+
+    return FoundClan;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  BOOL GetClanNameID( char *szName, _INT16 ID[2] )
+  {
+    FILE *fpPlayerFile;
+/*    char szString[255];*/
+    _INT16 CurClan = 0;
+    BOOL FoundClan = FALSE;
+    struct clan *TmpClan;
+
+    szName[0] = 0;
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    for (;;)
+    {
+      /* go through file till you find clan he wants */
+
+      fpPlayerFile = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYRW);
+      if (!fpPlayerFile)
+      {
+        free(TmpClan);
+        return FALSE;  /* means failed to find clan */
+      }
+      if (fseek(fpPlayerFile, (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET))
+      {
+        fclose(fpPlayerFile);
+        break;  /* couldn't fseek, so exit */
+      }
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+      {
+        fclose(fpPlayerFile);
+        break;  /* stop reading if no more players found */
+      }
+
+      fclose(fpPlayerFile);
+
+      /* see if name is the one */
+      if (TmpClan->ClanID[0] == ID[0] && TmpClan->ClanID[1] == ID[1])
+      {
+        /* found it! */
+        strcpy(szName, TmpClan->szName);
+        FoundClan = TRUE;
+        break;
+      }
+
+      CurClan++;
+    }
+
+    free(TmpClan);
+    return FoundClan;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  BOOL GetClan ( _INT16 ClanID[2], struct clan *TmpClan )
+  {
+    FILE *fpPlayerFile;
+    _INT16 ClanNum, iTemp;
+    char szFileName[50];
+    BOOL FoundClan = FALSE;
+
+    // make them all NULLs for safety
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      TmpClan->Member[iTemp] = NULL;
+
+    strcpy(szFileName, ST_CLANSPCFILE);
+
+    /* find guy in file */
+    fpPlayerFile = fopen(szFileName, "rb");
+    if (!fpPlayerFile)
+    {
+      return FALSE;     /* means failed to find clan */
+    }
+
+    for (ClanNum = 0;; ClanNum++)
+    {
+      if (fseek(fpPlayerFile, (long)ClanNum * (sizeof(struct clan) + 6L*sizeof(struct pc)), SEEK_SET))
+      {
+        // couldn't find clan in file
+        fclose(fpPlayerFile);
+        return FALSE;
+      }
+
+      if (!EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER))
+      {
+        fclose(fpPlayerFile);
+        for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+          TmpClan->Member[iTemp] = NULL;
+        return FALSE;
+      }
+
+      // if CRCs don't match, warn for now
+//    if (TmpClan->CRC != CRCValue(TmpClan, sizeof(TmpClan)) )
+//      DisplayStr("|12-> CRCs don't match!!\n");
+
+      // make them all NULLs for safety
+      for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+        TmpClan->Member[iTemp] = NULL;
+
+      if (TmpClan->ClanID[0] == ClanID[0] && TmpClan->ClanID[1] == ClanID[1])
+      {
+        /* found it */
+        FoundClan = TRUE;
+
+        /* read in PCs */
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          TmpClan->Member[iTemp] = malloc(sizeof(struct pc));
+          CheckMem(TmpClan->Member[iTemp]);
+          EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fpPlayerFile, XOR_PC);
+
+          /* skip those members which are non-existant */
+          if (TmpClan->Member[iTemp]->szName[0] == 0)
+          {
+            free(TmpClan->Member[iTemp]);
+            TmpClan->Member[iTemp] = NULL;
+          }
+          else
+            TmpClan->Member[iTemp]->MyClan = TmpClan;
+        }
+        break;
+      }
+    }
+    fclose(fpPlayerFile);
+
+    if (FoundClan)
+      return TRUE;
+    else
+    {
+      // DisplayStr("Bug #2\n%P");
+      return FALSE;
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void User_List ( void )
+  {
+    /* /USER parameter -- displays user list */
+
+    FILE *fpPlayerFile, *fpUserList;
+    struct clan *TmpClan;
+    _INT16 CurClan/*, CurMember, iTemp*/;
+    struct UserInfo User;
+    long Offset;
+
+    printf(ST_USERLISTH);
+
+    if (Game.Data->InterBBS == FALSE)
+    {
+      fpPlayerFile = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYWR);
+      if (!fpPlayerFile)
+      {
+        /* file not found, so clan not found! */
+        return;
+      }
+
+      TmpClan = malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+
+      /* else, file opened properly, so look for player */
+
+      // list local players
+      for (CurClan = 0;;CurClan++)
+      {
+        /* seek to the current player */
+        Offset = (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc));
+        if (fseek(fpPlayerFile, Offset, SEEK_SET))
+          break;  /* couldn't fseek, so exit */
+
+        if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+          break;  /* stop reading if no more players found */
+
+        // print out name etc.
+        printf("%2d|%2d %-20s  %-20s\n", TmpClan->ClanID[0], TmpClan->ClanID[1],
+          TmpClan->szUserName, TmpClan->szName);
+      }
+
+      /* was not found, so return FALSE) */
+      fclose(fpPlayerFile);
+
+      free(TmpClan);
+      TmpClan = NULL;
+    }
+    else
+    {
+      // list interbbs users using USERLIST.DAT
+      fpUserList = _fsopen("userlist.dat", "rb", SH_DENYWR);
+      if (fpUserList)
+      {
+        for (;;)
+        {
+          if (EncryptRead(&User, sizeof(struct UserInfo), fpUserList, XOR_ULIST) == 0)
+            break;
+
+          printf("%2d|%2d %-20s  %-20s\n", User.ClanID[0], User.ClanID[1],
+						User.szMasterName, User.szName);
+        }
+        fclose(fpUserList);
+      }
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void User_Maint ( void )
+    /*
+     * Runs maintenance on all users.
+     *
+     *
+     *
+     */
+  {
+    FILE *fpOldPC, *fpNewPC;
+    struct clan *TmpClan;
+    _INT16 iTemp, iTemp2, CurItem, Level;
+    long XPRequired[MAX_LEVELS];
+
+    DisplayStr("* User_Maint()\n");
+
+    /* figure XP required per level */
+    for (Level = 1; Level < MAX_LEVELS; Level++)
+    {
+      XPRequired[Level] = 50L;
+
+      for (iTemp = 1; iTemp <= Level; iTemp++)
+        XPRequired[Level] += ((long)(iTemp-1)*75L);
+    }
+
+
+    fpOldPC = _fsopen(ST_CLANSPCFILE, "rb", SH_DENYRW);
+    if (fpOldPC)
+    {
+      fpNewPC = _fsopen(ST_NEWPCFILE, "w+b", SH_DENYRW);
+      if (!fpNewPC)
+      {
+        System_Error("New.PC unopenable");
+      }
+
+      /* allocate memory */
+      TmpClan = (struct clan *) malloc(sizeof(struct clan));
+      CheckMem(TmpClan);
+
+      for (;;)
+      {
+        /* go through each clan and write his updated info to new file */
+
+        if (EncryptRead(TmpClan, sizeof(struct clan), fpOldPC, XOR_USER) == 0)
+          break;
+
+        /* skip if deleted */
+        if (TmpClan->ClanID[0] == -1)
+          continue;
+
+        /* FIXME: if over 14 days old, delete */
+        // add to "list" of users who are going to be deleted
+
+        /* update stats needed */
+        TmpClan->FirstDay = FALSE;
+
+        // fix bugs
+        if (TmpClan->Empire.VaultGold < 0)  TmpClan->Empire.VaultGold = 0;
+
+        TmpClan->QuestToday = FALSE;
+        TmpClan->VaultWithdrawals = 0;
+        TmpClan->AttendedMass = FALSE;
+        TmpClan->GotBlessing = FALSE;
+        TmpClan->Prayed = FALSE;
+        TmpClan->FightsLeft = Game.Data->MineFights;
+        TmpClan->ClanFights = Game.Data->ClanFights;
+        TmpClan->WasRulerToday = FALSE;
+        TmpClan->ClanWars = 0;
+        TmpClan->ChatsToday = 0;
+        ClearFlags(TmpClan->DFlags);
+        TmpClan->ResUncToday = 0;
+        TmpClan->ResDeadToday = 0;
+
+        // reduce days of protection
+        if (TmpClan->Protection > 0)
+          TmpClan->Protection--;
+        else
+          TmpClan->Protection = 0;
+        TmpClan->TradesToday = 0;
+
+        Empire_Maint ( &TmpClan->Empire );
+
+        for (iTemp = 0; iTemp < MAX_CLANCOMBAT; iTemp++)
+        {
+          TmpClan->ClanCombatToday[iTemp][0] = -1;
+          TmpClan->ClanCombatToday[iTemp][1] = -1;
+        }
+
+        if (TmpClan->Empire.VaultGold < 0)
+          TmpClan->Empire.VaultGold = 0;
+
+        /* WAS this the ruler and WAS he ousted? */
+        /* REP:
+        if (OustedRuler && OldRulerId[0] == TmpClan->ClanID[0] &&
+          OldRulerId[1] == TmpClan->ClanID[1])
+        {
+          TmpClan->WasRulerToday = TRUE;
+          TmpClan->Points -= 100;
+        }
+        */
+
+        /* is this the current ruler?  If so, give daily points */
+        if (TmpClan->ClanID[0] == Village.Data->RulingClanId[0] &&
+          TmpClan->ClanID[1] == Village.Data->RulingClanId[1])
+        {
+          TmpClan->Points += 25;
+        }
+
+        // read in 6 members
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          TmpClan->Member[iTemp] = malloc(sizeof(struct pc));
+          CheckMem(TmpClan->Member[iTemp]);
+          EncryptRead(TmpClan->Member[iTemp], sizeof(struct pc), fpOldPC, XOR_PC);
+        }
+
+        /* set HP to max */
+        for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+        {
+          /* if player is unconscious, revive him */
+          if (TmpClan->Member[iTemp]->Status == Unconscious ||
+            TmpClan->Member[iTemp]->Status == Here)
+          {
+            TmpClan->Member[iTemp]->Status = Here;
+            TmpClan->Member[iTemp]->HP = TmpClan->Member[iTemp]->MaxHP;
+            TmpClan->Member[iTemp]->SP = TmpClan->Member[iTemp]->MaxSP;
+          }
+          // if XP < 0, set it to what it should be
+          if (TmpClan->Member[iTemp]->Experience <= 0)
+          {
+            TmpClan->Member[iTemp]->Experience =
+              XPRequired[TmpClan->Member[iTemp]->Level];
+          }
+          if (TmpClan->Member[iTemp]->Experience >
+            XPRequired[TmpClan->Member[iTemp]->Level+1])
+          {
+            TmpClan->Member[iTemp]->Experience =
+              XPRequired[TmpClan->Member[iTemp]->Level+1];
+          }
+			}
+
+			// "release" NPC members
+      for (iTemp = Game.Data->MaxPermanentMembers; iTemp < 6; iTemp++)
+				if (TmpClan->Member[iTemp]->szName[0])
+				{
+					// is a npc-player
+					//printf("releasing %s\n", TmpClan->Member[iTemp]->szName);
+
+					for (iTemp2 = 0; iTemp2 < MAX_ITEMS_HELD; iTemp2++)
+					{
+						/* if held by deleted char, remove link */
+						if (TmpClan->Items[iTemp2].Available &&
+							TmpClan->Items[iTemp2].UsedBy == iTemp+1)
+						{
+							TmpClan->Items[iTemp2].UsedBy = 0;
+						}
+					}
+
+					// delete him now
+					TmpClan->Member[iTemp]->szName[0] = 0;
+				}
+
+        // fix up screwed up items, make them owned by no one
+        for (CurItem = 0; CurItem < MAX_ITEMS_HELD; CurItem++)
+        {
+          /* if held by deleted char, remove link */
+          if (TmpClan->Items[CurItem].UsedBy < 0 ||
+            TmpClan->Items[CurItem].UsedBy > Game.Data->MaxPermanentMembers)
+          {
+            TmpClan->Items[CurItem].UsedBy = 0;
+          }
+        }
+
+        /* make it so they stop using invalid items */
+        for (iTemp = 0; iTemp < Game.Data->MaxPermanentMembers; iTemp++)
+        {
+          if (TmpClan->Member[iTemp]->szName[0])
+          {
+            if (TmpClan->Member[iTemp]->Weapon &&
+              TmpClan->Items[ TmpClan->Member[iTemp]->Weapon-1 ].Available == FALSE)
+            {
+              TmpClan->Member[iTemp]->Weapon = 0;
+            }
+            if (TmpClan->Member[iTemp]->Armor &&
+              TmpClan->Items[ TmpClan->Member[iTemp]->Armor-1 ].Available == FALSE)
+            {
+              TmpClan->Member[iTemp]->Armor = 0;
+            }
+            if (TmpClan->Member[iTemp]->Shield &&
+              TmpClan->Items[ TmpClan->Member[iTemp]->Shield-1 ].Available == FALSE)
+            {
+              TmpClan->Member[iTemp]->Shield = 0;
+            }
+          }
+        }
+
+        /* write new stuff to new file */
+        EncryptWrite(TmpClan, sizeof(struct clan), fpNewPC, XOR_USER);
+
+        for (iTemp = 0; iTemp < 6; iTemp++)
+        {
+          EncryptWrite(TmpClan->Member[iTemp], sizeof(struct pc), fpNewPC, XOR_USER);
+          free(TmpClan->Member[iTemp]);
+          TmpClan->Member[iTemp] = NULL;
+        }
+      }
+
+      /* deallocate memory for PCs */
+      free(TmpClan);
+
+      fclose(fpOldPC);
+      fclose(fpNewPC);
+
+      /* delete old file, rename new one */
+      unlink(ST_CLANSPCFILE);
+      rename(ST_NEWPCFILE, ST_CLANSPCFILE);
+    }
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  BOOL User_Init ( void )
+    /*
+     * The current user online is initialized.  His stats are read in from
+     * the .PC file.  If not found, a new clan is created.
+     *
+     * Returns FALSE if user is new and didn't want to join the game.
+     */
+  {
+    // Returns TRUE if user was created/loaded successfully, otherwise,
+    // returns FALSE
+    _INT16 iTemp;
+
+    User.Initialized = TRUE;
+    PClan = malloc(sizeof(struct clan));
+    CheckMem(PClan);
+
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      PClan->Member[iTemp] = NULL;
+
+    if (!User_Read())
+    {
+      // see if in league already but he's just not on this
+      // BBS
+      if (IBBS_InList(od_control.user_name, FALSE))
+      {
+        // YES, he is IN the list already but he's not on
+        // this BBS, so tell him that
+
+        rputs("You're already logged as a user on another BBS.\n%P");
+        User_Destroy();
+        return FALSE;
+      }
+
+      if (!User_Create())
+      {
+        User_Destroy();
+        return FALSE;
+      }
+    }
+
+  /*
+    // ensure CRC is correct
+    if (CheckCRC(PClan, sizeof(struct clan) - sizeof(long), PClan->CRC) == FALSE)
+    {
+      User_Destroy();
+      System_Error("CLANS.PC data corrupt! [u]\n");
+    }
+
+    // ensure CRC is correct
+    for (iTemp = 0; iTemp < MAX_MEMBERS; iTemp++)
+      if (PClan->Member[iTemp] && CheckCRC(PClan->Member[iTemp], sizeof(struct pc) - sizeof(long), PClan->Member[iTemp]->CRC) == FALSE)
+      {
+        User_Destroy();
+        System_Error("CLANS.PC data corrupt [m]!\n");
+      }
+  */
+
+
+    User.UpdateUser = TRUE;
+    return TRUE;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void User_Close ( void )
+    /*
+     * Must be called to close down the user data.  User data is written to
+     * file if UpdateUser set (so that deleted users are not written to file
+     * if they chose to delete themselves).
+     */
+  {
+    // closes down current user logged in
+    if (User.Initialized == FALSE) return;
+
+    if (User.UpdateUser)
+      User_Write();
+
+    User_Destroy();
+  }
+
diff --git a/src/doors/clans-src/user.h b/src/doors/clans-src/user.h
new file mode 100644
index 0000000000000000000000000000000000000000..7940d7a608b7b5db82b1bb6afc263c032066fa9f
--- /dev/null
+++ b/src/doors/clans-src/user.h
@@ -0,0 +1,67 @@
+
+  void User_Maint ( void );
+
+  __BOOL User_Init ( void );
+    /*
+     * The current user online is initialized.  His stats are read in from
+     * the .PC file.  If not found, a new clan is created.
+     *
+     * Returns FALSE if user is new and didn't want to join the game.
+     */
+
+  void User_FirstTimeToday ( void );
+    /*
+     * Run whenever user plays first time that day.
+     *
+     */
+
+  void User_Close ( void );
+    /*
+     * Must be called to close down the user data.  User data is written to
+     * file if UpdateUser set (so that deleted users are not written to file
+     * if they chose to delete themselves).
+     */
+
+  _INT16 NumMembers ( struct clan *Clan, __BOOL OnlyOnesHere );
+    /*
+     * Returns the number of members in the clan.
+     *
+     * PRE: OnlyOnesHere is TRUE if only the alive members are to be checked.
+     */
+
+  void ClanStats ( struct clan *Clan, __BOOL AllowModify);
+    /*
+     * Shows stats for given Clan with option to modify values.
+     */
+
+  __BOOL GetClanID ( _INT16 ID[2], __BOOL OnlyLiving, __BOOL IncludeSelf,
+                   _INT16 WhichAlliance, __BOOL InAllianceOnly );
+
+  void ShowPlayerStats ( struct pc *PC, __BOOL AllowModify );
+  char GetStat ( struct pc *PC, char Stat );
+
+  void ListItems ( struct clan *Clan );
+
+  __BOOL GetClanNameID( char *szName, _INT16 ID[2] );
+
+  __BOOL GetClan ( _INT16 ClanID[2], struct clan *TmpClan );
+
+  __BOOL ClanExists ( _INT16 ClanID[2] );
+
+  void PC_Create( struct pc *PC, __BOOL ClanLeader );
+
+  void Clan_Update ( struct clan *Clan );
+
+  void ShowVillageStats ( void );
+
+  void User_List ( void );
+
+  void AddToDisband(void);
+
+  void DeleteClan ( _INT16 ClanID[2], char *szClanName, __BOOL Eliminate );
+
+  void User_Destroy ( void );
+
+  __BOOL Disbanded(void);
+
+  void User_Write (void);
diff --git a/src/doors/clans-src/video.c b/src/doors/clans-src/video.c
new file mode 100644
index 0000000000000000000000000000000000000000..c071d0b0be6e439a8cb111f55f6f69dc27f46cfb
--- /dev/null
+++ b/src/doors/clans-src/video.c
@@ -0,0 +1,886 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Video ADT -- x86 Architecture-specific
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __unix__
+#include <conio.h>
+#endif
+
+#ifdef _WIN32
+#include "cmdline.h" // defines display_win32_error ()
+#endif
+
+#include <ctype.h>
+#include <string.h>
+
+#include "defines.h"
+#include "door.h"
+#include "video.h"
+
+#define COLOR	0xB800
+#define MONO	0xB000
+
+#define CURS_NORMAL 	0
+#define CURS_FAT		1
+#define PADDING			'�'
+#define SPECIAL_CODE	'%'
+
+char o_fg4 = 7, o_bg4 = 0;
+
+#ifdef _WIN32
+static int default_cursor_size = 1;
+#endif
+
+// ------------------------------------------------------------------------- //
+
+  struct {
+    long VideoType;
+    long y_lookup[25];
+    char FAR *VideoMem;
+  } Video;
+
+// ------------------------------------------------------------------------- //
+  long Video_VideoType ( void )
+  {
+    return Video.VideoType;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  char FAR *vid_address ( void )
+  {
+// As usual, block off the local stuff
+#if !defined(__unix__) && !defined(_WIN32)
+    _INT16 tmp1, tmp2;
+
+    asm {
+      mov bx,0040h
+      mov es,bx
+      mov dx,es:63h
+      add dx,6
+      mov tmp1, dx           // move this into status port
+    };
+    Video.VideoType = COLOR;
+
+    asm {
+      mov bx,es:10h
+      and bx,30h
+      cmp bx,30h
+      jne FC1
+    };
+    Video.VideoType = MONO;
+
+    FC1:
+
+    if (Video.VideoType == MONO)
+      return ( ( void FAR * ) 0xB0000000L) ;
+    else
+      return ( ( void FAR * ) 0xB8000000L) ;
+
+#else
+	Video.VideoType = COLOR; /* Assume Color on Win32 & UNIX */
+	return NULL;
+#endif
+  }
+
+  void ScrollUp ( void )
+  {
+// As usual, block off the local stuff
+#if !defined(__unix__) && !defined(_WIN32)
+    asm {
+      mov al,1    // number of lines
+      mov ch,0    // starting row
+      mov cl,0    // starting column
+      mov dh, 24  // ending row
+      mov dl, 79  // ending column
+      mov bh, 7   // color
+      mov ah, 6
+      int 10h     // do the scroll
+    }
+#elif defined(_WIN32)
+    HANDLE handle_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	SMALL_RECT scroll_rect;
+	COORD top_left = { 0, 0 };
+	CHAR_INFO char_info;
+
+	GetConsoleScreenBufferInfo(handle_stdout, &screen_buffer);
+	scroll_rect.Top = 1;
+	scroll_rect.Left = 0;
+	scroll_rect.Bottom = screen_buffer.dwSize.Y;
+	scroll_rect.Right = screen_buffer.dwSize.X;
+
+	char_info.Attributes = screen_buffer.wAttributes;
+	char_info.Char.UnicodeChar = (TCHAR)' ';
+
+	if (!ScrollConsoleScreenBuffer(handle_stdout,
+		&scroll_rect, NULL, top_left, &char_info))
+	{
+		display_win32_error ();
+		exit (0);
+	}
+#else
+//# pragma message("ScrollUp() Nullified by no defines")
+#endif
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+  void put_character (char ch, short attrib, int x, int y)
+  {
+#ifdef __MSDOS__
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1)) ] = ch;
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1) + 1L)] = (char)(attrib & 0xff);
+#elif defined(_WIN32)
+		  COORD cursor_pos;
+		  DWORD bytes_written;
+		  HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+
+		  cursor_pos.X = x;
+		  cursor_pos.Y = y;
+
+		  SetConsoleCursorPosition (
+			  stdout_handle, cursor_pos);
+		  SetConsoleTextAttribute (
+			  stdout_handle,
+			  (WORD)attrib);
+		  WriteConsole (
+			  stdout_handle,
+			  &ch,
+			  1,
+			  &bytes_written,
+			  NULL);
+#endif
+
+  }
+
+  void zputs (char *string)
+  {
+#ifdef __unix__
+	int i;
+	int len;
+	
+	len = strlen (string);
+	if (!Door_Initialized())  {
+		for(i=0;i<len;i++)  {
+			if (string[i] == '|' && ((i + 1) < len && (i + 2) < len) && isdigit(string[i+1]) && isdigit(string[i+2]))  {
+				i+=2;
+			}
+			else  {
+				putchar(string[i]);
+			}
+		}
+	}
+#else
+	char number[3];
+	_INT16 cur_char, attr;
+	char foreground, background, cur_attr;
+	_INT16 i, j,  x,y;
+#ifndef _WIN32
+	struct text_info TextInfo;
+#else
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	int bytes_written;
+	COORD cursor_pos;
+/*	TCHAR space_char = (TCHAR)' ';*/
+#endif
+	static char o_fg = 7, o_bg = 0;
+	int scr_lines = 25, scr_width = 80;
+
+#ifndef _WIN32
+	gettextinfo(&TextInfo);
+	x = TextInfo.curx-1;
+	y = TextInfo.cury-1;
+#else
+	GetConsoleScreenBufferInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&screen_buffer);
+	x = screen_buffer.dwCursorPosition.X;
+	y = screen_buffer.dwCursorPosition.Y;
+	scr_lines = screen_buffer.dwSize.Y;
+	scr_width = screen_buffer.dwSize.X;
+#endif
+
+	cur_attr = o_fg | o_bg;
+    cur_char = 0;
+
+    for (;;)
+    {
+      if (y == scr_lines)
+      {
+        /* scroll line up */
+        ScrollUp();
+        y = scr_lines - 1;
+      }
+      if (string[cur_char] == 0)
+        break;
+      if (string[cur_char] == '\b')
+      {
+        x--;
+        cur_char++;
+        continue;
+      }
+      if (string[cur_char] == '\r')
+      {
+        x = 0;
+        cur_char++;
+        continue;
+      }
+      if (x == scr_width)
+      {
+        x = 0;
+        y++;
+
+        if (y == scr_lines)
+        {
+          /* scroll line up */
+          ScrollUp();
+          y = scr_lines - 1;
+        }
+        break;
+      }
+      if (string[cur_char]=='|')
+      {
+        if ( isdigit(string[cur_char+1]) && isdigit(string[cur_char+2]) )
+        {
+          number[0]=string[cur_char+1];
+          number[1]=string[cur_char+2];
+          number[2]=0;
+
+          attr=atoi(number);
+          if (attr>15)
+          {
+            background=attr-16;
+            o_bg = background << 4;
+            attr = o_bg | o_fg;
+            cur_attr = attr;
+          }
+          else
+          {
+            foreground=attr;
+            o_fg=foreground;
+            attr = o_fg | o_bg;
+            cur_attr = attr;
+          }
+          cur_char += 3;
+        }
+        else
+        {
+		  put_character (string[cur_char], cur_attr, x, y);
+
+          cur_char++;
+        }
+      }
+      else if (string[cur_char] == '\n')  {
+        y++;
+        if (y == scr_lines)
+        {
+          /* scroll line up */
+          ScrollUp();
+          y = scr_lines - 1;
+        }
+        cur_char++;
+        x = 0;
+      }
+      else if (string[cur_char] == 9)
+      {
+        /* tab */
+        cur_char++;
+        for (i=0;i<8;i++)
+        {
+          j = i + x;
+          if (j > scr_width) break;
+		  put_character(' ', cur_attr, j, y);
+        }
+        x += 8;
+      }
+      else
+      {
+		put_character (string[cur_char], cur_attr, x, y);
+
+        cur_char++;
+        x++;
+      }
+    }
+    gotoxy(x+1,y+1);
+#endif
+  }
+
+  void SetCurs ( _INT16 CursType )
+  {
+// As usual, block off the local stuff
+#if !defined(__unix__) && !defined(_WIN32)
+    if (CursType == CURS_NORMAL)
+    {
+      asm mov ah,01h
+      asm mov ch,11
+      asm mov cl,12
+      asm int 10h
+    }
+    else if (CursType == CURS_FAT)
+    {
+      asm mov ah,01h
+      asm mov ch,8
+      asm mov cl,13
+      asm int 10h
+    }
+#elif defined(_WIN32)
+	CONSOLE_CURSOR_INFO cursor_info;
+	cursor_info.bVisible = TRUE;
+	switch (CursType)
+	{
+	case CURS_NORMAL:
+		cursor_info.dwSize = default_cursor_size;
+		break;
+	case CURS_FAT:
+		cursor_info.dwSize = 75;
+		break;
+	default:
+		cursor_info.dwSize = default_cursor_size;
+	}
+	SetConsoleCursorInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&cursor_info);
+#endif
+  }
+
+  void qputs (char *string, _INT16 x, _INT16 y)
+  {
+// As usual, block off the local stuff
+#if defined(_WIN32) && !defined(__unix__)
+	gotoxy(x+1, y+1);
+    zputs(string);
+#elif defined(__unix__)
+#else
+    char number[3];
+    _INT16 cur_char, attr;
+    char foreground, background, cur_attr;
+    static o_fg = 7, o_bg = 0;
+    _INT16 i, j;
+
+    cur_attr = o_fg | o_bg;
+    cur_char=0;
+
+    while (1) {
+      if (string[cur_char] == 0)
+        break;
+      if (x == 80)
+        break;
+      if (string[cur_char]=='|')    {
+        if ( isdigit(string[cur_char+1]) )  {
+          number[0]=string[cur_char+1];
+          number[1]=string[cur_char+2];
+          number[2]=0;
+
+          attr=atoi(number);
+          if (attr>15)  {
+            background=attr-16;
+            o_bg = background << 4;
+            attr = o_bg | o_fg;
+            cur_attr = attr;
+          }
+          else  {
+            foreground=attr;
+            o_fg=foreground;
+            attr = o_fg | o_bg;
+            cur_attr = attr;
+          }
+          cur_char += 3;
+        }
+        else  {
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1)) ] = string[cur_char];
+          Video.VideoMem[(long) (Video.y_lookup[(long) y]+ (long) (x<<1) + 1L)] = cur_attr;
+
+          cur_char++;
+          x++;
+        }
+      }
+      else if (string[cur_char] == '\n')  {
+        y++;
+        cur_char++;
+        x = 0;
+      }
+      else if (string[cur_char] == 9)  {  // tab
+        cur_char++;
+        for (i=0;i<8;i++) {
+          j = i+x;
+          if (j > 80) break;
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) ] = ' ';
+          Video.VideoMem[ Video.y_lookup[y]+(j<<1) + 1] = cur_attr;
+        }
+        x += 8;
+      }
+      else  {
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) ] = string[cur_char];
+        Video.VideoMem[ Video.y_lookup[y]+(x<<1) + 1] = cur_attr;
+
+        cur_char++;
+        x++;
+      }
+    }
+#endif
+  }
+
+
+  void sdisplay( char *string, _INT16 x, _INT16 y, char color, _INT16 length, _INT16 input_length )
+  {
+#ifdef __unix__
+	fprintf(stderr,"%s\r\n",string);
+#elif defined(_WIN32)
+    COORD cursor_pos, current_cursor_pos;
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	WORD current_attr, i;
+	DWORD bytes_written;
+	TCHAR padding_char = (TCHAR)PADDING;
+
+	/* Save Current Color Attribute */
+	GetConsoleScreenBufferInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&screen_buffer);
+
+	current_attr = screen_buffer.wAttributes;
+
+	/* Save Current Cursor Position */
+	current_cursor_pos.X = screen_buffer.dwCursorPosition.X;
+	current_cursor_pos.Y = screen_buffer.dwCursorPosition.Y;
+
+	/* Set New Cursor Position (based on x, y) */
+	cursor_pos.X = x;
+	cursor_pos.Y = y;
+
+	SetConsoleCursorPosition (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		cursor_pos);
+
+	/* Set new color */
+	SetConsoleTextAttribute (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		(WORD) color);
+
+	/* Output Text */
+    WriteConsole (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		string,
+		strlen (string),
+		&bytes_written,
+		NULL);
+
+	/* Set color for padding */
+	SetConsoleTextAttribute (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		(WORD) 8);
+
+	/* Display Padding */
+	for (i = length; i < input_length; i++)
+	{
+		WriteConsole (
+			GetStdHandle (STD_OUTPUT_HANDLE),
+			&padding_char,
+			1,
+			&bytes_written,
+			NULL);
+	}
+
+	/* Reset color */
+	SetConsoleTextAttribute (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		current_attr);
+#else
+    _INT16 i, offset;
+    char *pString;
+
+    pString = string;
+
+    offset = y*160 + x*2;
+
+    while (*pString)
+    {
+      Video.VideoMem[ offset ] = *pString;
+      Video.VideoMem[ offset+1 ] = color;
+      offset+=2;
+      pString++;
+    }
+    for (i=length;i<input_length;i++)
+    {
+      Video.VideoMem[ offset ] = PADDING;
+      Video.VideoMem[ offset+1 ] = 8;
+      offset+=2;
+    }
+#endif
+  }
+
+
+  _INT16 LongInput( char *string, _INT16 x, _INT16 y, _INT16 input_length, char attr,
+    _INT16 low_char, _INT16 high_char)
+  {
+// As usual, block off the local stuff
+#if !defined(__unix__)
+    _INT16 length = strlen(string);  // length of string
+    _INT16 i,
+		insert = FALSE,
+		key,		// key inputted
+		cur_letter = length; // letter we're editing right now
+    char tmp_str[255];
+    char first_time = TRUE; // flags if this is the first time to input
+                // if TRUE, it will clear the line and input
+    char old_fg4, old_bg4;
+
+    // initialize the string here
+
+    SetCurs(insert);
+#ifdef __MSDOS__
+    textattr( attr );
+#else
+	SetConsoleTextAttribute (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		(WORD)attr);
+#endif
+
+    o_fg4 = attr&0x00FF;
+    o_bg4 = attr&0xFF00;
+    qputs(string, x, y);
+    gotoxy(x+length+1, y+1);
+
+    old_fg4 = o_fg4;
+    o_fg4 = 8;
+
+    for (i = length; i < input_length; i++)
+      putch(PADDING);
+
+    o_fg4 = old_fg4;
+
+    // now edit it
+
+    for (;;)
+    {
+      sdisplay( string, x, y, attr, length, input_length);
+
+      gotoxy(x+ 1 + cur_letter, y+1);
+
+      key = getch();
+
+      switch( (unsigned char)key )
+      {
+	    case 0xE0 :
+        case 0 :
+          switch( getch() )
+          {
+            case 80 : // down
+            case 72 : // up
+              break;
+            case 79 : // end
+              cur_letter = length;
+              break;
+            case 77 :   // right
+              if (cur_letter < length)
+                cur_letter++;
+              break;
+            case 75 :   // left
+              if (cur_letter)
+							cur_letter--;
+              break;
+            case 71 : // home
+              cur_letter = 0;
+              break;
+            case 82 : // insert
+              insert = !insert;
+              SetCurs(insert);
+              // change cursor here
+              break;
+            case 83 :   // delete
+              if (length && cur_letter < length)
+              {
+                i = cur_letter;
+                while (i<length)  {
+                  string[i] = string[i+1];
+                  i++;
+                }
+                string[length] = 0;
+
+                length--;
+              }
+              break;
+          }
+          break;
+
+        case '\t' :
+        case '\r' :     // enter
+          return 1;
+        case 25 : // ctrl-Y
+          string[0] = 0;
+          length = 0;
+          cur_letter = 0;
+          break;
+        case '\b' : // backspace
+          if (cur_letter > 0)   {
+            i = cur_letter-1;
+
+            while (i<length)
+            {
+              string[i] = string[i+1];
+              i++;
+            }
+            string[length] = 0;
+
+            length--;
+            cur_letter--;
+          }
+          break;
+        case 0x1B : // esc
+          break;
+        default :
+          if (first_time)
+          { // clear line!
+            string[0] = 0;
+            length = 0;
+            cur_letter = 0;
+          }
+          if ((char)key < low_char || (char)key > high_char)  break;
+          if (insert && length < input_length)  {
+
+            strcpy(tmp_str, &string[cur_letter]);
+            strcpy(&string[cur_letter+1], tmp_str);
+
+            string[cur_letter] = key;
+
+            length++;
+
+            if (cur_letter<input_length)
+            cur_letter++;
+          }
+          else if (!insert && cur_letter<input_length) {
+
+            string[ cur_letter ] = key;
+
+            if (cur_letter < length)
+              cur_letter++;
+            else if (cur_letter == length)  {
+              string[cur_letter+1]=0;
+              cur_letter++;
+              length++;
+            }
+          }
+        break;
+      } // end of while loop
+      first_time = FALSE;
+
+    }
+#else
+	return 0;
+#endif
+  }
+
+  void Input( char *string, _INT16 length )
+  {
+// As usual, block off the local stuff
+#if !defined(__unix__)
+    _INT16 cur_x, cur_y;
+
+#ifdef __MSDOS__
+    cur_x = wherex()-1;
+    cur_y = wherey()-1;
+#else
+	CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+	GetConsoleScreenBufferInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&screen_buffer);
+	cur_x = screen_buffer.dwCursorPosition.X;
+	cur_y = screen_buffer.dwCursorPosition.Y;
+#endif
+
+    LongInput( string, cur_x, cur_y, length, 15, 2, 255);
+    zputs("\n");
+
+    SetCurs(CURS_NORMAL);
+#endif
+  }
+
+
+  void ClearArea ( char x1, char y1,  char x2, char y2, char attr)
+  {
+#if !defined(__unix__) && !defined(_WIN32)
+    asm {
+      push ax
+      push bx
+      push cx
+      push dx
+
+      mov al, 0
+      mov ch, y1
+      mov cl, x1
+      mov dh, y2
+      mov dl, x2
+      mov bh, attr
+      mov ah, 7
+      int 10h
+
+      pop dx
+      pop cx
+      pop bx
+      pop ax
+    }
+#endif
+  }
+
+  void xputs (char *string, _INT16 x, _INT16 y)
+  {
+// As usual, block off the local stuff
+#if !defined(__unix__) && !defined(_WIN32)
+    char FAR *VidPtr;
+
+    VidPtr = Video.VideoMem + Video.y_lookup[y] + (x<<1);
+
+    while (x < 80 && *string)
+    {
+      *VidPtr = *string;
+
+      VidPtr += 2;
+      x++;
+      string++;
+    }
+#elif defined(_WIN32)
+	COORD cursor_pos;
+	DWORD bytes_written;
+
+	cursor_pos.X = x;
+	cursor_pos.Y = y;
+
+	SetConsoleCursorPosition (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		cursor_pos);
+
+	WriteConsole (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		string,
+		strlen (string),
+		&bytes_written,
+		NULL);
+#endif
+  }
+
+  void DisplayStr ( char *szString )
+  {
+// As usual, block off the local stuff
+#ifdef __unix__
+	if (Door_Initialized())
+	  rputs(szString);
+	else
+	  zputs(szString);
+#else
+    if (Door_Initialized())
+      rputs(szString);
+    else
+      zputs(szString);
+#endif
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Video_Init ( void )
+  {
+// As usual, block off the local stuff
+#if defined(__unix__) && !defined(_WIN32)
+#elif defined(_WIN32)
+	CONSOLE_CURSOR_INFO cursor_info;
+
+	if (!AllocConsole())
+	{
+		display_win32_error ();
+		exit (0);
+	}
+
+	if (!CreateConsoleScreenBuffer(
+		GENERIC_READ | GENERIC_WRITE,
+		FILE_SHARE_READ | FILE_SHARE_WRITE,
+		NULL,
+		CONSOLE_TEXTMODE_BUFFER,
+		NULL))
+	{
+		display_win32_error ();
+		exit (0);
+	}
+
+	if (!GetConsoleCursorInfo (
+		GetStdHandle (STD_OUTPUT_HANDLE),
+		&cursor_info))
+	{
+		display_win32_error ();
+		exit (0);
+	}
+	default_cursor_size = cursor_info.dwSize;
+#else
+    _INT16 iTemp;
+
+    Video.VideoMem = vid_address();
+    for (iTemp = 0; iTemp < 25;  iTemp++)
+      Video.y_lookup[ iTemp ] = iTemp * 160;
+#endif
+  }
+
+#ifdef _WIN32
+  void gotoxy(int x, int y)
+  {
+	  COORD cursor_pos;
+
+	  cursor_pos.X = x - 1;
+	  cursor_pos.Y = y - 1;
+
+	  SetConsoleCursorPosition (
+		  GetStdHandle (STD_OUTPUT_HANDLE),
+		  cursor_pos);
+  }
+
+  void clrscr (void)
+  {
+  HANDLE std_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+  CONSOLE_SCREEN_BUFFER_INFO screen_buffer;
+  COORD top_left = { 0, 0 };
+  DWORD cells_written;
+
+  GetConsoleScreenBufferInfo (std_handle, &screen_buffer);
+
+  FillConsoleOutputCharacter (
+    std_handle,
+    (TCHAR)' ',
+    screen_buffer.dwSize.X * screen_buffer.dwSize.Y,
+    top_left,
+    &cells_written);
+
+  FillConsoleOutputAttribute (
+    std_handle,
+    (WORD)7,
+    screen_buffer.dwSize.X * screen_buffer.dwSize.Y,
+    top_left,
+    &cells_written);
+
+  SetConsoleCursorPosition (
+    std_handle,
+    top_left);
+  }
+#endif
diff --git a/src/doors/clans-src/video.h b/src/doors/clans-src/video.h
new file mode 100644
index 0000000000000000000000000000000000000000..c868a77ac1c5d0948d9b482c9eddac05d973e6d3
--- /dev/null
+++ b/src/doors/clans-src/video.h
@@ -0,0 +1,29 @@
+/*
+ * Video ADT
+ */
+
+  char FAR *vid_address ( void );
+
+  void Video_Init ( void );
+    /*
+     * purpose  Initializes video system.
+     * post     video mem, y-lookup initialized,
+     */
+
+  void Input( char *string, _INT16 length );
+
+  void ClearArea ( char x1, char y1,  char x2, char y2, char attr);
+  void xputs (char *string, _INT16 x, _INT16 y);
+
+  long Video_VideoType ( void );
+
+  void DisplayStr ( char *szString );
+
+  void zputs (char *string);
+  void qputs (char *string, _INT16 x, _INT16 y);
+
+  void ScrollUp ( void );
+#ifdef _WIN32
+  void clrscr(void);
+  void gotoxy(int, int);
+#endif
diff --git a/src/doors/clans-src/village.c b/src/doors/clans-src/village.c
new file mode 100644
index 0000000000000000000000000000000000000000..aa42807464f7b6577b24b3705676d5156831f5e8
--- /dev/null
+++ b/src/doors/clans-src/village.c
@@ -0,0 +1,1543 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Village ADT
+ *
+ */
+
+#include <stdio.h>
+#ifndef __FreeBSD__
+#include <malloc.h>
+#endif
+
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <share.h>
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <OpenDoor.h>
+#include "structs.h"
+#include "system.h"
+#include "language.h"
+#include "mstrings.h"
+#include "door.h"
+#include "crc.h"
+#include "myopen.h"
+#include "quests.h"
+#include "news.h"
+#include "input.h"
+#include "menus.h"
+#include "voting.h"
+#include "empire.h"
+#include "reg.h"
+#include "help.h"
+#include "video.h"
+#include "npc.h"
+#include "parsing.h"
+#include "user.h"
+#include "mail.h"
+
+extern struct Language *Language;
+extern struct clan *PClan;
+struct village Village = { FALSE, NULL };
+extern struct config *Config;
+extern struct ibbs IBBS;
+extern struct game Game;
+extern BOOL Verbose;
+
+struct  PACKED Scheme {
+	char szName[20];
+
+  char ColorScheme[23];
+} PACKED;
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 OutsiderTownHallMenu ( void )
+  {
+    char *szTheOptions[11];
+    char szString[128];
+    _INT16 iTemp, ClanId[2];
+    long lTemp;
+    BOOL IsRuler;
+
+    LoadStrings(380, 10, szTheOptions);
+    szTheOptions[10] = "View Village Empire Stats";
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      /* show 'menu' */
+      if (Game.Data->InterBBS)
+        sprintf(szString, ST_VSTATHEADER, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszVillageName);
+      else
+        sprintf(szString, ST_VSTATHEADER, Village.Data->szName);
+      rputs(szString);
+
+      rputs(ST_LONGLINE);
+
+      if (Village.Data->RulingClanId[0] == -1)
+        rputs(ST_T2MENUSTAT0);
+      else
+      {
+        sprintf(szString, ST_T2MENUSTAT1, Village.Data->szRulingClan, Village.Data->RulingDays);
+        rputs(szString);
+      }
+
+      sprintf(szString, ST_T2MENUSTAT2, Village.Data->TaxRate);
+      rputs(szString);
+
+      sprintf(szString, ST_T2MENUSTAT3, Village.Data->InterestRate);
+      rputs(szString);
+
+      sprintf(szString, ST_T2MENUSTAT4, Village.Data->GST);
+      rputs(szString);
+
+      sprintf(szString, ST_T2MENUSTAT6, Village.Data->Empire.VaultGold);
+      rputs(szString);
+
+      sprintf(szString, ST_TMENUSTAT8, Village.Data->ConscriptionRate);
+      rputs(szString);
+/*
+      sprintf(szString, ST_TMENUSTAT9, Village.Data->GovtSystem == GS_DEMOCRACY ?
+        "Democracy" : "Dictatorship");
+      rputs(szString);
+
+      sprintf(szString, ST_TMENUSTAT10, Village.Data->ShowEmpireStats ?
+        "Available" : "Unavailable");
+      rputs(szString);
+*/
+
+      switch(GetChoice("Town2", ST_ENTEROPTION, szTheOptions, "DWBVPH?Q/ES", 'Q', TRUE))
+      {
+        case 'S' :  // village empire stats
+/*
+        IsRuler = PClan->ClanID[0] == Village.Data->RulingClanId[0] &&
+          PClan->ClanID[1] == Village.Data->RulingClanId[1];
+
+        if (Village.Data->Empire.OwnerType != EO_VILLAGE || (!IsRuler &&
+          Village.Data->ShowEmpireStats && Village.Data->Empire.OwnerType == EO_VILLAGE) ||
+          (Village.Data->Empire.OwnerType == EO_VILLAGE && IsRuler) )
+          EmpireStats(&Village.Data->Empire);
+        else if (Village.Data->Empire.OwnerType == EO_VILLAGE && IsRuler == FALSE &&
+          Village.Data->ShowEmpireStats == FALSE)
+          rputs("|07Empire stats made unavailable by ruler.\n%P");
+*/
+
+          Empire_Stats(&Village.Data->Empire);
+          break;
+        case 'E' :  // donate to empire
+          DonateToEmpire(&Village.Data->Empire);
+          break;
+        case 'B' :  // voting booth
+/*        if (Village.Data->GovtSystem == GS_DICTATOR)
+          {
+            rputs("This town is under dictatorial rule.  Voting is disabled.\n");
+          }
+          else
+            VotingBooth();
+*/
+          VotingBooth();
+          break;
+        case 'D' :  /* deposit into vault */
+          Help("Deposit into Vault", ST_CITIZENHLP);
+          lTemp = GetLong(ST_T2MENU1Q, 0, PClan->Empire.VaultGold);
+
+          if (lTemp)
+          {
+            Village.Data->Empire.VaultGold += lTemp;
+            PClan->Empire.VaultGold -= lTemp;
+
+            sprintf(szString, ST_T2MENU1, lTemp);
+            rputs(szString);
+          }
+          break;
+        case 'P' :  /* public discussion */
+          Menus_ChatRoom("public.txt");
+          break;
+        case 'W' :      /* Write to ruler */
+          if (Village.Data->RulingClanId[0] == -1)
+          {
+            // no ruler to write to!
+            rputs(ST_T2MENU3);
+            break;
+          }
+          ClanId[0] = Village.Data->RulingClanId[0];
+          ClanId[1] = Village.Data->RulingClanId[1];
+          MyWriteMessage2(ClanId, FALSE, FALSE, -1, "", FALSE, -1);
+          break;
+        case 'H' :  /* citizen help */
+          GeneralHelp(ST_CITIZENHLP);
+          break;
+        case 'V' :  /* view clan stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case 'Q' :      /* return to previous menu */
+          return 0;
+        case '?' :      /* redisplay options */
+          break;
+        case '/' :  // chat villagers
+          ChatVillagers(WN_TOWNHALL);
+          break;
+      }
+    }
+	(void)IsRuler;
+	(void)iTemp;
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void ChangeFlagScheme ( void )
+  {
+    BOOL Quit = FALSE;
+    char cInput;
+    _INT16 iTemp, WhichColour;
+    _INT16 OldFlag[3];
+    BOOL ChangesMade = FALSE;
+    char szString[255];
+
+    /* save current flag */
+    OldFlag[0] = Village.Data->ColorScheme[23];
+    OldFlag[1] = Village.Data->ColorScheme[24];
+    OldFlag[2] = Village.Data->ColorScheme[25];
+
+    Help("Flag", ST_RULERHLP);
+    rputs("\n%P");
+
+    while (!Quit)
+    {
+      /* show current scheme */
+      rputs(" |0CCurrent Flag:  |0X踻0Y踻0Z踈n\n");
+
+      rputs("|0A(|0B1|0A) |0CLeft bar\n");
+      rputs("|0A(|0B2|0A) |0CMiddle bar\n");
+      rputs("|0A(|0B3|0A) |0CRight bar\n");
+      rputs("|0A(|0BQ|0A) |0CQuit\n\n");
+
+      rputs("|0GChoose one|0E> |15");
+
+      /* get option */
+      cInput = od_get_answer("123Q\r\n");
+
+      switch (cInput)
+      {
+        case '1' :
+        case '2' :
+        case '3' :
+          sprintf(szString, "%c\n\n", cInput);
+          rputs(szString);
+
+          ChangesMade = TRUE;
+
+          WhichColour = (cInput - '1') + 23;
+
+          Help("Individual Colours", ST_CLANSHLP);
+
+          Village.Data->ColorScheme[ WhichColour ] = (char)GetLong("|0SPlease enter the colour to use (0 to 15) ", Village.Data->ColorScheme[ WhichColour ], 15);
+          Door_SetColorScheme(Village.Data->ColorScheme);
+          break;
+        case 'Q' :
+        case '\n' :
+        case '\r' :
+          rputs("Quit\n\n");
+          Quit = TRUE;
+          break;
+      }
+
+      /* act on option */
+    }
+
+    if (ChangesMade && NoYes("|0SAre you sure you wish to use this flag?") == NO)
+    {
+      Village.Data->ColorScheme[23] = OldFlag[0];
+      Village.Data->ColorScheme[24] = OldFlag[1];
+      Village.Data->ColorScheme[25] = OldFlag[2];
+    }
+    else if (ChangesMade)
+    {
+      rputs("|15Flag changes have been saved.\n\n");
+
+      sprintf(szString, ST_NEWSNEWFLAG, Village.Data->szRulingClan, Village.Data->ColorScheme[23], Village.Data->ColorScheme[24], Village.Data->ColorScheme[25]);
+      News_AddNews(szString);
+    }
+	(void)iTemp;
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void GetNums ( char *Array, _INT16 NumVars, char *string )
+  {
+    _INT16 iTemp, CurChar = 0;
+
+    // get next number
+    while ((string[CurChar] == ',' || string[CurChar] == ' ') && string[CurChar])
+      CurChar++;
+
+    for (iTemp = 0;  iTemp < NumVars; iTemp++)
+    {
+      Array[iTemp] = atoi(&string[CurChar]);
+
+      while (isdigit(string[CurChar]))
+        CurChar++;
+
+      // get next number
+      while ((string[CurChar] == ',' || string[CurChar] == ' ') && string[CurChar])
+        CurChar++;
+
+      if (string[CurChar] == 0)
+        break;
+    }
+  }
+
+  void LoadSchemes( struct Scheme *Scheme[128] )
+  {
+    _INT16 iTemp, CurScheme;
+    char szLine[128], *pcCurrentPos, szName[20];
+    struct FileHeader FileHeader;
+
+    for (iTemp = 0; iTemp < 128; iTemp++)
+		Scheme[iTemp] = NULL;
+
+    MyOpen("/d/Schemes", "r", &FileHeader);
+
+    if (!FileHeader.fp) return;
+
+    for (CurScheme = 0;;)
+    {
+      if (ftell(FileHeader.fp) >= FileHeader.lEnd)
+        break;
+
+      if (fgets(szLine, 128, FileHeader.fp) == NULL)
+        break;
+
+      Scheme[CurScheme] = malloc(sizeof(struct Scheme));
+      CheckMem(Scheme[CurScheme]);
+
+      pcCurrentPos = szLine;
+
+      /* get name */
+      GetToken(pcCurrentPos, szName);
+      strcpy(Scheme[CurScheme]->szName, szName);
+
+      /* get colors */
+      GetNums(Scheme[CurScheme]->ColorScheme, 23, pcCurrentPos);
+
+      CurScheme++;
+    }
+
+    fclose(FileHeader.fp);
+  }
+
+  void AddScheme ( void )
+  {
+    FILE *fp;
+    _INT16 iTemp;
+
+    fp = fopen("schemes.txt", "a");
+
+    fprintf(fp, "\nScheme ");
+    for (iTemp = 0; iTemp < 23; iTemp++)
+      fprintf(fp, "%d ", Village.Data->ColorScheme[iTemp]);
+
+    fclose(fp);
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void ChangeColourScheme ( void )
+  {
+    BOOL Quit = FALSE;
+    char cInput, szKeys[26], szString[128];
+    _INT16 iTemp, WhichColour, Choice;
+    struct Scheme *Scheme[128];
+    _INT16 TableColor[128];
+
+
+    /* set up tables which "point" to which color */
+    /* this is a tricky way of fixing a problem. ;) */
+    for (iTemp = 0; iTemp < 128; iTemp++)
+      TableColor[iTemp] = iTemp;
+    /* now for the abnormal ones */
+    TableColor[ '5' ] = '7';
+    TableColor[ '6' ] = '5';
+    TableColor[ '7' ] = '6';
+
+    Help("Color Scheme", ST_RULERHLP);
+    rputs("\n%P");
+
+
+    LoadSchemes(Scheme);
+
+    while (!Quit)
+    {
+      /* show current scheme */
+      rputs(ST_SCHEMETITLE);
+
+      rputs(ST_SCHEME1);
+      rputs(ST_SCHEME2);
+      rputs(ST_SCHEME3);
+      rputs(ST_SCHEME4);
+      rputs(ST_SCHEME5);
+
+      rputs(ST_SCHEME6);
+      rputs(ST_SCHEME7);
+      rputs(ST_SCHEME8);
+      rputs(ST_SCHEME9);
+      rputs(ST_SCHEME10);
+
+      rputs(ST_COLOR03);
+      rputs(ST_SCHEMEMENU1);
+      rputs(ST_SCHEMEMENU2);
+      rputs(ST_SCHEMEMENU3);
+      rputs(ST_SCHEMEMENU4);
+
+      rputs(ST_SCHEMEMENU5);
+      rputs(ST_SCHEMEMENU6);
+      rputs(ST_SCHEMEMENU7);
+      rputs(ST_SCHEMEMENU8);
+
+      /* prompt */
+      rputs(ST_SCHEMEMENU9);
+
+      /* get option */
+      cInput = od_get_answer("123456789ABCDEFGHIJMNQ\r\n!Z");
+
+      switch (cInput)
+      {
+        case 'Z' :  /* choose scheme */
+          rputs("Choose scheme\n\n");
+
+          strcpy(szKeys, "ABCDEFGHIJKLMNOP");
+          for (iTemp = 0; iTemp < 128; iTemp++)
+          {
+            if (Scheme[iTemp] == NULL)
+              break;
+
+            sprintf(szString, "|01(|09%c|01) |07%s\n", iTemp + 'A', Scheme[iTemp]->szName);
+            rputs(szString);
+          }
+          szKeys[iTemp] = 0;
+          strcat(szKeys, "Q\r\n");
+          rputs("|01(|09Q|01) |07Quit\n\n|07Choose one|03> |11");
+          cInput = od_get_answer(szKeys);
+
+          if (cInput == '\r' || cInput == 'Q' || cInput == '\n')
+          {
+            rputs("Quit\n");
+            break;
+          }
+          else
+            sprintf(szString, "%s\n", Scheme[cInput - 'A']->szName);
+            rputs(szString);
+
+          Choice = cInput - 'A';
+
+          for (iTemp = 0; iTemp < 23; iTemp++)
+            Village.Data->ColorScheme[iTemp] = Scheme[Choice]->ColorScheme[iTemp];
+          Door_SetColorScheme(Village.Data->ColorScheme);
+          break;
+        case '!' :
+          for (iTemp = 0; iTemp < 26; iTemp++)
+          {
+            sprintf(szString, "%d ", Village.Data->ColorScheme[iTemp]);
+            rputs(szString);
+          }
+          rputs("\n");
+          AddScheme();
+          door_pause();
+          break;
+        case 'Q' :
+        case '\r':
+        case '\n':
+          rputs("Quit\n\n");
+          Quit = TRUE;
+          break;
+        default :
+
+          sprintf(szString, "%c\n\n", cInput);
+          rputs(szString);
+
+          cInput = TableColor[ (cInput + 0) ];
+
+          if (isdigit(cInput))
+            WhichColour = cInput - '1';
+          else
+            WhichColour = (cInput - 'A') + 9;
+
+          Help("Individual Colours", ST_CLANSHLP);
+
+          iTemp = GetLong("|0SPlease enter the colour to use (1 to 15) ", (long)Village.Data->ColorScheme[ WhichColour ], 15);
+
+          if (iTemp)
+            Village.Data->ColorScheme[ WhichColour ] = iTemp;
+          Door_SetColorScheme(Village.Data->ColorScheme);
+          break;
+      }
+
+      /* act on option */
+    }
+
+    for (iTemp = 0; iTemp < 128; iTemp++)
+        if (Scheme[iTemp])
+            free(Scheme[iTemp]);
+  }
+
+
+// ------------------------------------------------------------------------- //
+  void BuildMenu ( void )
+  {
+    char *szTheOptions[9];
+    char szString[255];
+    _INT16 iTemp;
+    long THallBuildCosts[MAX_THALLLEVEL] =
+      { 15500L, 50000L, 100000L, 250000L };
+    long ChurchBuildCosts[MAX_CHURCHLEVEL] = { 8000L, 25000L, 30000L, 50000L, 70000L };
+    long PawnBuildCosts[MAX_PAWNLEVEL] = { 10000L, 25000L, 30000L, 50000L, 70000L };
+    long WizardBuildCosts[MAX_WIZARDLEVEL] = { 10000L, 25000L, 35000L, 40000L, 70000L };
+    long lTemp, TotalCost;
+    long PerCost;
+    _INT16 LimitingVariable, NumToBuild;
+
+    LoadStrings(350, 9, szTheOptions);
+
+    if (!PClan->TownHallHelp)
+    {
+      PClan->TownHallHelp = TRUE;
+      Help("Town Hall", ST_NEWBIEHLP);
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      /* show 'menu' */
+      if (Game.Data->InterBBS)
+        sprintf(szString, ST_VSTATHEADER, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszVillageName);
+      else
+        sprintf(szString, ST_VSTATHEADER, Village.Data->szName);
+      rputs(szString);
+
+      rputs(ST_LONGLINE);
+
+      sprintf(szString, ST_TMENUSTAT5, Village.Data->Empire.VaultGold);
+      rputs(szString);
+
+      /* church,
+         training hall,
+        + more on the way */
+
+      if (Village.Data->ChurchLevel == 0)
+        rputs(ST_BMENU3);
+      else if (Village.Data->ChurchLevel < MAX_CHURCHLEVEL)
+      {
+        sprintf(szString, ST_BMENU4, Village.Data->ChurchLevel+1);
+        rputs(szString);
+      }
+      else
+      {
+        sprintf(szString, ST_BMENU5, MAX_CHURCHLEVEL);
+        rputs(szString);
+      }
+
+      if (Village.Data->TrainingHallLevel == 0)
+        rputs(ST_BMENU6);
+      else if (Village.Data->TrainingHallLevel < MAX_THALLLEVEL)
+      {
+        sprintf(szString, ST_BMENU7, Village.Data->TrainingHallLevel+1);
+        rputs(szString);
+      }
+      else
+      {
+        sprintf(szString, ST_BMENU8, MAX_THALLLEVEL);
+        rputs(szString);
+      }
+
+      if (Village.Data->PawnLevel == 0)
+        rputs(ST_BMENU30);
+      else if (Village.Data->PawnLevel < MAX_PAWNLEVEL)
+      {
+        sprintf(szString, ST_BMENU31, Village.Data->PawnLevel+1);
+        rputs(szString);
+      }
+      else
+      {
+        sprintf(szString, ST_BMENU32, MAX_PAWNLEVEL);
+        rputs(szString);
+      }
+      if (Village.Data->WizardLevel == 0)
+        rputs(ST_BMENU33);
+      else if (Village.Data->WizardLevel < MAX_WIZARDLEVEL)
+      {
+        sprintf(szString, ST_BMENU34, Village.Data->WizardLevel+1);
+        rputs(szString);
+      }
+      else
+      {
+        sprintf(szString, ST_BMENU35, MAX_WIZARDLEVEL);
+        rputs(szString);
+      }
+
+      if (Village.Data->MarketLevel < MAX_MARKETLEVEL)
+      {
+        sprintf(szString, ST_BMENU36, Village.Data->MarketLevel+1);
+        rputs(szString);
+      }
+      else
+      {
+        sprintf(szString, "     |0CSmithy Level                |0B%d\n", Village.Data->MarketLevel);
+        rputs(szString);
+      }
+
+      /* more options */
+      rputs(ST_BMENU9);
+      rputs(ST_BMENU10);
+      rputs(ST_LONGLINE);
+
+      switch(GetChoice("", ST_ENTEROPTION, szTheOptions, "PZFCTH?QS", 'Q', TRUE))
+      {
+        case 'P' :  // pawn shop
+          Help("Pawn Shop", ST_RULERHLP);
+
+          if (Village.Data->PawnLevel == MAX_PAWNLEVEL)
+          {
+            rputs(ST_BMENU37);
+            break;
+          }
+          if (Village.Data->PawnLevel == 0)
+          {
+            sprintf(szString, ST_BMENU38,
+              PawnBuildCosts[0], Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < PawnBuildCosts[0])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU39) == YES)
+            {
+              Village.Data->Empire.VaultGold -= PawnBuildCosts[0];
+              Village.Data->PawnLevel = 1;
+
+              rputs(ST_BMENU40);
+              sprintf(szString, ST_BMENU41, Village.Data->szRulingClan);
+              News_AddNews(szString);
+              break;
+            }
+          }
+/* NO MORE REG
+          else if (Village.Data->PawnLevel == 3 && (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+            IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE))
+          {
+            rputs(ST_NEEDREGISTER);
+          }
+*/
+          else if (Village.Data->PawnLevel < MAX_PAWNLEVEL)
+          {
+            sprintf(szString, ST_BMENU42,
+              PawnBuildCosts[Village.Data->PawnLevel], Village.Data->PawnLevel+1, Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < PawnBuildCosts[ Village.Data->PawnLevel ])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU43) == YES)
+            {
+              Village.Data->Empire.VaultGold -= PawnBuildCosts[ Village.Data->PawnLevel ];
+              Village.Data->PawnLevel++;
+
+              sprintf(szString, ST_BMENU44, Village.Data->PawnLevel);
+              rputs(szString);
+
+              sprintf(szString, ST_BMENU45,
+                Village.Data->szRulingClan, Village.Data->PawnLevel);
+              News_AddNews(szString);
+              break;
+            }
+          }
+          break;
+        case 'Z' :  // wizard's shop
+          Help("Wizard's Shop", ST_RULERHLP);
+
+          if (Village.Data->WizardLevel == MAX_WIZARDLEVEL)
+          {
+            rputs(ST_BMENU46);
+            break;
+          }
+          if (Village.Data->WizardLevel == 0)
+          {
+            sprintf(szString, ST_BMENU47,
+              WizardBuildCosts[0], Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < WizardBuildCosts[0])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU48) == YES)
+            {
+              Village.Data->Empire.VaultGold -= WizardBuildCosts[0];
+              Village.Data->WizardLevel = 1;
+
+              rputs(ST_BMENU49);
+              sprintf(szString,
+              ST_BMENU50, Village.Data->szRulingClan);
+              News_AddNews(szString);
+              break;
+            }
+          }
+/* NO MORE REG
+          else if (Village.Data->WizardLevel == 3 && (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+            IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE))
+          {
+            rputs(ST_NEEDREGISTER);
+          }
+*/
+          else if (Village.Data->WizardLevel < MAX_WIZARDLEVEL)
+          {
+            sprintf(szString, ST_BMENU51,
+              WizardBuildCosts[Village.Data->WizardLevel], Village.Data->WizardLevel+1, Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < WizardBuildCosts[ Village.Data->WizardLevel ])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU52) == YES)
+            {
+              Village.Data->Empire.VaultGold -= WizardBuildCosts[ Village.Data->WizardLevel ];
+              Village.Data->WizardLevel++;
+
+              sprintf(szString, ST_BMENU53, Village.Data->WizardLevel);
+              rputs(szString);
+
+              sprintf(szString, ST_BMENU54,
+                Village.Data->szRulingClan, Village.Data->WizardLevel);
+              News_AddNews(szString);
+              break;
+            }
+          }
+          break;
+        case 'C' :  /* church */
+          Help("Church", ST_RULERHLP);
+
+          if (Village.Data->ChurchLevel == MAX_CHURCHLEVEL)
+          {
+            rputs(ST_BMENU11);
+            break;
+          }
+          if (Village.Data->ChurchLevel == 0)
+          {
+            // what will it cost
+            sprintf(szString, ST_BMENU12,
+              ChurchBuildCosts[0], Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < ChurchBuildCosts[0])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU13) == YES)
+            {
+              Village.Data->Empire.VaultGold -= ChurchBuildCosts[0];
+              Village.Data->ChurchLevel = 1;
+
+              rputs(ST_BMENU14);
+              sprintf(szString, ST_NEWSNEWCHURCH, Village.Data->szRulingClan);
+              News_AddNews(szString);
+              break;
+            }
+          }
+/* NO MORE REG
+          else if (Village.Data->ChurchLevel == 3 && (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+            IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE))
+          {
+            rputs(ST_NEEDREGISTER);
+          }
+*/
+          else if (Village.Data->ChurchLevel < MAX_CHURCHLEVEL)
+          {
+            sprintf(szString, ST_BMENU15, ChurchBuildCosts[Village.Data->ChurchLevel], Village.Data->ChurchLevel+1, Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < ChurchBuildCosts[ Village.Data->ChurchLevel ])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU16) == YES)
+            {
+              Village.Data->Empire.VaultGold -= ChurchBuildCosts[ Village.Data->ChurchLevel ];
+              Village.Data->ChurchLevel++;
+
+              sprintf(szString, ST_BMENU17, Village.Data->ChurchLevel);
+              rputs(szString);
+
+              sprintf(szString, ST_NEWSUPGRADECHURCH, Village.Data->szRulingClan, Village.Data->ChurchLevel);
+              News_AddNews(szString);
+              break;
+            }
+          }
+          break;
+        case 'T' :  /* training hall */
+          Help("Training Hall", ST_RULERHLP);
+
+          if (Village.Data->TrainingHallLevel == MAX_THALLLEVEL)
+          {
+            rputs(ST_BMENU18);
+            break;
+          }
+          if (Village.Data->TrainingHallLevel == 0)
+          {
+            sprintf(szString, ST_BMENU19, THallBuildCosts[0], Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < THallBuildCosts[0])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU20) == YES)
+            {
+              Village.Data->Empire.VaultGold -= THallBuildCosts[0];
+              Village.Data->TrainingHallLevel = 1;
+
+              rputs(ST_BMENU21);
+              sprintf(szString, ST_NEWSNEWTHALL, Village.Data->szRulingClan);
+              News_AddNews(szString);
+              break;
+            }
+          }
+/* NO MORE REG
+          else if (Village.Data->TrainingHallLevel == 3 && (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+            IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE))
+          {
+            rputs(ST_NEEDREGISTER);
+          }
+*/
+          else if (Village.Data->TrainingHallLevel < MAX_THALLLEVEL)
+          {
+            sprintf(szString, ST_BMENU22, THallBuildCosts[Village.Data->TrainingHallLevel], Village.Data->TrainingHallLevel+1, Village.Data->Empire.VaultGold);
+            rputs(szString);
+
+            if (Village.Data->Empire.VaultGold < THallBuildCosts[ Village.Data->TrainingHallLevel ])
+            {
+              rputs(ST_VILLNOAFFORD);
+              break;
+            }
+
+            if (YesNo(ST_BMENU23) == YES)
+            {
+              Village.Data->Empire.VaultGold -= THallBuildCosts[ Village.Data->TrainingHallLevel ];
+              Village.Data->TrainingHallLevel++;
+
+              sprintf(szString, ST_BMENU24, Village.Data->TrainingHallLevel);
+              rputs(szString);
+
+              sprintf(szString, ST_NEWSUPGRADETHALL, Village.Data->szRulingClan, Village.Data->TrainingHallLevel);
+              News_AddNews(szString);
+              break;
+            }
+          }
+          break;
+        case 'H' :  /* ruling help */
+          GeneralHelp(ST_RULERHLP);
+          break;
+        case 'Q' :    /* return to previous menu */
+          return;
+        case '?' :    /* redisplay options */
+          break;
+        case 'S' :  /* smithy */
+          Help("Smithy", ST_RULERHLP);
+
+          if (Village.Data->MarketLevel == MAX_MARKETLEVEL)
+          {
+            rputs("The smithy is at its highest level already\n%P");
+            break;
+          }
+/* NO MORE REG
+          else if (Village.Data->MarketLevel == 3 && (IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) == NFALSE ||
+            IsRegged(Config->szSysopName, Config->szBBSName, Config->szRegcode) != NTRUE))
+          {
+            rputs(ST_NEEDREGISTER);
+            break;
+          }
+*/
+
+          TotalCost = ((long)(Village.Data->MarketLevel+1)*(Village.Data->MarketLevel+1)*1250L) + 15000L;
+
+          sprintf(szString, ST_TOWN3, TotalCost, Village.Data->MarketLevel+1, Village.Data->Empire.VaultGold);
+          rputs(szString);
+
+          if (Village.Data->Empire.VaultGold < TotalCost)
+          {
+            rputs(ST_VILLNOAFFORD);
+            break;
+          }
+
+          if (YesNo(ST_TOWN4) == YES)
+          {
+            Village.Data->Empire.VaultGold -= TotalCost;
+            Village.Data->MarketLevel++;
+
+            sprintf(szString, ST_TOWN5, Village.Data->MarketLevel);
+            rputs(szString);
+
+            sprintf(szString, ST_NEWSSMITHY, Village.Data->szRulingClan, Village.Data->MarketLevel);
+            News_AddNews(szString);
+          }
+          break;
+      }
+    }
+	(void)LimitingVariable;
+	(void)lTemp;
+	(void)NumToBuild;
+	(void)PerCost;
+	(void)iTemp;
+  }
+
+
+
+// ------------------------------------------------------------------------- //
+
+  void EconomicsMenu ( void )
+  {
+    char *szTheOptions[7];
+    char szString[128];
+    _INT16 iTemp, OldTax;
+    long lTemp;
+
+    LoadStrings(390, 7, szTheOptions);
+
+    if (!PClan->TownHallHelp)
+    {
+      PClan->TownHallHelp = TRUE;
+      Help("Town Hall", ST_NEWBIEHLP);
+    }
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      /* show 'menu' */
+      if (Game.Data->InterBBS)
+        sprintf(szString, ST_VSTATHEADER, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszVillageName);
+      else
+        sprintf(szString, ST_VSTATHEADER, Village.Data->szName);
+      rputs(szString);
+
+      rputs(ST_LONGLINE);
+
+      sprintf(szString, ST_TMENUSTAT5, Village.Data->Empire.VaultGold);
+      rputs(szString);
+
+      sprintf(szString, ST_EMENU1, Village.Data->TaxRate);
+      rputs(szString);
+
+      sprintf(szString, ST_EMENU3, Village.Data->GST);
+      rputs(szString);
+
+      rputs(ST_EMENU7);
+
+      rputs(ST_EMENU8);
+      rputs(ST_EMENU9);
+      rputs(ST_LONGLINE);
+
+      switch(GetChoice("", ST_ENTEROPTION, szTheOptions, "TGWDH?Q", 'Q', TRUE))
+      {
+        case 'T' :  /* Tax rate */
+          Help("Tax Rate", ST_RULERHLP);
+
+          /* if already set tax today, don't allow it again */
+          if (Village.Data->SetTaxToday)
+            rputs(ST_EMENU10);  // tell him he can't set it more than once per day
+          else
+          {
+            /* figure out lowest tax rate and highest tax rate */
+            iTemp = (_INT16)GetLong(ST_EMENU11, Village.Data->TaxRate, 50);
+
+            /* if no change, do nothing */
+            if (iTemp == Village.Data->TaxRate)
+              break;
+
+            Village.Data->SetTaxToday = TRUE;
+
+            /* increasing the tax rate decreases/increases public approval */
+
+            /* going from 5% tax rate to an 8% rate means
+               8 - 5 = 3.  approval drops by 1 (3/3)
+               and momentum drops down by 3 */
+
+            OldTax = Village.Data->TaxRate;
+            Village.Data->TaxRate = iTemp;
+
+            sprintf(szString, ST_NEWSTAX1,
+              Village.Data->szRulingClan, Village.Data->TaxRate > OldTax ? "raised" : "lowered",
+                OldTax, Village.Data->TaxRate);
+            News_AddNews(szString);
+          }
+          break;
+        case 'G' :  /* GST */
+          Help("GST", ST_RULERHLP);
+
+          /* if already set today, don't allow it again */
+          if (Village.Data->SetGSTToday)
+            rputs(ST_EMENU15);
+          else
+          {
+            iTemp = (_INT16)GetLong(ST_EMENU16, Village.Data->GST, 50);
+
+            /* if no change, do nothing */
+            if (iTemp == Village.Data->GST)
+              break;
+
+            Village.Data->SetGSTToday = TRUE;
+
+            /* increasing the tax rate decreases/increases public approval */
+
+            /* going from 1% tax rate to an 7% rate means
+               7 - 1 = 6.  approval drops by 2 (6/3)
+               and momentum drops down by 6 */
+
+            OldTax = Village.Data->GST;
+            Village.Data->GST = iTemp;
+
+            sprintf(szString, ST_NEWSTAX3,
+              Village.Data->szRulingClan,
+              Village.Data->GST > OldTax ? "raised" : "lowered",
+              OldTax, Village.Data->GST);
+            News_AddNews(szString);
+          }
+          break;
+        case 'D' :  /* deposit in vault */
+          Help("Deposit into Vault", ST_RULERHLP);
+          lTemp = GetLong(ST_EMENU26, 0, PClan->Empire.VaultGold);
+
+          if (lTemp)
+          {
+            Village.Data->Empire.VaultGold += lTemp;
+            PClan->Empire.VaultGold -= lTemp;
+
+            sprintf(szString, ST_EMENU27, lTemp);
+            rputs(szString);
+
+            sprintf(szString, ST_NEWSDONATED, PClan->szName, lTemp);
+            News_AddNews(szString);
+          }
+          break;
+        case 'W' :  /* withdraw from vault */
+          Help("Withdraw from Vault", ST_RULERHLP);
+
+          if (PClan->VaultWithdrawals == 3)
+          {
+            /* can only do 3 withdrawals a day */
+            rputs(ST_EMENU28);
+            break;
+          }
+          PClan->VaultWithdrawals++;
+
+          lTemp = GetLong(ST_EMENU29, 0, Village.Data->Empire.VaultGold);
+
+          if (lTemp)
+          {
+            Village.Data->Empire.VaultGold -= lTemp;
+            PClan->Empire.VaultGold += lTemp;
+
+            sprintf(szString, ST_EMENU30, lTemp);
+            rputs(szString);
+
+            sprintf(szString, ST_NEWSEMBEZZLE, PClan->szName, lTemp);
+            News_AddNews(szString);
+          }
+          break;
+        case 'H' :  /* ruling help */
+          GeneralHelp(ST_RULERHLP);
+          break;
+        case 'Q' :    /* return to previous menu */
+          return;
+        case '?' :    /* redisplay options */
+          break;
+      }
+    }
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  _INT16 TownHallMenu ( void )
+  {
+    char *szTheOptions[17];
+    char szString[255], szSpeech[128];
+    _INT16 iTemp, OldRate;
+    _INT16 LimitingVariable, NumToTrain;
+    long GuardCost;
+
+    LoadStrings(335, 15, szTheOptions);
+    szTheOptions[15] = "Conscription Rate";
+    szTheOptions[16] = "Toggle Empire Stats";
+
+    /* get a choice */
+    for (;;)
+    {
+      rputs("\n\n");
+
+      /* show 'menu' */
+      if (Game.Data->InterBBS)
+        sprintf(szString, ST_VSTATHEADER, IBBS.Data->Nodes[IBBS.Data->BBSID-1].Info.pszVillageName);
+      else
+        sprintf(szString, ST_VSTATHEADER, Village.Data->szName);
+      rputs(szString);
+
+      rputs(ST_LONGLINE);
+      sprintf(szString, ST_TMENUSTAT0, Village.Data->RulingDays);
+      rputs(szString);
+      sprintf(szString, ST_TMENUSTAT7, Village.Data->Empire.VaultGold);
+      rputs(szString);
+      sprintf(szString, ST_TMENUSTAT8, Village.Data->ConscriptionRate);
+      rputs(szString);
+/*    sprintf(szString, ST_TMENUSTAT9, Village.Data->GovtSystem == GS_DEMOCRACY ?
+        "Democracy" : "Dictatorship");
+      rputs(szString);
+
+      sprintf(szString, ST_TMENUSTAT10, Village.Data->ShowEmpireStats ?
+        "Available" : "Unavailable");
+      rputs(szString);
+*/
+
+      rputs(ST_LONGLINE);
+
+      switch(GetChoice("Town1", ST_ENTEROPTION, szTheOptions, "SECLHMD!V?Q/BGPRT", 'Q', TRUE))
+      {
+/*      case 'T' :
+          ToggleEmpireStats();
+          break;
+*/
+        case 'R' :  // conscription rate
+          Help("Conscription Rate", ST_RULERHLP);
+
+          /* if already set rate today, don't allow it again */
+          if (Village.Data->SetConToday)
+            // rputs("Can't set conscription rate more than once a day.\n%P");  // tell him he can't set it more than once per day
+            rputs(ST_TMENU19);  // tell him he can't set it more than once per day
+          else
+          {
+            /* figure out lowest rate rate and highest rate */
+            iTemp = (_INT16)GetLong(ST_TMENU20, Village.Data->ConscriptionRate, 20);
+
+            /* if no change, do nothing */
+            if (iTemp == Village.Data->ConscriptionRate)
+						break;
+
+            Village.Data->SetConToday = TRUE;
+
+            OldRate = Village.Data->ConscriptionRate;
+            Village.Data->ConscriptionRate = iTemp;
+
+            // sprintf(szString, ">> %s %s the conscription rate from %d to %d\n\n",
+            sprintf(szString, ST_NEWS4,
+              Village.Data->szRulingClan, Village.Data->ConscriptionRate > OldRate ? "raised" : "lowered",
+              OldRate, Village.Data->ConscriptionRate);
+            News_AddNews(szString);
+          }
+          break;
+        case 'P' :  // manage empire
+          Empire_Manage(&Village.Data->Empire);
+          break;
+/*      case 'G' :  // system of gov't
+          ChangeGovtSystem();
+          break;
+*/
+        case 'B' :  // voting booth
+/*        if (Village.Data->GovtSystem == GS_DICTATOR)
+          {
+            // rputs("This town is under dictatorial rule.  Voting is disabled.\n");
+            rputs(ST_TMENU21);
+          }
+          else
+            VotingBooth();
+*/
+            VotingBooth();
+          break;
+        case 'E' :  /* economics */
+          EconomicsMenu();
+          break;
+        case 'V' :  /* view clan stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case 'L' :    /* flag scheme */
+          ChangeFlagScheme();
+          break;
+        case 'C' :    /* change colour scheme */
+          ChangeColourScheme();
+          break;
+        case 'M' :  /* make announcement */
+          /* enter announcement */
+          rputs(ST_TMENU11);
+          szSpeech[0] = 0;
+          GetStr(szSpeech, 70, FALSE);
+
+          if (szSpeech[0] == 0)
+          {
+            rputs(ST_ABORTED);
+            break;
+          }
+
+          sprintf(szString, ST_NEWSRULERSPEECH, Village.Data->szRulingClan);
+          News_AddNews(szString);
+          News_AddNews(szSpeech);
+          News_AddNews("|16\n\n");
+          break;
+        case 'D' :  /* public discussion */
+          Menus_ChatRoom("public.txt");
+          break;
+        case '!' :  /* abdicate */
+          /* ask if he wants to abdicate for sure */
+          if (NoYes(ST_TMENU15Q) == YES)
+          {
+            /* reset Village stats */
+            Village.Data->RulingClanId[0] = -1;
+            Village.Data->RulingClanId[1] = -1;
+            Village.Data->szRulingClan[0] = 0;
+
+            Village.Data->RulingDays = 0;
+            Village.Data->GovtSystem = GS_DEMOCRACY;
+
+            /* reduce score */
+            /* reset user stats */
+            PClan->WasRulerToday = TRUE;
+            PClan->Points -= 100;
+
+            sprintf(szString, ST_NEWSABDICATED, PClan->szName);
+            News_AddNews(szString);
+
+            return 0;
+          }
+          break;
+        case 'H' :  /* ruling help */
+          GeneralHelp(ST_RULERHLP);
+          break;
+        case 'S' :  /* structures menu */
+          BuildMenu();
+          break;
+        case 'Q' :  /* return to previous menu */
+          return 0;
+        case '?' :  /* redisplay options */
+          break;
+        case '/' :  // chat villagers
+          ChatVillagers(WN_TOWNHALL);
+          break;
+      }
+    }
+	(void)LimitingVariable;
+	(void)NumToTrain;
+	(void)GuardCost;
+  }
+
+
+
+
+// ------------------------------------------------------------------------- //
+
+  void Village_NewRuler ( void )
+  {
+    char szString[128];
+
+    /* if they WERE the rulers today, can't become rulers again */
+    if (PClan->WasRulerToday)
+    {
+      rputs("|15Your clan cannot claim rule again until tomorrow.\n%P");
+      return;
+    }
+
+    Village.Data->RulingClanId[0] = PClan->ClanID[0];
+    Village.Data->RulingClanId[1] = PClan->ClanID[1];
+    Village.Data->RulingDays = 0;
+
+    strcpy(Village.Data->szRulingClan, PClan->szName);
+
+    sprintf(szString, ST_NEWSNEWRULER, Village.Data->szRulingClan);
+    News_AddNews(szString);
+
+    /* give him points for becoming ruler */
+    PClan->Points += 20L;
+
+    rputs("|15Your clan now rules the village!\n");
+    door_pause();
+  }
+
+
+// ------------------------------------------------------------------------- //
+
+  void Village_Destroy ( void )
+    /*
+     * This function frees up mem used by Village.
+     *
+     */
+  {
+    free(Village.Data);
+    Village.Initialized = FALSE;
+  }
+
+  BOOL Village_Read ( void )
+    /*
+     * This function reads in the village.dat data and places it in Village.
+     *
+     */
+  {
+    FILE *fp;
+
+    fp = _fsopen(ST_VILLAGEDATFILE, "rb", SH_DENYWR);
+    if (!fp)  return FALSE;
+
+    EncryptRead(Village.Data, (long)sizeof(struct village_data), fp, XOR_VILLAGE);
+    fclose(fp);
+    return TRUE;
+  }
+
+  void Village_Write ( void )
+    /*
+     * This function writes the Village data to village.dat.
+     *
+     */
+  {
+    FILE *fp;
+
+    if (Village.Initialized == FALSE)
+    {
+      Village_Destroy();
+      System_Error("Village not initialized!\n");
+    }
+
+    Village.Data->CRC = CRCValue(Village.Data, sizeof(struct village_data) - sizeof(long));
+
+    fp = _fsopen(ST_VILLAGEDATFILE, "wb", SH_DENYRW);
+    if (fp)
+    {
+      EncryptWrite(Village.Data, sizeof(struct village_data), fp, XOR_VILLAGE);
+      fclose(fp);
+    }
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Village_Reset ( void )
+  {
+    Village.Data->PublicMsgIndex = 1;
+
+    Village.Data->TownType = -1;      /* unknown for now */
+    Village.Data->TaxRate = 0;        /* no taxes */
+    Village.Data->InterestRate = 0;   /* 0% interest rate */
+    Village.Data->GST = 0;        /* no gst */
+    Village.Data->Empire.VaultGold = 45000L; /* some money to begin with */
+    Village.Data->ConscriptionRate = 10;
+
+    Village.Data->RulingClanId[0] = -1; /* no ruling clan yet */
+    Village.Data->RulingClanId[1] = -1;
+
+    Village.Data->szRulingClan[0] = 0;
+    Village.Data->RulingDays = 0;
+    Village.Data->GovtSystem = GS_DEMOCRACY;
+
+
+    Village.Data->MarketLevel = 0;      /* weaponshop level */
+    Village.Data->TrainingHallLevel = 0;
+    Village.Data->ChurchLevel = 0;
+    Village.Data->PawnLevel = 0;
+    Village.Data->WizardLevel = 0;
+
+    Village.Data->SetTaxToday = FALSE;
+    Village.Data->SetInterestToday = FALSE;
+    Village.Data->SetGSTToday = FALSE;
+    Village.Data->SetConToday = FALSE;
+
+    Village.Data->UpMarketToday = FALSE;
+    Village.Data->UpTHallToday = FALSE;
+    Village.Data->UpChurchToday = FALSE;
+    Village.Data->UpPawnToday = FALSE;
+    Village.Data->UpWizToday = FALSE;
+    Village.Data->ShowEmpireStats = FALSE;
+
+    ClearFlags(Village.Data->HFlags);
+    ClearFlags(Village.Data->GFlags);
+
+    Empire_Create(&Village.Data->Empire, FALSE);
+    strcpy(Village.Data->Empire.szName, Village.Data->szName);
+    Village.Data->Empire.Land = 500;      // village starts off with this
+    Village.Data->Empire.Buildings[B_BARRACKS] = 10;
+    Village.Data->Empire.Buildings[B_WALL] = 10;
+    Village.Data->Empire.Buildings[B_TOWER] = 5;
+    Village.Data->Empire.Buildings[B_STEELMILL] = 5;
+    Village.Data->Empire.Buildings[B_BUSINESS] = 10;
+    Village.Data->Empire.Army.Footmen = 100;
+    Village.Data->Empire.Army.Axemen = 25;
+
+    Village.Data->CostFluctuation = 5 - RANDOM(11);
+    Village.Data->MarketQuality = MQ_AVERAGE;
+
+    Village.Data->CRC = CRCValue(&Village.Data, sizeof(struct village_data) - sizeof(long));
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Village_Maint ( void )
+  {
+    _INT16 MarketIndex;
+    char *szQuality[4] = { "Average", "Good", "Very Good", "Excellent" },
+         szString[255];
+
+    DisplayStr("* Village_Maint()\n");
+
+    if (Village.Data->Empire.VaultGold < 0)
+      Village.Data->Empire.VaultGold = 0;
+
+    Village.Data->SetTaxToday       = FALSE;
+    Village.Data->SetInterestToday  = FALSE;
+    Village.Data->SetGSTToday       = FALSE;
+    Village.Data->SetConToday       = FALSE;
+
+    Village.Data->UpMarketToday     = FALSE;
+    Village.Data->UpTHallToday      = FALSE;
+    Village.Data->UpChurchToday     = FALSE;
+    Village.Data->UpPawnToday       = FALSE;
+    Village.Data->UpWizToday        = FALSE;
+
+    if (Village.Data->ConscriptionRate > 20)
+      Village.Data->ConscriptionRate = 20;
+
+    ClearFlags(Village.Data->HFlags);
+
+    if (Village.Data->RulingClanId[0] != -1)
+      Village.Data->RulingDays++;
+
+		// choose a new ruler if possible
+    ChooseNewLeader();
+
+    // figure out village fluctuation costs
+    MarketIndex = RANDOM(15);
+
+    if (MarketIndex < 7)
+    {
+      Village.Data->CostFluctuation = 5 - RANDOM(11);
+      Village.Data->MarketQuality = MQ_AVERAGE;
+    }
+    else if (MarketIndex < 11)
+    {
+      Village.Data->CostFluctuation = RANDOM(10);
+      Village.Data->MarketQuality = MQ_GOOD;
+    }
+    else if (MarketIndex < 13)
+    {
+      Village.Data->CostFluctuation = 10 + RANDOM(10);
+      Village.Data->MarketQuality = MQ_VERYGOOD;
+    }
+    else
+    {
+      Village.Data->CostFluctuation = 20 + RANDOM(10);
+      Village.Data->MarketQuality = MQ_EXCELLENT;
+    }
+
+    sprintf(szString, "|0A � |0CWeapon quality today is |0B%s\n\n",
+      szQuality[Village.Data->MarketQuality]);
+    News_AddNews(szString);
+
+    Empire_Maint ( &Village.Data->Empire );
+
+
+    Village_Write();
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Village_Init ( void )
+    /*
+     * This function initializes Village data.
+     *
+     */
+  {
+    if (Verbose)
+    {
+      DisplayStr("> Village_Init()\n");
+      delay(500);
+    }
+
+    Village.Data = malloc(sizeof(struct village_data));
+    CheckMem(Village.Data);
+	Village.Initialized = TRUE;
+
+    if (!Village_Read())
+    {
+      Village_Destroy();
+      System_Error("Village.Dat not found!\n");
+    }
+
+    // ensure CRC is correct
+    if (CheckCRC(Village.Data, sizeof(struct village_data) - sizeof(long), Village.Data->CRC) == FALSE)
+    {
+      Village_Destroy();
+      System_Error("Village data corrupt!\n");
+    }
+
+    Door_SetColorScheme( Village.Data->ColorScheme );
+
+    if (Verbose)
+    {
+      DisplayStr("> Village_Init done()\n");
+      delay(500);
+    }
+
+  }
+
+// ------------------------------------------------------------------------- //
+
+  void Village_Close ( void )
+    /*
+     * This function initializes Village data.
+     *
+     */
+  {
+    if (Village.Initialized == FALSE) return;
+
+    Village_Write();
+    Village_Destroy();
+  }
+
diff --git a/src/doors/clans-src/village.h b/src/doors/clans-src/village.h
new file mode 100644
index 0000000000000000000000000000000000000000..5093e4cca2a5f0e4ec5ef878bcbd70f6ecec212d
--- /dev/null
+++ b/src/doors/clans-src/village.h
@@ -0,0 +1,12 @@
+
+  void Village_Init ( void );
+  void Village_Close ( void );
+
+  void Village_Maint ( void );
+
+  void Village_NewRuler ( void );
+
+  _INT16 OutsiderTownHallMenu ( void );
+  _INT16 TownHallMenu ( void );
+
+  void Village_Reset ( void );
diff --git a/src/doors/clans-src/voting.c b/src/doors/clans-src/voting.c
new file mode 100644
index 0000000000000000000000000000000000000000..03f6ff93cb1875eeee53dcd29468511ebd4dbe48
--- /dev/null
+++ b/src/doors/clans-src/voting.c
@@ -0,0 +1,370 @@
+/*
+
+The Clans BBS Door Game
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+/*
+ * Voting module
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#ifdef __unix__
+#include "unix_wrappers.h"
+#else
+#include <dos.h>
+#endif
+#include <errno.h>
+#include <string.h>
+
+#include "structs.h"
+#include "language.h"
+#include "mstrings.h"
+#include "door.h"
+#include "input.h"
+#include "news.h"
+#include "myopen.h"
+#include "user.h"
+#include "help.h"
+
+extern struct clan *PClan;
+extern struct Language *Language;
+extern struct village Village;
+
+  _INT16 GetVotes ( _INT16 TopCandidates[50][2], _INT16 TopVotes[50], BOOL UserOnline)
+  {
+    FILE *fpPlayerFile;
+    char szFileName[50];
+    _INT16 CurClan, iTemp, CurVote, NumVotes, NumUndecided = 0,
+      ClanID[2];
+    struct clan *TmpClan;
+    long Offset;
+
+    strcpy(szFileName, ST_CLANSPCFILE);
+
+    TmpClan = malloc(sizeof(struct clan));
+    CheckMem(TmpClan);
+
+    fpPlayerFile = fopen(szFileName, "r+b");
+    if (!fpPlayerFile)
+    {
+      TopCandidates[0][0] = -1;
+      TopCandidates[0][1] = -1;
+      free(TmpClan);
+      return 0;  /* failed to find clan */
+    }
+
+
+    // initialize votes to -1
+    for (CurVote = 0; CurVote < 50; CurVote++)
+    {
+      TopCandidates[CurVote][0] = -1;
+      TopCandidates[CurVote][1] = -1;
+      TopVotes[CurVote] = 0;
+    }
+
+    for (CurClan = 0;; CurClan++)
+    {
+      /* go through file till you find clan he wants */
+
+      Offset = (long)CurClan * (sizeof(struct clan) + 6L*sizeof(struct pc));
+      if (fseek(fpPlayerFile, Offset, SEEK_SET))
+      {
+        break;  /* couldn't fseek, so exit */
+      }
+
+      if (EncryptRead(TmpClan, sizeof(struct clan), fpPlayerFile, XOR_USER) == 0)
+        break;  /* stop reading if no more players found */
+
+      /* skip if deleted clan */
+      if (TmpClan->ClanID[0] == -1)
+        continue;
+
+      // skip if it's this user and he's online
+      if (UserOnline &&
+        TmpClan->ClanID[0] == PClan->ClanID[0] &&
+        TmpClan->ClanID[1] == PClan->ClanID[1])
+        continue;
+
+      // skip vote if undecided
+      if (TmpClan->ClanRulerVote[0] == -1)
+      {
+        NumUndecided++;
+        continue;
+      }
+
+      // see if who he voted for is in list, if not, add to it
+      for (CurVote = 0; CurVote < 50; CurVote++)
+      {
+        if (TopCandidates[CurVote][0] == TmpClan->ClanRulerVote[0] &&
+          TopCandidates[CurVote][1] == TmpClan->ClanRulerVote[1])
+        {
+          // found match, increment this vote
+          TopVotes[CurVote]++;
+          break;
+        }
+
+        // if -1, set this vote as our user's choice and increment votes
+        if (TopCandidates[CurVote][0] == -1)
+        {
+          TopCandidates[CurVote][0] = TmpClan->ClanRulerVote[0];
+          TopCandidates[CurVote][1] = TmpClan->ClanRulerVote[1];
+          TopVotes[CurVote] = 1;
+          break;
+        }
+      }
+    }
+    fclose(fpPlayerFile);
+
+    free(TmpClan);
+    TmpClan = NULL;
+
+    // now add on the current user's stats
+
+    // see if who he voted for is in list, if not, add to it
+    if (UserOnline && PClan->ClanRulerVote[0] != -1)
+      for (CurVote = 0; CurVote < 50; CurVote++)
+      {
+        if (TopCandidates[CurVote][0] == PClan->ClanRulerVote[0] &&
+          TopCandidates[CurVote][1] == PClan->ClanRulerVote[1])
+        {
+          // found match, increment this vote
+          TopVotes[CurVote]++;
+          break;
+        }
+
+        // if -1, set this vote as our user's choice and increment votes
+        if (TopCandidates[CurVote][0] == -1)
+        {
+          TopCandidates[CurVote][0] = PClan->ClanRulerVote[0];
+          TopCandidates[CurVote][1] = PClan->ClanRulerVote[1];
+          TopVotes[CurVote] = 1;
+          break;
+        }
+      }
+    else if (UserOnline && PClan->ClanRulerVote[0] == -1)
+      NumUndecided++;
+
+
+    // sort it out
+    for (iTemp = 0; iTemp < 50; iTemp++)
+      for (CurVote = 0; CurVote < 49; CurVote++)
+      {
+        if (TopVotes[CurVote] < TopVotes[CurVote+1])
+        {
+          NumVotes = TopVotes[CurVote];
+          TopVotes[CurVote] = TopVotes[CurVote+1];
+          TopVotes[CurVote+1] = NumVotes;
+
+          ClanID[0] = TopCandidates[CurVote][0];
+          ClanID[1] = TopCandidates[CurVote][1];
+
+          TopCandidates[CurVote][0] = TopCandidates[CurVote+1][0];
+          TopCandidates[CurVote][1] = TopCandidates[CurVote+1][1];
+
+          TopCandidates[CurVote+1][0] = ClanID[0];
+          TopCandidates[CurVote+1][1] = ClanID[1];
+        }
+      }
+
+    return NumUndecided;
+  }
+
+  void VotingBooth ( void )
+  {
+    _INT16 TopCandidates[50][2];
+    _INT16 TopVotes[50], ClanID[2], iTemp, Undecided;
+    char szName[25], szString[128];
+    char *szTheOptions[4], *szTop10Names[10];
+    BOOL Done = FALSE;
+
+    if (!PClan->VoteHelp)
+    {
+      PClan->VoteHelp = TRUE;
+      Help("Voting Booth", ST_NEWBIEHLP);
+      rputs("\n%P");
+    }
+
+    LoadStrings(1310, 4, szTheOptions);
+
+    // allocate mem for top 10 names
+    for (iTemp = 0; iTemp < 10; iTemp++)
+      szTop10Names[iTemp] = MakeStr(25);
+
+    while (!Done)
+    {
+      Undecided = GetVotes(TopCandidates, TopVotes, TRUE);
+
+      // get top 10 names
+      for (iTemp = 0; iTemp < 10; iTemp++)
+      {
+        if (TopCandidates[iTemp][0] == -1)
+          break;
+
+        GetClanNameID(szTop10Names[iTemp], TopCandidates[iTemp]);
+      }
+
+      // show top votes to user
+
+      rputs(ST_LONGLINE);
+      rputs(" |07Rank Clan              Votes\n");
+
+      for (iTemp = 0; iTemp < 10; iTemp++)
+      {
+        if (TopCandidates[iTemp][0] == -1)
+          break;
+
+        sprintf(szString, "|0B%3d.  |0C%-20s %d\n", iTemp+1,
+          szTop10Names[iTemp], TopVotes[iTemp]);
+        rputs(szString);
+      }
+      sprintf(szString, "      |0C%-20s %d\n", "Undecided", Undecided );
+      rputs(szString);
+
+      if (PClan->ClanRulerVote[0] != -1)
+      {
+        GetClanNameID(szName, PClan->ClanRulerVote);
+      }
+      else
+        strcpy(szName, "Undecided");
+
+      sprintf(szString, "\n |0CYour Vote: |0B%s\n", szName);
+      rputs(szString);
+
+      switch(GetChoice("Voting Booth", ST_ENTEROPTION, szTheOptions, "Q?VC", 'Q', TRUE))
+      {
+        case 'Q' :    /* Quit */
+          Done = TRUE;
+          break;
+        case '?' :    /* redisplay options */
+          break;
+        case 'V' :    /* stats */
+          ClanStats(PClan, TRUE);
+          break;
+        case 'C' :    /* change vote */
+          rputs("|0CEnter a blank line to become undecided\n");
+          if (GetClanID( ClanID, FALSE, FALSE, -1, -1 ) == FALSE)
+          {
+            rputs("You are now undecided.\n");
+            PClan->ClanRulerVote[0] = -1;
+            PClan->ClanRulerVote[1] = -1;
+          }
+          else
+          {
+            rputs("Vote changed.\n");
+            PClan->ClanRulerVote[0] = ClanID[0];
+            PClan->ClanRulerVote[1] = ClanID[1];
+          }
+          break;
+      }
+    }
+
+    for (iTemp = 0; iTemp < 10; iTemp++)
+      free(szTop10Names[iTemp]);
+  }
+
+  void ChooseNewLeader ( void )
+  {
+    _INT16 TopCandidates[50][2];
+    _INT16 TopVotes[50], /*ClanID[2],*/ iTemp, MostVotes, NumTied;
+    _INT16 NewRulerID[2];
+    char szName[25], szString[128];
+
+    // if voting not allowed, just write in news that the dictatorship
+    // continues
+/*
+    if (Village.GovtSystem == GS_DICTATOR && Village.RulingClanId[0] != -1)
+    {
+      GetClanNameID(szName, Village.RulingClanId);
+
+      // sprintf(szString, ">> %s's reign as dictator continues.\n\n",
+      sprintf(szString, ST_NEWS0, szName);
+      AddNews(szString);
+      return;
+    }
+*/
+
+    // get sorted votes
+    GetVotes(TopCandidates, TopVotes, FALSE);
+
+    // if no votes, do nothing
+    if (TopCandidates[0][0] == -1)
+      return;
+
+    // find the top one
+
+    MostVotes = TopVotes[0];
+
+    // eliminate all those who have less than this (this is done because there
+    // may be a tie)
+
+    for (iTemp = 0; iTemp < 50; iTemp++)
+      if (TopVotes[iTemp] < MostVotes)
+        break;
+
+    // where we stopped is the amount of votes tied for first place
+    NumTied = iTemp-1;
+
+    if (NumTied == 0)
+    {
+      // only one guy at the top, make him the new ruler
+      NewRulerID[0] = TopCandidates[0][0];
+      NewRulerID[1] = TopCandidates[0][1];
+    }
+    else
+    {
+      // choose one at random
+      iTemp = RANDOM(NumTied);
+
+      NewRulerID[0] = TopCandidates[iTemp][0];
+      NewRulerID[1] = TopCandidates[iTemp][1];
+    }
+
+    // get his name, put it in the news
+    GetClanNameID(szName, NewRulerID);
+
+    // if same as yesterday's ruler, just tell people he was re-elected
+    if (NewRulerID[0] == Village.Data->RulingClanId[0] &&
+      NewRulerID[1] == Village.Data->RulingClanId[1])
+    {
+      // sprintf(szString, ">> %s is re-elected as the leader of town!\n\n",
+      sprintf(szString, ST_NEWS1, szName);
+      News_AddNews(szString);
+    }
+    else
+    {
+      // sprintf(szString, ">> %s is elected as the new leader of town!\n\n",
+      sprintf(szString, ST_NEWS2, szName);
+      News_AddNews(szString);
+
+      // make him the new ruler
+      Village.Data->RulingClanId[0] = NewRulerID[0];
+      Village.Data->RulingClanId[1] = NewRulerID[1];
+      strcpy(Village.Data->szRulingClan, szName);
+      Village.Data->RulingDays = 0;
+
+      // make sure voting is allowed for the new ruler
+      Village.Data->GovtSystem = GS_DEMOCRACY;
+
+      // write message? -- no need, pretty obvious if it's first thing
+      // in the news
+    }
+  }
diff --git a/src/doors/clans-src/voting.h b/src/doors/clans-src/voting.h
new file mode 100644
index 0000000000000000000000000000000000000000..658f67b5cd7a5b01e39d42ec09f2abfbb2b8c463
--- /dev/null
+++ b/src/doors/clans-src/voting.h
@@ -0,0 +1,4 @@
+
+  void VotingBooth ( void );
+
+  void ChooseNewLeader ( void );
diff --git a/src/doors/clans-src/w32conv.c b/src/doors/clans-src/w32conv.c
new file mode 100644
index 0000000000000000000000000000000000000000..7498c2b8f8417e8f1278f60f487fdc9c75fdbf12
--- /dev/null
+++ b/src/doors/clans-src/w32conv.c
@@ -0,0 +1,291 @@
+/*
+
+The Clans Win32 Datafile Conversion Utility
+Copyright (C) 2002 Michael Dillon
+Copyright (C) 1997-2002 Allen Ussher
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+/* w32conv.c was written by Michael Dillon.  It employs structures created by
+   and under the authority of Allen Ussher. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "structs.h"
+
+#ifndef _WIN32
+# pragma message("This conversion program was intended for early Win32 versions of The Clans")
+#endif
+
+#define CLANS_PCFILE "CLANS.PC"
+#define CLANS_PCFILE_NEW "NEW.PC"
+#define CLANS_PCFILE_BACKUP "CLANS.PC.OLD"
+
+struct old_clan {
+  _INT16 ClanID[2];
+  char szUserName[30];
+  char szName[25];
+  char Symbol[21];
+
+  char QuestsDone[8], QuestsKnown[8];
+
+  char PFlags[8], DFlags[8];
+  char ChatsToday, TradesToday;
+
+	_INT16 ClanRulerVote[2];		// who are you voting for as the ruler?
+
+	_INT16 Alliances[MAX_ALLIES];		// alliances change from BBS to BBS, -1
+                                // means no alliance, 0 = first one, ID
+                                // that is...
+
+  long Points;
+  char szDateOfLastGame[11];
+
+  _INT16 FightsLeft, ClanFights,
+      MineLevel;
+
+  _INT16 WorldStatus, DestinationBBS;
+
+	char VaultWithdrawals;
+
+  _INT16 PublicMsgIndex;
+
+	_INT16 ClanCombatToday[MAX_CLANCOMBAT][2];
+  _INT16 ClanWars;
+
+  struct pc *Member[MAX_MEMBERS];
+  struct item_data Items[MAX_ITEMS_HELD];
+
+	char ResUncToday, ResDeadToday ;
+
+  struct empire Empire;
+
+  // Help
+  char DefActionHelp : 1,
+       CommHelp      : 1,
+       MineHelp      : 1,
+       MineLevelHelp : 1,
+       CombatHelp    : 1,
+       TrainHelp     : 1,
+       MarketHelp    : 1,
+       PawnHelp      : 1,
+       WizardHelp    : 1,
+       EmpireHelp    : 1,
+       DevelopHelp   : 1,
+       TownHallHelp  : 1,
+       DestroyHelp   : 1,
+       ChurchHelp    : 1,
+       THallHelp     : 1,
+       SpyHelp       : 1,
+       AllyHelp      : 1,
+       WarHelp       : 1,
+       VoteHelp      : 1,
+       TravelHelp    : 1,
+
+       WasRulerToday : 1,
+       MadeAlliance  : 1,
+       Protection    : 4,
+       FirstDay      : 1,
+       Eliminated    : 1,
+       QuestToday    : 1,
+       AttendedMass  : 1,
+       GotBlessing   : 1,
+       Prayed        : 1;
+  
+  long CRC;
+} PACKED;
+
+void display_error(const char *, ...);
+void check_pointer(void *);
+void cipher(void *, size_t, unsigned char);
+void convert_to_new(struct clan *, struct old_clan *);
+
+int main(void)
+{
+  FILE *fp_old, *fp_new;
+  struct clan *clan;
+  struct pc *pc;
+  struct old_clan *old_clan;
+  int i;
+
+  if (access(CLANS_PCFILE, 0) != 0)
+  {
+    display_error("Unable to open %s: %s\n", CLANS_PCFILE, strerror(errno));
+    return 1;
+  }
+
+  clan = (struct clan *)malloc(sizeof(struct clan));
+  old_clan = (struct old_clan *)malloc(sizeof(struct old_clan));
+  pc = (struct pc *)malloc(sizeof(struct pc));
+
+  fp_old = fopen(CLANS_PCFILE, "rb");
+  if (!fp_old)
+  {
+    display_error("Failure to open %s: %s\n", CLANS_PCFILE, strerror(errno));
+    exit(0);
+  }
+
+  fp_new = fopen(CLANS_PCFILE_NEW, "wb");
+  if (!fp_new)
+  {
+    display_error("Failure to open %s: %s\n", CLANS_PCFILE_NEW, strerror(errno));
+    exit(0);
+  }
+
+  do {
+    if (fread(old_clan, sizeof(struct old_clan), 1, fp_old))
+    {
+      cipher(old_clan, sizeof(struct old_clan), 9);
+      printf("Found Clan: %s\n", old_clan->szName);
+      convert_to_new(clan, old_clan);
+      cipher(clan, sizeof(struct clan), 9);
+      fwrite(clan, sizeof(struct clan), 1, fp_new);
+    }
+    else if (!feof(fp_old))
+    {
+      display_error("clan: fread error");
+      exit(0);
+    }
+    else
+      break; /* last entry was read */
+    for (i = 0; i < 6; i++)
+    {
+      if (fread(pc, sizeof(struct pc), 1, fp_old))
+        fwrite(pc, sizeof(struct pc), 1, fp_new);
+      else
+      {
+        display_error("pc: fread error");
+        exit(0);
+      }
+    }
+  } while (!feof(fp_old));
+
+  fclose(fp_old);
+  fflush(fp_new);
+  fclose(fp_new);
+
+  unlink(CLANS_PCFILE_BACKUP);
+  rename(CLANS_PCFILE, CLANS_PCFILE_BACKUP);
+  rename(CLANS_PCFILE_NEW, CLANS_PCFILE);
+
+  free(pc);
+  free(old_clan);
+  free(clan);
+  return 0;
+}
+
+void display_error(const char *format, ...)
+{
+  va_list args;
+
+  va_start(args, format);
+  vfprintf(stderr, format, args);
+  va_end(args);
+
+  fflush(stderr);
+}
+
+void check_pointer(void *ptr)
+{
+  if (!ptr)
+    display_error("Pointer is invalid!");
+  exit(0);
+}
+
+void cipher(void *obj, size_t obj_len, unsigned char xor_val)
+{
+  while (obj_len--)
+  {
+    *(char *)obj = *(char *)obj ^ xor_val;
+    obj = (char *)obj + 1;
+  }
+}
+
+void convert_to_new(struct clan *clan, struct old_clan *old_clan)
+{
+  int i;
+
+  clan->ClanID[0] = old_clan->ClanID[0];
+  clan->ClanID[1] = old_clan->ClanID[1];
+  strncpy(clan->szUserName, old_clan->szUserName, 30);
+  strncpy(clan->szName, old_clan->szName, 25);
+  strncpy(clan->Symbol, old_clan->Symbol, 21);
+  memcpy(clan->QuestsDone, old_clan->QuestsDone, 8);
+  memcpy(clan->QuestsKnown, old_clan->QuestsKnown, 8);
+  memcpy(clan->PFlags, old_clan->PFlags, 8);
+  memcpy(clan->DFlags, old_clan->DFlags, 8);
+  clan->ChatsToday = old_clan->ChatsToday;
+  clan->TradesToday = old_clan->TradesToday;
+  clan->ClanRulerVote[0] = old_clan->ClanRulerVote[0];
+  clan->ClanRulerVote[1] = old_clan->ClanRulerVote[1];
+  for (i = 0; i < MAX_ALLIES; i++)
+    clan->Alliances[i] = old_clan->Alliances[i];
+  clan->Points = old_clan->Points;
+  strncpy(clan->szDateOfLastGame, old_clan->szDateOfLastGame, 11);
+  clan->FightsLeft = old_clan->FightsLeft;
+  clan->ClanFights = old_clan->ClanFights;
+  clan->MineLevel = old_clan->MineLevel;
+  clan->WorldStatus = old_clan->WorldStatus;
+  clan->DestinationBBS = old_clan->DestinationBBS;
+  clan->VaultWithdrawals = old_clan->VaultWithdrawals;
+  clan->PublicMsgIndex = old_clan->PublicMsgIndex;
+  for (i = 0; i < MAX_CLANCOMBAT; i++)
+  {
+    clan->ClanCombatToday[i][0] = old_clan->ClanCombatToday[i][0];
+    clan->ClanCombatToday[i][1] = old_clan->ClanCombatToday[i][1];
+  }
+  clan->ClanWars = old_clan->ClanWars;
+  for (i = 0; i < MAX_MEMBERS; i++)
+    clan->Member[i] = old_clan->Member[i];
+  for (i = 0; i < MAX_ITEMS_HELD; i++)
+    memcpy(&clan->Items[i], &old_clan->Items[i], sizeof(struct item_data));
+  clan->ResUncToday = old_clan->ResUncToday;
+  clan->ResDeadToday = old_clan->ResDeadToday;
+  memcpy(&clan->Empire, &old_clan->Empire, sizeof(struct empire));
+  clan->DefActionHelp = old_clan->DefActionHelp;
+  clan->CommHelp = old_clan->CommHelp;
+  clan->MineHelp = old_clan->MineHelp;
+  clan->MineLevelHelp = old_clan->MineLevelHelp;
+  clan->CombatHelp = old_clan->CombatHelp;
+  clan->TrainHelp = old_clan->TrainHelp;
+  clan->MarketHelp = old_clan->MarketHelp;
+  clan->PawnHelp = old_clan->PawnHelp;
+  clan->WizardHelp = old_clan->WizardHelp;
+  clan->EmpireHelp = old_clan->EmpireHelp;
+  clan->DevelopHelp = old_clan->DevelopHelp;
+  clan->TownHallHelp = old_clan->TownHallHelp;
+  clan->DestroyHelp = old_clan->DestroyHelp;
+  clan->ChurchHelp = old_clan->ChurchHelp;
+  clan->THallHelp = old_clan->THallHelp;
+  clan->SpyHelp = old_clan->SpyHelp;
+  clan->AllyHelp = old_clan->AllyHelp;
+  clan->WarHelp = old_clan->WarHelp;
+  clan->VoteHelp = old_clan->VoteHelp;
+  clan->TravelHelp = old_clan->TravelHelp;
+  clan->WasRulerToday = old_clan->WasRulerToday;
+  clan->MadeAlliance = old_clan->MadeAlliance;
+  clan->Protection = old_clan->Protection;
+  clan->FirstDay = old_clan->FirstDay;
+  clan->Eliminated = old_clan->Eliminated;
+  clan->QuestToday = old_clan->QuestToday;
+  clan->AttendedMass = old_clan->AttendedMass;
+  clan->GotBlessing = old_clan->GotBlessing;
+  clan->Prayed = old_clan->Prayed;
+  clan->CRC = old_clan->CRC; 
+}
\ No newline at end of file
diff --git a/src/doors/clans-src/wb_fapnd.c b/src/doors/clans-src/wb_fapnd.c
new file mode 100644
index 0000000000000000000000000000000000000000..29aeb9a42918a5aa1d17f3de5e7fdc16440401b3
--- /dev/null
+++ b/src/doors/clans-src/wb_fapnd.c
@@ -0,0 +1,139 @@
+/* 
+** by: Walter Bright via Usenet C newsgroup
+**
+** modified by: Bob Stout based on a recommendation by Ray Gardner
+**
+** modified by: David Gersic to deal with binary files
+**
+** There is no point in going to asm to get high speed file copies. Since it
+** is inherently disk-bound, there is no sense (unless tiny code size is
+** the goal). Here's a C version that you'll find is as fast as any asm code
+** for files larger than a few bytes (the trick is to use large disk buffers):
+*/
+
+#include <stdlib.h>
+#ifdef __unix__
+#include <stdio.h>
+#include "unix_wrappers.h"
+#else
+#include <io.h>
+#endif
+#include <fcntl.h>
+
+#if !defined(__ZTC__) && !defined(__TURBOC__)
+ #include <sys/types.h>
+#endif
+
+#include "defines.h"
+#include <sys/stat.h>
+#include "snipfile.h"
+
+_INT16 file_append(char *from, char *to)
+{
+      _INT16 fdfrom,fdto;
+      _INT16 bufsiz;
+
+      fdfrom = open(from,O_RDONLY|O_BINARY,0);
+      if (fdfrom < 0)
+            return 1;
+
+      /* Open R/W by owner, R by everyone else        */
+
+#ifdef __unix__
+      fdto=open(to,O_BINARY|O_CREAT|O_APPEND|O_RDWR,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+#else
+      fdto=open(to,O_BINARY|O_CREAT|O_APPEND|O_RDWR,S_IREAD|S_IWRITE);
+#endif
+      if (fdto < 0)
+            goto err;
+
+      /* Use the largest buffer we can get    */
+
+      for (bufsiz = 0x4000; bufsiz >= 128; bufsiz >>= 1)
+      {
+            register char *buffer;
+
+            buffer = (char *) malloc(bufsiz);
+            if (buffer)
+            {
+                  while (1)
+                  {
+                        register _INT16 n;
+
+                        n = read(fdfrom,buffer,bufsiz);
+                        if (n == -1)                /* if error             */
+                              break;
+                        if (n == 0)                 /* if end of file       */
+                        {
+                              free(buffer);
+                              close(fdto);
+                              close(fdfrom);
+                              return 0;             /* success              */
+                        }
+                        if (n != write(fdto,buffer,(unsigned) n))
+                              break;
+                  }
+                  free(buffer);
+                  break;
+            }
+      }
+      close(fdto);
+      remove(to);                               /* delete any partial file  */
+err:  close(fdfrom);
+      return 1;
+}
+
+_INT16 file_copy(char *from, char *to)
+{
+      _INT16 fdfrom,fdto;
+      _INT16 bufsiz;
+
+      fdfrom = open(from,O_RDONLY|O_BINARY,0);
+      if (fdfrom < 0)
+            return 1;
+
+      /* Open R/W by owner, R by everyone else        */
+
+#ifdef __unix__
+      fdto=open(to,O_BINARY|O_CREAT|O_APPEND|O_RDWR,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+#else
+      fdto=open(to,O_BINARY|O_CREAT|O_TRUNC|O_RDWR,S_IREAD|S_IWRITE);
+#endif
+      if (fdto < 0)
+            goto err;
+
+      /* Use the largest buffer we can get    */
+
+      for (bufsiz = 0x4000; bufsiz >= 128; bufsiz >>= 1)
+      {
+            register char *buffer;
+
+            buffer = (char *) malloc(bufsiz);
+            if (buffer)
+            {
+                  while (1)
+                  {
+                        register _INT16 n;
+
+                        n = read(fdfrom,buffer,bufsiz);
+                        if (n == -1)                /* if error             */
+                              break;
+                        if (n == 0)                 /* if end of file       */
+                        {
+                              free(buffer);
+                              close(fdto);
+                              close(fdfrom);
+                              return 0;             /* success              */
+                        }
+                        if (n != write(fdto,buffer,(unsigned) n))
+                              break;
+                  }
+                  free(buffer);
+                  break;
+            }
+      }
+      close(fdto);
+      remove(to);                               /* delete any partial file  */
+err:  close(fdfrom);
+      return 1;
+}