From 9f74cf6941406005b63ad0cb804fad218bda6fb8 Mon Sep 17 00:00:00 2001 From: JT Traub Date: Mon, 9 Oct 2023 10:26:25 -0700 Subject: [PATCH] Remove the arcadia directory This code is mostly dead and hasn't been updated/built/looked at in a long time. It will still exist in git history, and I believe that Artyom is going to create 'last state/arcadia' branch which preserves it before merging all the neworigin and neworigins-v6 changes to master to bring things back to sanity. --- arcadia/Changes.txt | 287 -- arcadia/Makefile | 33 - arcadia/Notes.txt | 183 - arcadia/arcadia_intro.html | 1 - arcadia/aregion.cpp | 3053 ------------- arcadia/aregion.h | 550 --- arcadia/army1.cpp | 2580 ----------- arcadia/army1.h | 148 - arcadia/astring.cpp | 377 -- arcadia/astring.h | 76 - arcadia/battle1.cpp | 1136 ----- arcadia/battle1.h | 103 - arcadia/economy.cpp | 1791 -------- arcadia/edit.cpp | 3145 -------------- arcadia/extra.cpp | 1093 ----- arcadia/faction.cpp | 1017 ----- arcadia/faction.h | 265 -- arcadia/fileio.cpp | 466 -- arcadia/fileio.h | 136 - arcadia/formation1.cpp | 473 -- arcadia/formation1.h | 138 - arcadia/game.cpp | 2952 ------------- arcadia/game.h | 702 --- arcadia/gamedata.cpp | 5366 ----------------------- arcadia/gamedata.h | 578 --- arcadia/gamedefs.cpp | 73 - arcadia/gamedefs.h | 763 ---- arcadia/gameio.cpp | 132 - arcadia/gameio.h | 53 - arcadia/genrules.cpp | 8300 ------------------------------------ arcadia/hexside.cpp | 328 -- arcadia/hexside.h | 0 arcadia/html/arcadia.css | 18 - arcadia/html/intro.html | 1 - arcadia/html/styles.css | 18 - arcadia/items.cpp | 1504 ------- arcadia/items.h | 402 -- arcadia/magic.cpp | 629 --- arcadia/main.cpp | 188 - arcadia/map.cpp | 1501 ------- arcadia/market.cpp | 157 - arcadia/market.h | 69 - arcadia/modify.cpp | 1111 ----- arcadia/monsters.cpp | 68 - arcadia/monthorders.cpp | 2323 ---------- arcadia/npc.cpp | 479 --- arcadia/object.cpp | 568 --- arcadia/object.h | 186 - arcadia/orders.cpp | 489 --- arcadia/orders.h | 536 --- arcadia/parseorders.cpp | 4021 ----------------- arcadia/production.cpp | 125 - arcadia/production.h | 61 - arcadia/rules.cpp | 252 -- arcadia/runorders.cpp | 3816 ----------------- arcadia/shields.cpp | 52 - arcadia/shields.h | 43 - arcadia/skills.cpp | 493 --- arcadia/skills.h | 352 -- arcadia/skillshows.cpp | 3467 --------------- arcadia/soldier1.cpp | 741 ---- arcadia/soldier1.h | 131 - arcadia/specials.cpp | 637 --- arcadia/spells.cpp | 5344 ----------------------- arcadia/spells.h | 117 - arcadia/template.cpp | 593 --- arcadia/times.cpp | 328 -- arcadia/unit.cpp | 3082 ------------- arcadia/unit.h | 371 -- arcadia/world.cpp | 2628 ------------ 70 files changed, 73199 deletions(-) delete mode 100644 arcadia/Changes.txt delete mode 100644 arcadia/Makefile delete mode 100644 arcadia/Notes.txt delete mode 100644 arcadia/arcadia_intro.html delete mode 100644 arcadia/aregion.cpp delete mode 100644 arcadia/aregion.h delete mode 100644 arcadia/army1.cpp delete mode 100644 arcadia/army1.h delete mode 100644 arcadia/astring.cpp delete mode 100644 arcadia/astring.h delete mode 100644 arcadia/battle1.cpp delete mode 100644 arcadia/battle1.h delete mode 100644 arcadia/economy.cpp delete mode 100644 arcadia/edit.cpp delete mode 100644 arcadia/extra.cpp delete mode 100644 arcadia/faction.cpp delete mode 100644 arcadia/faction.h delete mode 100644 arcadia/fileio.cpp delete mode 100644 arcadia/fileio.h delete mode 100644 arcadia/formation1.cpp delete mode 100644 arcadia/formation1.h delete mode 100644 arcadia/game.cpp delete mode 100644 arcadia/game.h delete mode 100644 arcadia/gamedata.cpp delete mode 100644 arcadia/gamedata.h delete mode 100644 arcadia/gamedefs.cpp delete mode 100644 arcadia/gamedefs.h delete mode 100644 arcadia/gameio.cpp delete mode 100644 arcadia/gameio.h delete mode 100644 arcadia/genrules.cpp delete mode 100644 arcadia/hexside.cpp delete mode 100644 arcadia/hexside.h delete mode 100644 arcadia/html/arcadia.css delete mode 100644 arcadia/html/intro.html delete mode 100644 arcadia/html/styles.css delete mode 100644 arcadia/items.cpp delete mode 100644 arcadia/items.h delete mode 100644 arcadia/magic.cpp delete mode 100644 arcadia/main.cpp delete mode 100644 arcadia/map.cpp delete mode 100644 arcadia/market.cpp delete mode 100644 arcadia/market.h delete mode 100644 arcadia/modify.cpp delete mode 100644 arcadia/monsters.cpp delete mode 100644 arcadia/monthorders.cpp delete mode 100644 arcadia/npc.cpp delete mode 100644 arcadia/object.cpp delete mode 100644 arcadia/object.h delete mode 100644 arcadia/orders.cpp delete mode 100644 arcadia/orders.h delete mode 100644 arcadia/parseorders.cpp delete mode 100644 arcadia/production.cpp delete mode 100644 arcadia/production.h delete mode 100644 arcadia/rules.cpp delete mode 100644 arcadia/runorders.cpp delete mode 100644 arcadia/shields.cpp delete mode 100644 arcadia/shields.h delete mode 100644 arcadia/skills.cpp delete mode 100644 arcadia/skills.h delete mode 100644 arcadia/skillshows.cpp delete mode 100644 arcadia/soldier1.cpp delete mode 100644 arcadia/soldier1.h delete mode 100644 arcadia/specials.cpp delete mode 100644 arcadia/spells.cpp delete mode 100644 arcadia/spells.h delete mode 100644 arcadia/template.cpp delete mode 100644 arcadia/times.cpp delete mode 100644 arcadia/unit.cpp delete mode 100644 arcadia/unit.h delete mode 100644 arcadia/world.cpp diff --git a/arcadia/Changes.txt b/arcadia/Changes.txt deleted file mode 100644 index 1a0e8f233..000000000 --- a/arcadia/Changes.txt +++ /dev/null @@ -1,287 +0,0 @@ -Hi all, - -Arcadia IV: Xanaxor (named after the mage of the same name from Arcadia III: Nylandor) is now taking registrations. Because I am computer illiterate (except when it comes to C++ and the Atlantis code) registration will have to involve filling out the form below and emailing it to me. - -The rules for Arcadia IV may be found at http://home.arcor.de/oidipus/game4. Also there are a map of Xanaxor, the hero/magic skill tree, a list of changes from Atlantis 5.0 and the 'skillshows' file which lists all skill, item and object descriptions for the game. - -The game will take 12 players and the main landmass is approximately 120 hexes large. The map was handmade and every attempt made to balance the starting locations for tax/trade ability. Each player will be assigned at random to begin as an elf, dwarf or human; you get to select the race that your initial unit and home village will have. - -Turns will be run twice a week, most likely on Mondays and Thursdays or Fridays. Details on how to submit orders will arrive when the first turn is run. - -The client program Atlantis Little Helper (ALH) will parse all of the features present in Xanaxor, with a little modification to its configuration files. If we are lucky some kindly person from one of our pre-games will have prepared some fully functional config files which can be shared around ... - -Both of the GMs running the Arcadia series will be playing in Xanaxor. - -Bradley -================================= - - - -================================= -List of Changes for Arcadia IV: ---------------------------------- -Changes since the testgame/Xanaxino: - -Non-undead monsters no longer cause morale penalties, and no monsters are affected by morale penalties. -Tax has been moved to occur just before the other month-long orders -Unity/Bird Lore experience reduced. Wolf Lore/Trading experience increased. -Undead have an 80% chance of coming back to life following a battle in which they are killed, provided that they are controlled by a mage who survives the battle and are NOT killed by the spell Banish Undead. -Elves defence bonus removed -Produce items are now credited when send items are recieved, to avoid eg wood being produced then shared with a weaponsmith in the same turn. -Hero skills cannot be taught ---------------------------------- -Changes since Arcadia III: - -Table of races changed: (5 human, 5 dwarf, 5 elf, 2 other) - -Humans: raiders, barbarians, eskimos, nomads, tribesmen -Elves: ancient elves, wood elves, sea elves, high elves, tribal elves -Dwarves: plains dwarves, ice dwarves, hill dwarves, under dwarves, desert dwarves -Others: mermen, orcs - -Maximum skill levels (specialist / non-specialist skills) for units are: -4/2 for normal units -6/4 for leaders -8/6 for heros -6/4 for heros studying hero/magic skills - -Orders added: -SHARE (sets flag 'sharing' on/off) -SEND (sends goods to nearby regions) -COMMAND (takes command of faction) -TEMPLATE (stores a set of orders under given name (eg TEMPLATE Scout) ) -TYPE (applies a set of stored orders to the given unit, eg TYPE Scout) -LABEL (adds a label to a unit that only the owner can see) -ALL (issues orders to all units with the specified label) -SPOILS: SWIM & SAIL added -DISABLE (disables/re-enables an unwanted skill, eg summon wind) - -Orders removed from Arcadia III: -GIVEIF -RECRUIT - -HEROES: -Mages are renamed heroes -Leaders become leaders by studying leadership ($50); heroes become heroes when a leader studies heroship ($100). Leaders / heroes retain their race characteristics. -Hero/Mage specialities are innate, depending on the unit's race (eg barbarian or wood elf). -Wandering mages no longer exist. -Energy costs of spells no longer depend on race/speciality, though experience gained still does. -Energy is gained from the five base magic skills: Patterning, Mysticism, Winkey, Summoning and Artifact Lore. Battletraining and Charisma do not produce energy; nor do spells in those trees require energy. -There is now no hard limit on how many spells a mage may cast per month, and no extra energy cost to casting multiple spells. -A mage may not cast a particular spell more than once per month. -New magic tree. -Heros can execute a study order AND another monthlong order (other than study) in one turn. -Heros may not assassinate other heroes. -Magic shields gain a +1 bonus in combat, ie an energy shield at level 1 now functions as it used to at level 2. Force shield is unchanged. -Energy recharge rate listed in reports. -Magic skills may not be taught. - -ALIGNMENTS: -Factions take on one of four alignments: Human, Elven, Dwarven, or Independent, depending on the race of their commanding unit (who must be a hero). -Alignment of factions marked in reports if unit's faction is identified. -Maintenance cost of units of the same ethnicity as the faction alignment are: 10,20,100 silver for normal, leader and hero units. -Maintenance cost of units of different ethnicity as the faction alignment are: 20,40,200 silver for normal, leader and hero units. -If the commander of a faction is killed during a month, the faction alignment will be set to "chaotic" AFTER the next maintenance phase. It may be reset at the beginning of next month by appointing a new commander. If it is not, all units will have to pay the "different ethnicity" maintenance cost. -If an army comprises mixed ethnicities, each man in the army receives (on average) a combat penalty of 2(1-f) to his attack and melee defence skills. f = the fraction of the army of the SAME ethnicity as the soldier. An average penalty of 0.3 would mean a 30% chance of a -1 penalty and a 70% chance of no penalty. This effect may be halved with the hero skill "unity". -Elves do not suffer from penalties to ranged attacks (in forests/jungles) - -GUARDS: -There are now four guardfactions, one of each alignment. Guardfactions are unfriendly to factions of different alignment. -Guard regeneration halved from Arcadia III, still depends on city untaxed income (not fixed as in Atlantis 5.0). -The final number of guards which grow in a settlement now depend on the taxation available there, while the quality of the guards depends on the size (ie village, town or city) of the settlement. -Guards in cities behave as before, except that they only prevent assassinations and stealing against factions of their own alignment (ie Elven guards will not prevent assassination of units belonging to a Dwarven faction, even if the assassinated unit is made up of elves) -There are also some regional guards outside of cities who allow taxing, but only by factions of the same alignment as the guards. Regional guards never regenerate. -Guards may be skilled in combat, riding, crossbow or longbow, depending on their race and the local terrain. Guards will be equipped with items/weapons necessary for use of their skill, so riding guards will have swords and horses, while combat guards will have only swords, and crossbow guards will have crossbows - - -MISCELLANEOUS: -New armour table (only minor changes from Arcadia III) -Item sharing implemented for EXCHANGE, SEND, STUDY, PRODUCE, BUILD, BUY (Not for SELL). -Bridge cost reduced to 40 / skill 3. -Units transiting through a region will recieve a report on the region (not including units in the region). -Ranged attacks get +1 bonus in oceans and deserts -Populations multiplied by 20. -The formula for available taxation has changed so that available taxation income is no longer as sensitive to changes in wages, increasing taxation abilities in the "low tax" regions (jungle, tundra etc.). -Units that have some swimming capacity, but weigh more than their capacity, will discard items (from heaviest to lightest, including non-swimming men) until they can swim, instead of drowning (though if there are no mermen in the unit, this may currently result in discarding all men). -Spoils order modified so that, for example, spoils ride allows a unit to pick up items until picking up any more would prevent them riding. Also, two new spoils options (swim, sail) added. -Disabling or forgetting a hero's combat spell sets their combat spell to 'none'. -Towers, forts, etc. have different defences, ranging from a +2 bonus (tower) to a +4 bonus (magical fortress). Forts and Citadels have greater defence bonuses for non-melee attacks (+3/+4) than for melee attacks (+2/+3). -Number of trade items reduced to 12 (from 19) -Unit 'labels' listed in reports (for ALL/LABEL orders) -Flying units now move 6 as they are supposed to, not 8 as in Nylandor. -Using an ! before an order will suppress run-time errors in most cases other than DESTROY, TAX, PILLAGE, ENTER, LEAVE, GUARD. [HAVE HAD SOME TESTGAME PROBLEMS HERE, IF YOU TRY IT PLEASE CHECK FOR/REPORT ANY BUGS!] -PROMOTE now works in the open. - - - -Spells / skills removed since Arcadia III: -Sea Ward -Rejuvenation -Earthquake -Illusion -Illusory Creatures -Dispel Illusions -Illusory Wounds -Transfiguration [incorporated into transmutation] -Alteration -Mind Reading -Summon Black Wind -Tactics -Gemcutting - -Spells / skills added: -Battletraining -Charisma -Unity -Frenzy -Second Sight -Swiftness -Trading -Merchantry -Quartermastery [similar but not identical to Fracas 'quartermaster'] - -Spells / skills altered since Arcadia III: -PHEN (phantasmal entertainment): Renamed gladiator and CAST option removed. -ARTL (artifact lore): Becomes a foundation which adds to magic energy. -MYST (mysticism): Fizzle/energy effects removed; it now behaves like any other foundation. -TRAM (transmutation): Can produce horses / livestock / winged horses. -CLEA (clearskies): increases production of fish in a region. -BIRD (bird lore): LARGE option removed, energy cost removed, sees (level) hexes in chosen direction, number of eagles summonable reduced to (skill-2) squared [from (sk-1) squared]. -WOLF (wolf lore): Number of wolves summonable halved; spell free -GRYF (gryffin lore): 10%*level chance of success; spell free. -MODI (modification): range halved, resource increase reduced. -DIVE (diversion): range halved. -TRAM (transmutation): Production of advanced items requires level 5, and 3 normal items per advanced item (up from 4 and 2). -DEMO (demon lore): Cost of imps decreases with skill level (was meant to be this way in Nylandor, but bugged) -NECR (necromancy):Necromancy now has no limit on how many corpses may be raised after a battle. -RAIS (raise undead): Energy cost of summoning undead reduced to 5 (from 6). -SULI (summon lich): Limit for summoning liches removed. -NECR / RAIS / SULI: Decay rate of undead reduced to 6.7% (from 10%) -SUBA (summon balrogs): Maintenance energy for balrogs reduced to 5-2.5 (from 7-3.5) energy per month. -ENGR (engrave runes): Protects against weather attacks as well as energy/spirit -FEAR (create fear): Hits 50% more than in Arc III -SSTO (summon storm): Hits 50% more than in Arc III -COUR (instill courage): Gives +2 bonus (up from +1) and +1 against ranged attacks. Hits 150% more than intended in Arc III, 400% more than actual (bugged) in Arc III -SWIN (summon wind): Energy cost halved - -Items added: -Dolphins (normal, mount) -Flying dolphins (advanced, mount) -Staves of Yew (magic, weapon) - -Items removed: -Wagons -Rough Gems -7 Trade Items (GEM, GCHE, VODK, MINK, SPIC, COTT, IVOR) - -Item changes: -PPAR requires ARMO 4 (from GCUT 5) -AGAL protection increased to 200 -rgems count as advanced items -MSWO is armour-piercing -RUNE is armour-piercing, and has its combat bonus increased to 5. -DBOW is no longer armour-piercing -DBOW, XBOW get +2 attack bonus -XBOW attacks in battle round 2,4,6 -CLOA reduces multi-hit point heros to one hit point in battle. -GRYF: 33 hits/attacks (down from 40), all skill levels up by 1. - - - -Stored templates are listed at the end of the report, and may be used immediately after definition. For instance, a sample set of orders: - -#atlantis 10 xxxx -template Scout -avoid 1 -noaid 1 -claim 100 -buy 1 peasant - -unit 99 -study stea -form -type scout -move n -end -form -type scout -move ne -end -form -type scout -move nw -end -form -type scout -move s -end -#end - -etc. - ---------------------------------- -List of Changes for Arcadia III, compared to Atlantis 5.0: - -Units gain experience from using skills, and knowledge from studying skills. These are stored seperately, eg MINI 3 (90/60). Units get one skill level with 30 experience/knowledge, a second at 90, a third at 180 and a fourth at 300. -Slightly different terrain resource generation -Different monster strengths, particularly liches, dragons and balrogs -Stables, temples and fish traps enabled -Slight changes to: magic carpets -Different ship costs and capacities -Slightly more intelligent monster behaviour (monsters on coasts don't stay still so often, pirates and merfolk don't come to land) -Different city growth rates -Edge terrain and new sailing rules -Arcadia Battle Code -Ranged attacks get -1 penalty in forests/jungles -Different skill requirements (eg yew requires LUMB 6, not LUMB 5) -Artifact skills require item inputs (eg iron for amulets) -Mages do not need to be located in a building to study above level 2. -Defensive riding for monsters reduced from 0,3,6 (walk,ride,fly) to 0,2,4. - -Items added: -Pearls -Pearl Plate Armour - -Items removed: -Tarot Cards - -Objects added: -Hexside terrain (rivers, ravines, bridges, roads, rocks, beaches, harbours) -New shipping table - -Spells / skills removed: -Carpenter -Shipbuilding - -Spells / skills added/modified: -Construction -Mysticism -Windkey -Patterning -Summoning -Blizzard -Fog -Transmutation -Modification -Diversion -Resurrection -Summon Spirit of the Dead -Create Portal -Hypnosis -Binding -Dragon Lore -Concealment -Light -Darkness -Summon Men -Gryffin Lore -Artifact Lore -Instill Courage -Inner Strength - -New orders: -FIGHTAS -TACTICS - -Order modifications: -FORM - will work without an ID number (though cannot be referenced without a number). \ No newline at end of file diff --git a/arcadia/Makefile b/arcadia/Makefile deleted file mode 100644 index 933f9209a..000000000 --- a/arcadia/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -GAME = arcadia - -CPLUS = g++ -CC = gcc -CFLAGS = -g -I. -Wall - -ENGINE_OBJECTS = alist.o aregion.o army1.o astring.o battle1.o economy.o \ - formation1.o hexside.o times.o soldier1.o magic.o \ - edit.o faction.o fileio.o game.o gamedata.o gamedefs.o gameio.o \ - genrules.o i_rand.o items.o main.o market.o modify.o monthorders.o \ - npc.o object.o orders.o parseorders.o production.o runorders.o \ - shields.o skills.o skillshows.o specials.o spells.o template.o unit.o \ - extra.o map.o monsters.o rules.o world.o - -OBJECTS = $(patsubst %.o,obj/%.o,$(ENGINE_OBJECTS)) - -$(GAME)-m: objdir $(OBJECTS) - $(CPLUS) $(CFLAGS) -o $(GAME) $(OBJECTS) - -clean: - rm -f $(OBJECTS) - if [ -d obj ]; then rmdir obj; fi - rm -f html/$(GAME).html - -rules: - (./$(GAME) genrules html/intro.html html/styles.css html/$(GAME).html) - -objdir: - if [ ! -d obj ]; then mkdir obj; fi - -$(patsubst %.o,obj/%.o,$(ENGINE_OBJECTS)): obj/%.o: %.cpp - $(CPLUS) $(CFLAGS) -c -o $@ $< - diff --git a/arcadia/Notes.txt b/arcadia/Notes.txt deleted file mode 100644 index 8f9ede98d..000000000 --- a/arcadia/Notes.txt +++ /dev/null @@ -1,183 +0,0 @@ -Carry overs from Nylandor: -* Edge terrain and new sailing rules -* Arcadia Battle Code -* Experience code -* Different skill requirements to standard atlantis (eg yew requires LUMB 6, not LUMB 5) -* Artifact skills require item inputs (eg iron for amulets) -* Different terrain balances to standard atlantis -* Different armour table to standard atlantis -* Different magic tree to standard atlantis -* Different city growth rates to standard atlantis -* Different monster strengths to standard atlantis, particularly liches, dragons and balrogs -* Various bugfixes -* Slightly more intelligent monster behaviour (monsters on coasts don't stay still so often, pirates and merfolk don't come to land) -* Different ship costs and capacities -* Slight changes to: magic carpets -* Stables, temples and fish traps enabled -* 'Carpenter' and 'Shipbuilding' combined into 'Construction' - - - -040730: - -u->speciality cleared from the code. Basic normal/specialist/leader/mage types included. Recruited wiped - -Checked all the leader specific stuff and particularly 'IsLeader()'. - -Enabled studying leadership and heroship to upgrade units. Prevented giving men between unit classes. - -guard regen partly redone: -Halved guard regen rate from Nylandor (Still depends on tax, but now $1000 per guard). -Fixed guard generation and set xbows/lbows by race - -Increased protection of AGAL to 200 and capacity of trireme to 1000. -Replaced IDWA with MERM - -PHEN 3 moved to PHEN 1 - -Transfiguration removed - - -041123: -linked escape code removed -tactics skill disabled and removed from combat code; officer control reset to 100 base -battle leader refers to attribute "seniority" -Nylandor bugfixes carried over: * carpet double report * specials bugcrash if att=0 * farsight always succeeded * assassination doesn't get all unit equipment * long unit names crashing battles * windkey usage * clearskies and sailing * following sail experience -system("pause") in aregion shifted to debug only * swimmers can catch ships -Recruit order removed -bridge cost reduced to 40 / skill 3 - -041203: -seaward/rejuvenation disabled -fizzles #ifdef'd out -wagons removed -pearl plate requirement reduced to gcut 4 -agall protection increased to 200 -rough gems changed to advanced items -removed giveif order -partially added send order: constructors/destructors, parsing, rules description - -041204: -SEND gamedef'd -Transit report enabled (REGION | BUILDINGS) -DoSendOrder mostly coded - -041205: -Rest of SEND order coded. 'itemsintransit' added to unit.h -Gamedef::Transit turned on to check Quartermaster rules. - -041219: -XBows set to attack in rounds 2,4,6 and gain +2 combat bonus -DBows lose armour-pierce mod but gain +2 combat bonus -MSwords gain armour-pierce mod -Armour table changed to make armour-pierce more effective and PPAR/LARM better against magic -TEST: Original orders not outputted to checkfile, only errors. -Parsing done for run-time order suppression, except for: DESTROY, TAX, PILLAGE, PROMOTE, ENTER, LEAVE, GUARD, CAST - - -050213: -unit->herostudyorder included / enabled. -Multiple spells cost normal amount (not 50% more, etc.) -Unlimited spells may be cast: data structure converted to list -No spell type may be cast more than once -Magic shields get a +1 bonus in combat -Heros cannot assassinate other heros -Added routines: unit::getitems() and unit::cangetitems() -Can Claim items from others during: STUDY, BUILD | 050215: PRODUCE, CAST, SEND, EXCHANGE [Todo: SELL, BUY] - -050215: -Enchant Armour/Swords code modified for can-claim. -Exchange item-check modified for can-claim -SEND cost adjusted to sqrt(weight-cap) -Can Claim code adjusted to be compatible with CVS version of same. BUY, SELL not yet implemented as CVS version is bugged, also Arcadia build and produce are significantly improved compared to CVS version. -Created new races and set race skills - -050216: -Added basics for: TOUG,UNIY,FREN,SSIG,SWIF,TRAD,MERC [BATT,CHAR,DOLP already added] -Removed: EQUA, DILL, ILCR, ILWO, ILLN, MIND [TRAF, SWAR, REJU, ALTE already removed] -TOUG,FREN,BATT,SSIG,SWIF,TRAD,MERC fully implemented -Done parsing for quartermastery - -050217: -Removed parsing for quartermastery; implemented it using different method ;). -CLOA reduces maxhits to 1 in battle. -Implemented COMMAND order and end-of-round command check -Implemented double maintenance cost for non-ethnic men -Implemented morale penalty in combat for mixed races -Implemented UNIY -Faction alignment added to report and save file -Some dragon stats cleared -ENHANCEDRANGED flag added for ocean, desert -Elves immune to range penalties -Combat seniority code -Foundation skillshows rewritten -specialist descriptions removed from skillshows -CLEA increases fish production - -050218: -Various spell updates -Guard faction split into 4, and sets other alignments unfriendly -Population multiplier included -Begun coding "TryToSwim" ---- -Finished & enabled "TryToSwim" -class Template and Faction::AList formtemplates added -TEMPLATE order added -TYPE order added - -050219: -TYPE bug fixed -Writeout / Readin of templates enabled -SPOILS code redone, SPOILS SWIM and SPOILS SAIL flags added - -050220: -skill disable code written. Should be saved with skill level -skill disable parse code written -Disabling or forgetting a hero's combat spell sets their combat spell to 'none'. -Disabled skills marked in reports -Faction ethnicity marked in reports - -050224: -Updated advanced item values -Updated Edit Import Function -Incorporated ALL and LABEL orders, and modified code for TYPE orders. - -050226: -Fixed LABEL not being recorded in gamefile bug & added label to unit constructor/destructor -Updated SWIN, FEAR, COUR, SSTO -Implemented CHAR -Implemented ! handling in all 'easy' cases. -Added staff of yew and NEVERLOST flag -Added experience for unity, battletraining, frenzy, toughness, swiftness, second sight - -050227: -Implemented silver sharing for BUY orders. -Implemented ! handling for CAST, PROMOTE -Allowed PROMOTE to work in open -Added FDOL - -050228: -Fixed crash bugs in CLOA-1hp check and ethnic morale penalty - -? -Fixed bug for study orders not being cleared -Generalised TEMPLATE / ALL to act after order parsing, not during - -050303: -Fixed crash bug from STAY coding -Implemented skill-level check for studying magic skills - -050323: -Set max guard levels to depend on tax available - -050325: -Included i_rand.cpp -Allowed guards to use horses if appropriate -Added 'regional' guards -Basics of times/rumour reports added, and battle rumours coded - - -Todo: -Allow transfer from leader to non-leader if errors are suppressed -Rewrite rules magic section for heros, and normal->leader->hero progression -Note for buying: multiple buyers - don't count silver twice if possible. \ No newline at end of file diff --git a/arcadia/arcadia_intro.html b/arcadia/arcadia_intro.html deleted file mode 100644 index 7b8976eb3..000000000 --- a/arcadia/arcadia_intro.html +++ /dev/null @@ -1 +0,0 @@ -This is a test … for me, to pray that I get CVS access diff --git a/arcadia/aregion.cpp b/arcadia/aregion.cpp deleted file mode 100644 index f3795f6a8..000000000 --- a/arcadia/aregion.cpp +++ /dev/null @@ -1,3053 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include -#include -#include "game.h" -#include "gamedata.h" - -Location *GetUnit(AList *list, int n) -{ - forlist(list) { - Location *l = (Location *) elem; - if (l->unit->num == n) return l; - } - return 0; -} - -ARegionPtr *GetRegion(AList *l, int n) -{ - forlist(l) { - ARegionPtr *p = (ARegionPtr *) elem; - if (p->ptr->num == n) return p; - } - return 0; -} - -Farsight::Farsight() -{ - faction = 0; - unit = 0; - level = 0; - for(int i = 0; i < NDIRS; i++) - exits_used[i] = 0; -} - -Farsight *GetFarsight(AList *l, Faction *fac) -{ - forlist(l) { - Farsight *f = (Farsight *) elem; - if (f->faction == fac) return f; - } - return 0; -} - -AString TownString(int i) -{ - switch (i) { - case TOWN_VILLAGE: - return "village"; - case TOWN_TOWN: - return "town"; - case TOWN_CITY: - return "city"; - } - return "huh?"; -} - -TownInfo::TownInfo() -{ - name = 0; - pop = 0; - basepop = 0; - activity = 0; - growth = 0; - mortality = 0; -} - -TownInfo::~TownInfo() -{ - if (name) delete name; -} - -void TownInfo::Readin(Ainfile *f, ATL_VER &v) -{ - name = f->GetStr(); - pop = f->GetInt(); - basepop = f->GetInt(); - growth = f->GetInt(); - mortality = f->GetInt(); -} - -void TownInfo::Writeout(Aoutfile *f) -{ - f->PutStr(*name); - f->PutInt(pop); - f->PutInt(basepop); - f->PutInt(growth); - f->PutInt(mortality); -} - -ARegion::ARegion() -{ - name = new AString("Region"); - xloc = 0; - yloc = 0; - buildingseq = 1; - gate = 0; - gatemonth = 0; - gateopen = 1; - willsink = 0; - town = 0; - development = 0; - habitat = 0; - mortality = 0; - growth = 0; - migration = 0; - culture = 0; - clearskies = 0; - earthlore = 0; - fog = 0; - flagpole = FL_NULL; - timesmarker = 0; - dynamicexits = 0; - for (int i=0; icoastal_races)/sizeof(int); - int noncoastal = sizeof(typer->races)/sizeof(int); - if(IsCoastal()) { - for(int i=0; icoastal_races[i]) return 1; - } - } - for(int i=0; iraces[i]) return 1; - } - return 0; -} - -int ARegion::GetNearestProd(int item) -{ - AList regs, regs2; - AList *rptr = ®s; - AList *r2ptr = ®s2; - AList *temp; - ARegionPtr *p = new ARegionPtr; - p->ptr = this; - regs.Add(p); - - for (int i=0; i<5; i++) { - forlist(rptr) { - ARegion *r = ((ARegionPtr *) elem)->ptr; - AString skname = ItemDefs[item].pSkill; - int sk = LookupSkill(&skname); - if (r->products.GetProd(item, sk)) { - regs.DeleteAll(); - regs2.DeleteAll(); - return i; - } - for (int j=0; jptr = neighbors[j]; - r2ptr->Add(p); - } - } - rptr->DeleteAll(); - temp = rptr; - rptr = r2ptr; - r2ptr = temp; - } - } - regs.DeleteAll(); - regs2.DeleteAll(); - return 5; -} - - -void ARegion::LairCheck() -{ - // No lair if town in region - if (town) return; - - - TerrainType *tt = &TerrainDefs[type]; - - if(!tt->lairChance) return; - - int check = getrandom(100); - if(check >= tt->lairChance) return; - - int count = 0; - unsigned int c; - for(c = 0; c < sizeof(tt->lairs)/sizeof(int); c++) { - if(tt->lairs[c] != -1) { - if(!(ObjectDefs[tt->lairs[c]].flags & ObjectType::DISABLED)) { - count++; - } - } - } - count = getrandom(count); - - int lair = -1; - for(c = 0; c < sizeof(tt->lairs)/sizeof(int); c++) { - if(tt->lairs[c] != -1) { - if(!(ObjectDefs[tt->lairs[c]].flags & ObjectType::DISABLED)) { - if(!count) { - lair = tt->lairs[c]; - break; - } - count--; - } - } - } - - if(lair != -1) { - MakeLair(lair); - return; - } -} - -void ARegion::MakeLair(int t) -{ - Object *o = new Object(this); - o->num = buildingseq++; - o->name = new AString(AString(ObjectDefs[t].name) + " [" + o->num + "]"); - o->type = t; - o->incomplete = 0; - o->inner = -1; - objects.Add(o); -} - -int ARegion::GetPoleDistance(int dir) -{ - int ct = 1; - ARegion *nreg = neighbors[dir]; - while (nreg) { - ct++; - nreg = nreg->neighbors[dir]; - } - return ct; -} - -void ARegion::Setup() -{ - // - // type and location have been setup, do everything else - SetupProds(); -cout << "."; - SetupPop(); -cout << "."; - // - // Make the dummy object - // - Object *obj = new Object(this); - objects.Add(obj); -cout << "."; - if(Globals->LAIR_MONSTERS_EXIST) - LairCheck(); -} - -int ARegion::TraceConnectedRoad(int dir, int sum, AList *con, int range) -{ - ARegionPtr *rn = new ARegionPtr(); - rn->ptr = this; - int isnew = 1; - forlist(con) { - ARegionPtr *reg = (ARegionPtr *) elem; - if ((reg) && (reg->ptr)) if(reg->ptr == this) isnew = 0; - } - if(isnew == 0) return sum; - con->Add(rn); -#if 0 - Awrite(AString(" -> ") + *name + "(" + xloc + ", " + yloc + ")"); - Awrite(AString(" +") + (town->TownType()+1)); -#endif - if(town) sum += town->TownType() + 1; - if(range > 0) { - for(int d=0; dGetRealDirComp(d)) continue; - if(r->HasConnectingRoad(d)) sum = r->TraceConnectedRoad(d, sum, con, range-1); - } - } - return sum; -} - -int ARegion::CountRoadConnectedTowns(int range) -{ - int townsum = 0; - AList *con = new AList(); - ARegionPtr *rp = new ARegionPtr(); - rp->ptr = this; - con->Add(rp); - for(int d=0; dHasConnectingRoad(d)) townsum = r->TraceConnectedRoad(d, townsum, con, range-1); - } - return townsum; -} - -// AS -void ARegion::DoDecayCheck(ARegionList *pRegs) -{ - forlist (&objects) { - Object *o = (Object *) elem; - if(!(ObjectDefs[o->type].flags & ObjectType::NEVERDECAY)) { - DoDecayClicks(o, pRegs); - } - } -} - -// AS -void ARegion::DoDecayClicks(Object *o, ARegionList *pRegs) -{ - if(ObjectDefs[o->type].flags & ObjectType::NEVERDECAY) return; - - int clicks = getrandom(GetMaxClicks()); - clicks += PillageCheck(); - - if(clicks > ObjectDefs[o->type].maxMonthlyDecay) - clicks = ObjectDefs[o->type].maxMonthlyDecay; - - o->incomplete += clicks; - - if(o->incomplete > 0) { - // trigger decay event - RunDecayEvent(o, pRegs); - } -} - -// AS -void ARegion::RunDecayEvent(Object *o, ARegionList *pRegs) -{ - AList *pFactions; - pFactions = PresentFactions(); - forlist (pFactions) { - Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(GetDecayFlavor() + *o->name + " " + - ObjectDefs[o->type].name + " in " + - ShortPrint(pRegs)); - } -} - -// AS -AString ARegion::GetDecayFlavor() -{ - AString flavor; - int badWeather = 0; - if (weather != W_NORMAL && !clearskies) badWeather = 1; - if (!Globals->WEATHER_EXISTS) badWeather = 0; - switch (type) { - case R_PLAIN: - case R_ISLAND_PLAIN: - case R_CERAN_PLAIN1: - case R_CERAN_PLAIN2: - case R_CERAN_PLAIN3: - case R_CERAN_LAKE: - flavor = AString("Floods have damaged "); - break; - case R_DESERT: - case R_CERAN_DESERT1: - case R_CERAN_DESERT2: - case R_CERAN_DESERT3: - flavor = AString("Flashfloods have damaged "); - break; - case R_CERAN_WASTELAND: - case R_CERAN_WASTELAND1: - flavor = AString("Magical radiation has damaged "); - break; - case R_TUNDRA: - case R_CERAN_TUNDRA1: - case R_CERAN_TUNDRA2: - case R_CERAN_TUNDRA3: - if (badWeather) { - flavor = AString("Ground freezing has damaged "); - } else { - flavor = AString("Ground thaw has damaged "); - } - break; - case R_MOUNTAIN: - case R_ISLAND_MOUNTAIN: - case R_CERAN_MOUNTAIN1: - case R_CERAN_MOUNTAIN2: - case R_CERAN_MOUNTAIN3: - if (badWeather) { - flavor = AString("Avalanches have damaged "); - } else { - flavor = AString("Rockslides have damaged "); - } - break; - case R_CERAN_HILL: - case R_CERAN_HILL1: - case R_CERAN_HILL2: - flavor = AString("Quakes have damaged "); - break; - case R_FOREST: - case R_SWAMP: - case R_ISLAND_SWAMP: - case R_JUNGLE: - case R_CERAN_FOREST1: - case R_CERAN_FOREST2: - case R_CERAN_FOREST3: - case R_CERAN_MYSTFOREST: - case R_CERAN_MYSTFOREST1: - case R_CERAN_MYSTFOREST2: - case R_CERAN_SWAMP1: - case R_CERAN_SWAMP2: - case R_CERAN_SWAMP3: - case R_CERAN_JUNGLE1: - case R_CERAN_JUNGLE2: - case R_CERAN_JUNGLE3: - flavor = AString("Encroaching vegetation has damaged "); - break; - case R_CAVERN: - case R_UFOREST: - case R_TUNNELS: - case R_CERAN_CAVERN1: - case R_CERAN_CAVERN2: - case R_CERAN_CAVERN3: - case R_CERAN_UFOREST1: - case R_CERAN_UFOREST2: - case R_CERAN_UFOREST3: - case R_CERAN_TUNNELS1: - case R_CERAN_TUNNELS2: - case R_CHASM: - case R_CERAN_CHASM1: - case R_GROTTO: - case R_CERAN_GROTTO1: - case R_DFOREST: - case R_CERAN_DFOREST1: - if (badWeather) { - flavor = AString("Lava flows have damaged "); - } else { - flavor = AString("Quakes have damaged "); - } - break; - default: - flavor = AString("Unexplained phenomena have damaged "); - break; - } - return flavor; -} - -// AS -int ARegion::GetMaxClicks() -{ - int terrainAdd = 0; - int terrainMult = 1; - int weatherAdd = 0; - int badWeather = 0; - int maxClicks; - if (weather != W_NORMAL && !clearskies) badWeather = 1; - if (!Globals->WEATHER_EXISTS) badWeather = 0; - switch (type) { - case R_PLAIN: - case R_ISLAND_PLAIN: - case R_TUNDRA: - case R_CERAN_PLAIN1: - case R_CERAN_PLAIN2: - case R_CERAN_PLAIN3: - case R_CERAN_LAKE: - case R_CERAN_TUNDRA1: - case R_CERAN_TUNDRA2: - case R_CERAN_TUNDRA3: - terrainAdd = -1; - if (badWeather) weatherAdd = 4; - break; - case R_MOUNTAIN: - case R_ISLAND_MOUNTAIN: - case R_CERAN_MOUNTAIN1: - case R_CERAN_MOUNTAIN2: - case R_CERAN_MOUNTAIN3: - case R_CERAN_HILL: - case R_CERAN_HILL1: - case R_CERAN_HILL2: - terrainMult = 2; - if (badWeather) weatherAdd = 4; - break; - case R_FOREST: - case R_SWAMP: - case R_ISLAND_SWAMP: - case R_JUNGLE: - case R_CERAN_FOREST1: - case R_CERAN_FOREST2: - case R_CERAN_FOREST3: - case R_CERAN_MYSTFOREST: - case R_CERAN_MYSTFOREST1: - case R_CERAN_MYSTFOREST2: - case R_CERAN_SWAMP1: - case R_CERAN_SWAMP2: - case R_CERAN_SWAMP3: - case R_CERAN_JUNGLE1: - case R_CERAN_JUNGLE2: - case R_CERAN_JUNGLE3: - terrainAdd = -1; - terrainMult = 2; - if (badWeather) weatherAdd = 1; - break; - case R_DESERT: - case R_CERAN_DESERT1: - case R_CERAN_DESERT2: - case R_CERAN_DESERT3: - terrainAdd = -1; - if (badWeather) weatherAdd = 5; - case R_CAVERN: - case R_UFOREST: - case R_TUNNELS: - case R_CERAN_CAVERN1: - case R_CERAN_CAVERN2: - case R_CERAN_CAVERN3: - case R_CERAN_UFOREST1: - case R_CERAN_UFOREST2: - case R_CERAN_UFOREST3: - case R_CERAN_TUNNELS1: - case R_CERAN_TUNNELS2: - case R_CHASM: - case R_CERAN_CHASM1: - case R_GROTTO: - case R_CERAN_GROTTO1: - case R_DFOREST: - case R_CERAN_DFOREST1: - terrainAdd = 1; - terrainMult = 2; - if (badWeather) weatherAdd = 6; - break; - default: - if (badWeather) weatherAdd = 4; - break; - } - maxClicks = terrainMult * (terrainAdd + 2) + (weatherAdd + 1); - return maxClicks; -} - -// AS -int ARegion::PillageCheck() -{ - int pillageAdd = maxwages - wages; - if (pillageAdd > 0) return pillageAdd; - return 0; -} - -// AS -int ARegion::HasRoad() -{ -/* Hex Patch Dec '03 */ - if(!Globals->HEXSIDE_TERRAIN) { - forlist (&objects) { - Object *o = (Object *) elem; - if(o->IsRoad() && o->incomplete < 1) return 1; - } - } - else { - for(int i=0;i<6;i++) { - if(hexside[i]->road == -1) return 1; - } - } - return 0; -} - -// AS -int ARegion::HasExitRoad(int realDirection) -{ - forlist (&objects) { - Object *o = (Object *) elem; - if (o->IsRoad() && o->incomplete < 1) { - if (o->type == GetRoadDirection(realDirection)) return 1; - } - } - return 0; -} - -// AS -int ARegion::CountConnectingRoads() -{ - int connections = 0; - for (int i = 0; i < NDIRS; i++) { - if (HasExitRoad(i) && neighbors[i] && - HasConnectingRoad(i)) - connections ++; - } - return connections; -} - -// AS -int ARegion::HasConnectingRoad(int realDirection) -{ - int opposite = GetRealDirComp(realDirection); - - if (neighbors[realDirection] - && neighbors[realDirection]->HasExitRoad(opposite)) - return 1; - - return 0; -} - -// AS -int ARegion::GetRoadDirection(int realDirection) -{ - int roadDirection = 0; - switch (realDirection) { - case D_NORTH: - roadDirection = O_ROADN; - break; - case D_NORTHEAST: - roadDirection = O_ROADNE; - break; - case D_NORTHWEST: - roadDirection = O_ROADNW; - break; - case D_SOUTH: - roadDirection = O_ROADS; - break; - case D_SOUTHEAST: - roadDirection = O_ROADSE; - break; - case D_SOUTHWEST: - roadDirection = O_ROADSW; - break; - } - return roadDirection; -} - -// AS -int ARegion::GetRealDirComp(int realDirection) -//BS - This will stuff up on really small maps where some hexes may have multiple connections -//to another hex - this may return the wrong connection. -//Also, this seems to return zero (=D_NORTH) by default. Is this wise? -{ - int complementDirection = 0; - - if (neighbors[realDirection]) { - ARegion *n = neighbors[realDirection]; - for (int i = 0; i < NDIRS; i++) - if (n->neighbors[i] == this) - return i; - } - - switch (realDirection) { - case D_NORTH: - complementDirection = D_SOUTH; - break; - case D_NORTHEAST: - complementDirection = D_SOUTHWEST; - break; - case D_NORTHWEST: - complementDirection = D_SOUTHEAST; - break; - case D_SOUTH: - complementDirection = D_NORTH; - break; - case D_SOUTHEAST: - complementDirection = D_NORTHWEST; - break; - case D_SOUTHWEST: - complementDirection = D_NORTHEAST; - break; - } - return complementDirection; -} - -void ARegion::UpdateProducts() -{ - forlist (&products) { - Production *prod = (Production *) elem; - int lastbonus = prod->baseamount / 2; - int bonus = 0; - - if (prod->itemtype == I_SILVER && prod->skill == -1) continue; - - forlist (&objects) { - Object *o = (Object *) elem; - if (o->incomplete < 1 && - ObjectDefs[o->type].productionAided == prod->itemtype) { - lastbonus /= 2; - bonus += lastbonus; - } - } - prod->amount = prod->baseamount + bonus; - - if (prod->itemtype == I_GRAIN || prod->itemtype == I_LIVESTOCK) { - if(!Globals->ARCADIA_MAGIC) prod->amount += ((earthlore + clearskies) * 40) / prod->baseamount; - else prod->amount += ((2*earthlore + clearskies) * prod->baseamount) / 6; - } - if (prod->itemtype == I_FISH) prod->amount += clearskies * prod->baseamount / 2; - } -} - -AString ARegion::ShortPrint(ARegionList *pRegs) -{ - AString temp = TerrainDefs[type].name; - temp += AString(" (") + xloc + "," + yloc; - - ARegionArray *pArr = pRegs->pRegionArrays[zloc]; - if(pArr->strName) { - temp += ","; - if(Globals->EASIER_UNDERWORLD && - (Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS > 1)) { - temp += AString("") + zloc + " <"; - } else { - // add less explicit multilevel information about the underworld - if(zloc > 2 && zloc < Globals->UNDERWORLD_LEVELS+2) { - for(int i = zloc; i > 3; i--) { - temp += "very "; - } - temp += "deep "; - } else if((zloc > Globals->UNDERWORLD_LEVELS+2) && - (zloc < Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + 2)) { - for(int i = zloc; i > Globals->UNDERWORLD_LEVELS + 3; i--) { - temp += "very "; - } - temp += "deep "; - } - } - temp += *pArr->strName; - if(Globals->EASIER_UNDERWORLD && - (Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS > 1)) { - temp += ">"; - } - } - temp += ")"; - temp += AString(" in ") + *name; - return temp; -} - -AString ARegion::Print(ARegionList *pRegs) -{ - AString temp = ShortPrint(pRegs); - if (town) { - temp += AString(", contains ") + *(town->name) + " [" + - TownString(town->TownType()) + "]"; - } - return temp; -} - -void ARegion::SetLoc(int x, int y, int z) -{ - xloc = x; - yloc = y; - zloc = z; -} - -void ARegion::SetGateStatus(int month) -{ - if ((type == R_NEXUS) || (Globals->START_GATES_OPEN && IsStartingCity())) { - gateopen = 1; - return; - } - gateopen = 0; - for (int i = 0; i < Globals->GATES_NOT_PERENNIAL; i++) { - int dmon = gatemonth + i; - if (dmon > 11) dmon = dmon - 12; - if (dmon == month) gateopen = 1; - } -} - -void ARegion::Kill(Unit *u) -{ - //edit for times reporting of dead guards. - if(u->type == U_GUARD || u->type == U_GUARDMAGE) { - timesmarker = 1; - } - - Unit *first = 0; - forlist((&objects)) { - Object *obj = (Object *) elem; - if (obj) { - forlist((&obj->units)) { - if (((Unit *) elem)->faction->num == u->faction->num && - ((Unit *) elem) != u) { - first = (Unit *) elem; - break; - } - } - } - if (first) break; - } - - if (first) { - // give u's stuff to first - forlist(&u->items) { - Item *i = (Item *) elem; - if (!IsSoldier(i->type)) { - first->items.SetNum(i->type, first->items.GetNum(i->type) + - i->num); - u->items.SetNum(i->type, 0); - // If we're in ocean and not in a structure, make sure that - // the first unit can actually hold the stuff and not drown - // If the item would cause them to drown then they won't - // pick it up. - if(TerrainDefs[type].similar_type == R_OCEAN) { - if(first->object->type == O_DUMMY) { - if(!first->CanReallySwim()) { - first->items.SetNum(i->type, - first->items.GetNum(i->type) - i->num); - } - } - } - } - } - } - -//BS mod - units at this stage still have men in them! Shouldn't matter ... I hope! (needed for mages to rise again!) - if(u->type != U_MAGE || !Globals->ARCADIA_MAGIC || !u->IsAlive()) { - u->MoveUnit(0); - hell.Add(u); - } else { - //mage under arcadia - u->MoveUnit(GetDummy()); - u->dead = u->faction->num; - u->canattack = 0; - //cannot clear any orders which may have led to the battle, or might later double destruct the order - u->SafeClearOrders(); - //faction changed in post-turn processing, or in Game::KillDead if died in battle. - } -} - -void ARegion::ClearHell() -{ - hell.DeleteAll(); -} - -Object *ARegion::GetObject(int num) -{ - forlist(&objects) { - Object *o = (Object *) elem; - if (o->num == num) return o; - } - return 0; -} - -Object *ARegion::GetDummy() -{ - forlist(&objects) { - Object *o = (Object *) elem; - if (o->type == O_DUMMY) return o; - } - return 0; -} - -Unit *ARegion::GetUnit(int num) -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - Unit *u = obj->GetUnit(num); - if(u) { - return(u); - } - } - return 0; -} - -Location *ARegion::GetLocation(UnitId *id, int faction) -{ - Unit *retval = 0; - forlist(&objects) { - Object *o = (Object *) elem; - retval = o->GetUnitId(id, faction); - if (retval) { - Location *l = new Location; - l->region = this; - l->obj = o; - l->unit = retval; - return l; - } - } - return 0; -} - -Unit *ARegion::GetUnitAlias(int alias, int faction) -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - Unit *u = obj->GetUnitAlias(alias, faction); - if(u) { - return(u); - } - } - return 0; -} - -Unit *ARegion::GetUnitId(UnitId *id, int faction) -{ - Unit *retval = 0; - forlist(&objects) { - Object *o = (Object *) elem; - retval = o->GetUnitId(id, faction); - if (retval) return retval; - } - return retval; -} - -Location *ARegionList::GetUnitId(UnitId *id, int faction, ARegion *cur) -{ -// if(!id || !cur) return NULL; //for safety - - Location *retval = NULL; - // Check current region first - retval = cur->GetLocation(id, faction); - if (retval) return retval; - - // No? We must be looking for an existing unit. - if (!id->unitnum) return NULL; - - return this->FindUnit(id->unitnum); -} - -int ARegion::Present(Faction *f) -{ - if(!Globals->ARCADIA_MAGIC) { - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) - if (((Unit *) elem)->faction == f) return 1; - } - } else { - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) - if ((((Unit *) elem)->faction == f) && (((Unit *) elem)->dead == 0)) return 1; - } - } - return 0; -} - -AList *ARegion::PresentFactions() -{ - AList *facs = new AList; - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (!GetFaction2(facs, u->faction->num)) { - FactionPtr *p = new FactionPtr; - p->ptr = u->faction; - facs->Add(p); - } - } - } - return facs; -} - -void ARegion::Writeout(Aoutfile *f) -{ - f->PutStr(*name); - f->PutInt(num); - if (type != -1) f->PutStr(TerrainDefs[type].type); - else f->PutStr("NO_TERRAIN"); - f->PutInt(buildingseq); - f->PutInt(gate); - if(gate > 0) f->PutInt(gatemonth); - f->PutInt(willsink); - f->PutInt(flagpole); - - if (race != -1) f->PutStr(ItemDefs[race].abr); - else f->PutStr("NO_RACE"); - f->PutInt(population); - f->PutInt(basepopulation); - f->PutInt(migration); - f->PutInt(wages); - f->PutInt(maxwages); - f->PutInt(money); - - f->PutInt(elevation); - f->PutInt(humidity); - f->PutInt(temperature); - f->PutInt(vegetation); - f->PutInt(culture); - - f->PutInt(habitat); - f->PutInt(development); - f->PutInt(growth); - f->PutInt(mortality); - - if (town) { - f->PutInt(1); - town->Writeout(f); - } else { - f->PutInt(0); - } - - f->PutInt(xloc); - f->PutInt(yloc); - f->PutInt(zloc); - - products.Writeout(f); - markets.Writeout(f); - - for(int i=0; i<6; i++) { - if(neighbors[i] && (neighbors[i]->num < num)) continue; - else - { - f->PutInt(i); -#ifdef DEBUG - if(!hexside[i]) { - Awrite("bugger!"); - system("PAUSE"); - Awrite(AString("missing hexside ") + i); - f->PutInt(0); - f->PutInt(0); - f->PutInt(0); - } else -#endif - hexside[i]->Writeout(f); - delete hexside[i]; //otherwise they seem to never get cleared. - } - } - f->PutInt(-1); - - f->PutInt(objects.Num()); - forlist ((&objects)) ((Object *) elem)->Writeout(f); -} - -int LookupRegionType(AString *token) -{ - for (int i = 0; i < R_NUM; i++) { - if (*token == TerrainDefs[i].type) return i; - } - return -1; -} - -void ARegion::Readin(Ainfile *f, AList *facs, ATL_VER v) -{ - AString *temp; - - name = f->GetStr(); - - num = f->GetInt(); - temp = f->GetStr(); - type = LookupRegionType(temp); - delete temp; - buildingseq = f->GetInt(); - gate = f->GetInt(); - if(gate > 0) gatemonth = f->GetInt(); - willsink = f->GetInt(); - flagpole = f->GetInt(); - - temp = f->GetStr(); - race = LookupItem(temp); - delete temp; - - population = f->GetInt(); - basepopulation = f->GetInt(); - migration = f->GetInt(); - wages = f->GetInt(); - maxwages = f->GetInt(); - money = f->GetInt(); - - elevation = f->GetInt(); - humidity = f->GetInt(); - temperature = f->GetInt(); - vegetation = f->GetInt(); - culture = f->GetInt(); - - habitat = f->GetInt(); - development = f->GetInt(); - growth = f->GetInt(); - mortality = f->GetInt(); - - if (f->GetInt()) { - town = new TownInfo; - town->Readin(f, v); - } else { - town = 0; - } - - xloc = f->GetInt(); - yloc = f->GetInt(); - zloc = f->GetInt(); - - products.Readin(f); - markets.Readin(f); - - int done = 0; - while(!done) { - int side = f->GetInt(); - if(side == -1) done = 1; - else { - Hexside *temp = new Hexside(); - temp->Readin(f); - hexside[side] = temp; - } - } - - int i = f->GetInt(); - for (int j=0; jReadin(f, facs, v); - objects.Add(temp); - } -} - -int ARegion::CanMakeAdv(Faction *fac, int item) -//currently only called for report writing, so really "can see advanced" -{ - AString skname; - int sk; - Farsight *f; - - if(ItemDefs[item].flags & ItemType::ALWAYSSEE) return 1; - - if(Globals->IMPROVED_FARSIGHT) { - forlist(&farsees) { - f = (Farsight *)elem; - if(f && f->faction == fac && f->unit) { - skname = ItemDefs[item].pSkill; - sk = LookupSkill(&skname); - if(f->unit->GetSkill(sk) >= ItemDefs[item].pLevel) - return 1; - } - } - } - - if((Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) && - (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_RESOURCES)) { - forlist(&passers) { - f = (Farsight *)elem; - if(f && f->faction == fac && f->unit) { - skname = ItemDefs[item].pSkill; - sk = LookupSkill(&skname); - if(f->unit->GetSkill(sk) >= ItemDefs[item].pLevel) - return 1; - } - } - } - - forlist(&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == fac) { - skname = ItemDefs[item].pSkill; - sk = LookupSkill(&skname); - if (u->GetSkill(sk) >= ItemDefs[item].pLevel) - return 1; - if(u->GetSkill(S_BASE_CHARISMA) && Population()) { //hardcoded charisma effect - int charis = u->GetSkill(S_BASE_CHARISMA); - while(charis--) { - if(getrandom(2)) { - u->Event(AString("Learns about the presence of ") + ItemDefs[item].name + " in the local region."); - return 1; - } - } - } - } - } - } - return 0; -} - -void ARegion::WriteProducts(Areport *f, Faction *fac, int present) -{ - AString temp = "Products: "; - int has = 0; - forlist((&products)) { - Production *p = ((Production *) elem); - if (ItemDefs[p->itemtype].type & IT_ADVANCED) { - if (CanMakeAdv(fac, p->itemtype) || (fac->IsNPC())) { - if (has) { - temp += AString(", ") + p->WriteReport(); - } else { - has = 1; - temp += p->WriteReport(); - } - } - } else { - if (p->itemtype == I_SILVER) { - if (p->skill == S_ENTERTAINMENT) { - if((Globals->TRANSIT_REPORT & - GameDefs::REPORT_SHOW_ENTERTAINMENT) || present) { - f->PutStr(AString("Entertainment available: $") + - p->amount + "."); - } else { - f->PutStr(AString("Entertainment available: $0.")); - } - } - } else { - if(!present && - !(Globals->TRANSIT_REPORT & - GameDefs::REPORT_SHOW_RESOURCES)) - continue; - if (has) { - temp += AString(", ") + p->WriteReport(); - } else { - has = 1; - temp += p->WriteReport(); - } - } - } - } - - if (has==0) temp += "none"; - temp += "."; - f->PutStr(temp); -} - -int ARegion::HasItem(Faction *fac, int item) -{ - forlist(&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == fac) { - if (u->items.GetNum(item)) return 1; - } - } - } - return 0; -} - -void ARegion::WriteMarkets(Areport *f, Faction *fac, int present) -{ - AString temp = "Wanted: "; - int has = 0; - forlist(&markets) { - Market *m = (Market *) elem; - if (!m->amount) continue; - if(!present && - !(Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_MARKETS)) - continue; - if (m->type == M_SELL) { - if (ItemDefs[m->item].type & IT_ADVANCED) { - if(!Globals->MARKETS_SHOW_ADVANCED_ITEMS) { - if (!HasItem(fac, m->item)) { - continue; - } - } - } - if (has) { - temp += ", "; - } else { - has = 1; - } - temp += m->Report(); - } - } - if (!has) temp += "none"; - temp += "."; - f->PutStr(temp); - - temp = "For Sale: "; - has = 0; - { - forlist(&markets) { - Market *m = (Market *) elem; - if (!m->amount) continue; - if(!present && - !(Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_MARKETS)) - continue; - if (m->type == M_BUY) { - if (has) { - temp += ", "; - } else { - has = 1; - } - temp += m->Report(); - } - } - } - if (!has) temp += "none"; - temp += "."; - f->PutStr(temp); -} - -void ARegion::WriteEconomy(Areport *f, Faction *fac, int present) -{ - f->AddTab(); - - if((Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_WAGES) || present) { - f->PutStr(AString("Wages: ") + WagesForReport() + "."); - } else { - f->PutStr(AString("Wages: $0.")); - } - - WriteMarkets(f, fac, present); - - WriteProducts(f, fac, present); - - f->EndLine(); - f->DropTab(); -} - -void ARegion::WriteExits(Areport *f, ARegionList *pRegs, int *exits_seen) -{ - f->PutStr("Exits:"); - f->AddTab(); - /* Hex Patch Dec '03*/ - AString temp = ""; - int y = 0; - for (int i=0; iPrint(pRegs); - - Hexside *h = hexside[i]; - if(h && h->type) temp += AString(", ") + HexsideDefs[h->type].name; - if(h && h->road != 0) { - temp += AString(", ") + HexsideDefs[H_ROAD].name; - if(h->road > 0) temp += AString(" (needs ") + h->road + ")"; - } - if(h && h->bridge != 0) { - temp += AString(", ") + HexsideDefs[H_BRIDGE].name; - if(h->bridge > 0) temp += AString(" (needs ") + h->bridge + ")"; - } - if(h && h->harbour != 0) { - temp += AString(", ") + HexsideDefs[H_HARBOUR].name; - if(h->harbour > 0) temp += AString(" (needs ") + h->harbour + ")"; - } - - temp += "."; - - f->PutStr(temp); - y = 1; - } - else if (exits_seen[i]) { - if(hexside[i]->type) { - Hexside *h = hexside[i]; - temp = AString(DirectionStrs[i]) + " : "; - if(h && h->type) temp += HexsideDefs[h->type].name; - - temp += "."; - - f->PutStr(temp); - y = 1; - } - } - } - if (!y) f->PutStr("none"); - f->DropTab(); - f->EndLine(); -} -/* -#define AC_STRING "%s Nexus is a magical place; the entryway " \ -"to the world of %s. Enjoy your stay, the city guards should " \ -"keep you safe as long as you should choose to stay. However, rumour " \ -"has it that once you have left the Nexus, you can never return." -*/ - - -#define AC_STRING "%s Nexus is a magical place; the purgatory " \ -"of the world of %s. If you have ended up here, it is because " \ -"something has gone wrong. Most likely, too many factions have " \ -"already joined the world, and there was no space for your own." - - -void ARegion::WriteReport(Areport *f, Faction *fac, int month, - ARegionList *pRegions) -{ - Farsight *farsight = GetFarsight(&farsees, fac); - Farsight *passer = GetFarsight(&passers, fac); - int present = Present(fac) || fac->IsNPC(); - - if (farsight || passer || present) { - AString temp = Print(pRegions); - if (Population() && - (present || farsight || - (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_PEASANTS))) { - temp += AString(", ") + Population() + " peasants"; - if(Globals->RACES_EXIST) { - temp += AString(" (") + ItemDefs[race].names + ")"; - } - if(present || farsight || - Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_REGION_MONEY) { - temp += AString(", $") + money; - } else { - temp += AString(", $0"); - } - } - temp += "."; - f->PutStr(temp); - f->PutStr("-------------------------------------------------" - "-----------"); - - f->AddTab(); - if(Globals->WEATHER_EXISTS) { - temp = "It was "; - if (clearskies) temp += "unnaturally clear "; - else { - if(weather == W_BLIZZARD) temp = "There was an unnatural "; - else if(weather == W_NORMAL) temp = "The weather was "; - temp += SeasonNames[weather]; - } - temp += " last month; "; - int nxtweather = pRegions->GetWeather(this, (month + 1) % 12); - temp += "it will be "; - temp += SeasonNames[nxtweather]; - temp += " next month."; - f->PutStr(temp); - } - -#if 0 - f->PutStr(""); - temp = "Elevation is "; - f->PutStr(temp + elevation); - temp = "Humidity is "; - f->PutStr(temp + humidity); - temp = "Temperature is "; - f->PutStr(temp + temperature); -#endif - - if (type == R_NEXUS) { - int len = strlen(AC_STRING)+2*strlen(Globals->WORLD_NAME); - char *nexus_desc = new char[len]; - sprintf(nexus_desc, AC_STRING, Globals->WORLD_NAME, - Globals->WORLD_NAME); - f->PutStr(""); - f->PutStr(nexus_desc); - f->PutStr(""); - delete [] nexus_desc; - } - - f->DropTab(); - - WriteEconomy(f, fac, present || farsight); - -//write events - f->PutStr("Events:"); - f->AddTab(); - - int done = 0; - if(fog) { - done = 1; - f->PutStr("There is an unnatural fog over the region."); - } - - - if(events.First()) { - done = 1; - forlist(&events) { - AString *temp = (AString *) elem; - f->PutStr(*temp); - } - } - - if(willsink>0) { - if(willsink>1) temp = AString("This region will sink beneath the seas in ") + willsink + " months"; - else if(willsink == 1) temp = "This region will sink beneath the seas next month."; - f->PutStr(temp); - done = 1; - } - if (!done) f->PutStr("none"); - f->DropTab(); - f->EndLine(); - - int exits_seen[NDIRS]; - if(present || farsight || - (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_ALL_EXITS)) { - for(int i = 0; i < NDIRS; i++) - exits_seen[i] = 1; - } else { - // This is just a transit report and we're not showing all - // exits. See if we are showing used exits. - - // Show none by default. - int i; - for(i = 0; i < NDIRS; i++) - exits_seen[i] = 0; - // Now, if we should, show the ones actually used. - if(Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_USED_EXITS) { - forlist(&passers) { - Farsight *p = (Farsight *)elem; - if(p->faction == fac) { - for(i = 0; i < NDIRS; i++) { - exits_seen[i] |= p->exits_used[i]; - } - } - } - } - } - - WriteExits(f, pRegions, exits_seen); - - - if(Globals->GATES_EXIST && gate && gate != -1) { - int sawgate = 0; - if(fac->IsNPC()) - sawgate = 1; - if(Globals->IMPROVED_FARSIGHT && farsight) { - forlist(&farsees) { - Farsight *watcher = (Farsight *)elem; - if(watcher && watcher->faction == fac && watcher->unit) { - if(watcher->unit->GetSkill(S_GATE_LORE)) { - sawgate = 1; - } - } - } - } - if(Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) { - forlist(&passers) { - Farsight *watcher = (Farsight *)elem; - if(watcher && watcher->faction == fac && watcher->unit) { - if(watcher->unit->GetSkill(S_GATE_LORE)) { - sawgate = 1; - } - } - } - } - forlist(&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (!sawgate && - ((u->faction == fac) && - u->GetSkill(S_GATE_LORE))) { - sawgate = 1; - } - } - } - if(sawgate) { - if(gateopen) { - f->PutStr(AString("There is a Gate here (Gate ") + gate + - " of " + (pRegions->numberofgates) + ")."); - f->PutStr(""); - } else if (Globals->SHOW_CLOSED_GATES) { - f->PutStr(AString("There is a closed Gate here.")); - f->PutStr(""); - } - } - } - int obs = GetObservation(fac, 0); - int truesight = GetTrueSight(fac, 0); - int detfac = 0; - int passobs = GetObservation(fac, 1); - int passtrue = GetTrueSight(fac, 1); - int passdetfac = detfac; - if(fac->IsNPC()) { - obs = 10; - passobs = 10; - } - forlist (&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == fac && (u->GetSkill(S_MIND_READING) > 2 || (Globals->ARCADIA_MAGIC && u->GetSkill(S_MIND_READING) > 1)) ) { - detfac = 1; - } - } - } - if(Globals->IMPROVED_FARSIGHT && farsight) { - forlist(&farsees) { - Farsight *watcher = (Farsight *)elem; - if(watcher && watcher->faction == fac && watcher->unit) { - if(watcher->unit->GetSkill(S_MIND_READING) > 2 || (Globals->ARCADIA_MAGIC && watcher->unit->GetSkill(S_MIND_READING) > 1) ) { - detfac = 1; - } - } - } - } - - if((Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) && - (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_UNITS)) { - forlist(&passers) { - Farsight *watcher = (Farsight *)elem; - if(watcher && watcher->faction == fac && watcher->unit) { - if(watcher->unit->GetSkill(S_MIND_READING) > 2 || (Globals->ARCADIA_MAGIC && watcher->unit->GetSkill(S_MIND_READING) > 1)) { - passdetfac = 1; - } - } - } - } - { - forlist (&objects) { - ((Object *) elem)->Report(f, fac, obs, truesight, fog, detfac, - passobs, passtrue, passdetfac, - present || farsight); - } - f->EndLine(); - } - } -} - -// DK -void ARegion::WriteTemplate(Areport *f, Faction *fac, - ARegionList *pRegs, int month) -{ - int header = 0; - - forlist (&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == fac) { - if (!header) { - // DK - if (fac->temformat == TEMPLATE_MAP) { - WriteTemplateHeader(f, fac, pRegs, month); - } else { - f->PutStr(""); - f->PutStr(AString("*** ") + Print(pRegs) + " ***", 1); - } - header = 1; - } - - f->PutStr(""); - f->PutStr(AString("unit ") + u->num); - // DK - if (fac->temformat == TEMPLATE_LONG || - fac->temformat == TEMPLATE_MAP) { - f->PutStr(u->TemplateReport(), 1); - } - forlist(&(u->oldorders)) { - f->PutStr(*((AString *) elem)); - } - u->oldorders.DeleteAll(); - - if (u->turnorders.First()) { - int first = 1; - TurnOrder *tOrder; - forlist(&u->turnorders) { - tOrder = (TurnOrder *)elem; - if (first) { - forlist(&tOrder->turnOrders) { - f->PutStr(*((AString *) elem)); - } - first = 0; - } else { - if (tOrder->repeating) - f->PutStr(AString("@TURN")); - else - f->PutStr(AString("TURN")); - - forlist(&tOrder->turnOrders) { - f->PutStr(*((AString *) elem)); - } - f->PutStr(AString("ENDTURN")); - } - } - tOrder = (TurnOrder *) u->turnorders.First(); - if (tOrder->repeating) { - f->PutStr(AString("@TURN")); - forlist(&tOrder->turnOrders) { - f->PutStr(*((AString *) elem)); - } - f->PutStr(AString("ENDTURN")); - } - } - u->turnorders.DeleteAll(); - } - } - } -} - -int ARegion::GetTrueSight(Faction *f, int usepassers) -{ - int truesight = 0; - - if(Globals->IMPROVED_FARSIGHT) { - forlist(&farsees) { - Farsight *farsight = (Farsight *)elem; - if(farsight && farsight->faction == f && farsight->unit) { - int t = farsight->unit->GetSkill(S_TRUE_SEEING); - if(t > truesight) truesight = t; - } - } - } - - if(usepassers && - (Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) && - (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_UNITS)) { - forlist(&passers) { - Farsight *farsight = (Farsight *)elem; - if(farsight && farsight->faction == f && farsight->unit) { - int t = farsight->unit->GetSkill(S_TRUE_SEEING); - if(t > truesight) truesight = t; - } - } - } - - forlist ((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->faction == f) { - int temp = u->GetSkill(S_TRUE_SEEING); - if (temp>truesight) truesight = temp; - } - } - } - return truesight; -} - -int ARegion::GetObservation(Faction *f, int usepassers) -{ - int obs = 0; - - if(Globals->IMPROVED_FARSIGHT) { - forlist(&farsees) { - Farsight *farsight = (Farsight *)elem; - if(farsight && farsight->faction == f && farsight->unit) { - int o = farsight->unit->GetAttribute("observation"); - if(o > obs) obs = o; - } - } - } - if(usepassers && - (Globals->TRANSIT_REPORT & GameDefs::REPORT_USE_UNIT_SKILLS) && - (Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_UNITS)) { - forlist(&passers) { - Farsight *farsight = (Farsight *)elem; - if(farsight && farsight->faction == f && farsight->unit) { - int o = farsight->unit->GetAttribute("observation"); - if(o > obs) obs = o; - } - } - } - forlist ((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->faction == f) { - int temp = u->GetAttribute("observation"); - if (temp>obs) obs = temp; - } - } - } - return obs; -} - -void ARegion::SetWeather(int newWeather) -{ - weather = newWeather; -} - -int ARegion::IsCoastal() -{ - if (TerrainDefs[type].similar_type == R_OCEAN || TerrainDefs[type].similar_type == R_FAKE) return 1; - int seacount = 0; - for (int i=0; itype].similar_type == R_OCEAN || TerrainDefs[neighbors[i]->type].similar_type == R_FAKE) ) { - if (!Globals->LAKESIDE_IS_COASTAL && neighbors[i]->type == R_LAKE) continue; - seacount++; - } - } - return seacount; -} - -int ARegion::IsCoastalOrLakeside() -{ -/* BS Sailing Patch */ - if ((type != R_LAKE) && (TerrainDefs[type].similar_type == R_OCEAN || TerrainDefs[type].similar_type == R_FAKE) ) return 1; - int seacount = 0; - for (int i=0; itype].similar_type == R_OCEAN || TerrainDefs[neighbors[i]->type].similar_type == R_FAKE) ) { - seacount++; - } - } - return seacount; -} - -int ARegion::MoveCost(int movetype, ARegion *fromRegion, int dir, AString *road) -{ - int cost = 1; - if(Globals->WEATHER_EXISTS) { - cost = 2; - if (weather == W_BLIZZARD && !clearskies) return 10; - if (weather == W_NORMAL || clearskies) cost = 1; - } - if (movetype != M_FLY) { //ie walk, ride, swim* or none *: don't think swim gets sent here - cost = (TerrainDefs[type].movepoints * cost); - - /* Hex Patch Dec '03 */ - if(!(Globals->HEXSIDE_TERRAIN)) { - if(fromRegion->HasExitRoad(dir) && fromRegion->HasConnectingRoad(dir)) { - cost -= cost/2; - if (road) - *road = "on a road "; - } - } - if(Globals->HEXSIDE_TERRAIN && dir < NDIRS) { //NDIRS condition in case of MOVE_IN. - int block = 0; - /* Hex Patch Dec '03 */ - Hexside *h = fromRegion->hexside[dir]; - if(h->road < 0) { - cost = (cost * (HexsideDefs[H_ROAD].movementmultiplier + 2) + 1) /2 ; - block += HexsideDefs[H_ROAD].blockeffect; - } - if(h->bridge < 0) { - cost = (cost * (HexsideDefs[H_BRIDGE].movementmultiplier + 2) + 1) /2; - block += HexsideDefs[H_BRIDGE].blockeffect; - } - if(h->type) { - cost = (cost * (HexsideDefs[h->type].movementmultiplier + 2) + 1) /2; - block += HexsideDefs[h->type].blockeffect; - } - - if(block>0) return -1; // note this only applies to walking and riding - } - - } - if(cost < 1) cost = 1; - return cost; -} - -Unit *ARegion::Forbidden(Unit *u) -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u2 = (Unit *) elem; - if (u2->Forbids(this, u)) return u2; - } - } - return 0; -} - -Unit *ARegion::ForbiddenByAlly(Unit *u) -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u2 = (Unit *) elem; - if (u->faction->GetAttitude(u2->faction->num) == A_ALLY && - u2->Forbids(this, u)) return u2; - } - } - return 0; -} - -int ARegion::HasCityGuard() -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->type == U_GUARD && u->GetSoldiers() && - u->guard == GUARD_GUARD) { - return 1; - } - } - } - return 0; -} - -int ARegion::NotifySpell(Unit *caster, char *spell, ARegionList *pRegs) -{ - AList flist; - unsigned int i; - - SkillType *pS = FindSkill(spell); - - if (!(pS->flags & SkillType::NOTIFY)) { - // Okay, we aren't notifyable, check our prerequisites - for(i = 0; i < sizeof(pS->depends)/sizeof(SkillDepend); i++) { - if (pS->depends[i].skill == NULL) break; - if(NotifySpell(caster, pS->depends[i].skill, pRegs)) return 1; - } - return 0; - } - - AString skname = spell; - int sp = LookupSkill(&skname); - forlist((&objects)) { - Object *o = (Object *) elem; - forlist ((&o->units)) { - Unit *u = (Unit *) elem; - if (u->faction == caster->faction) continue; - if (u->GetSkill(sp)) { - if (!GetFaction2(&flist, u->faction->num)) { - FactionPtr *fp = new FactionPtr; - fp->ptr = u->faction; - flist.Add(fp); - } - } - } - } - - forlist_reuse (&flist) { - FactionPtr *fp = (FactionPtr *) elem; - fp->ptr->Event(AString(*(caster->name)) + " uses " + SkillStrs(sp) + - " in " + Print(pRegs) + "."); - } - return 1; -} - -// ALT, 26-Jul-2000 -// Procedure to notify all units in city about city name change -void ARegion::NotifyCity(Unit *caster, AString& oldname, AString& newname) -{ - AList flist; - forlist((&objects)) { - Object *o = (Object *) elem; - forlist ((&o->units)) { - Unit *u = (Unit *) elem; - if (u->faction == caster->faction) continue; - if (!GetFaction2(&flist, u->faction->num)) { - FactionPtr *fp = new FactionPtr; - fp->ptr = u->faction; - flist.Add(fp); - } - } - } - { - forlist(&flist) { - FactionPtr *fp = (FactionPtr *) elem; - fp->ptr->Event(AString(*(caster->name)) + " renames " + - oldname + " to " + newname + "."); - } - } -} - -int ARegion::CanTax(Unit *u) -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u2 = (Unit *) elem; - if (u2->guard == GUARD_GUARD && u2->IsReallyAlive()) - if(u2->type == U_GUARD || u2->type == U_GUARDMAGE) { - if(town) return 0; //guards prevent taxing in towns - if(u2->faction->ethnicity != u->faction->ethnicity) return 0; //guards prevent other ethnicities taxing - } else if (u2->GetAttitude(this, u) <= A_NEUTRAL) return 0; - } - } - - return 1; -} - -int ARegion::CanPillage(Unit *u) -{ - forlist(&objects) { - Object *obj = (Object *)elem; - forlist (&obj->units) { - Unit *u2 = (Unit *)elem; - if(u2->guard == GUARD_GUARD && u2->IsReallyAlive() && - u2->faction != u->faction) - return 0; - } - } - return 1; -} - -int ARegion::ForbiddenShip(Object *ship) -{ - forlist(&ship->units) { - Unit *u = (Unit *) elem; - if (Forbidden(u)) return 1; - } - return 0; -} - -void ARegion::DefaultOrders(int peasantfaction) -//peasantfaction is carried for ARCADIA MAGIC, it has no effect if ARCADIA_MAGIC is disabled. -{ - forlist((&objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) - ((Unit *) elem)->DefaultOrders(obj, peasantfaction); - } -} - -// -// This is just used for mapping; just check if there is an inner region. -// -int ARegion::HasShaft() -{ - forlist (&objects) { - Object *o = (Object *) elem; - if (o->inner != -1) return 1; - } - return 0; -} - -int ARegion::IsGuarded() -{ - forlist (&objects) { - Object *o = (Object *) elem; - forlist (&o->units) { - Unit *u = (Unit *) elem; - if (u->guard == GUARD_GUARD) return 1; - } - } - return 0; -} - -int ARegion::CountWMons() -{ - int count = 0; - forlist (&objects) { - Object *o = (Object *) elem; - forlist (&o->units) { - Unit *u = (Unit *) elem; - if (u->type == U_WMON) { - count ++; - } - } - } - return count; -} - -ARegionList::ARegionList() -{ - pRegionArrays = 0; - numLevels = 0; - numberofgates = 0; -} - -ARegionList::~ARegionList() -{ - if(pRegionArrays) { - int i; - for(i = 0; i < numLevels; i++) { - delete pRegionArrays[i]; - } - - delete pRegionArrays; - } -} - -void ARegionList::WriteRegions(Aoutfile *f) -{ - f->PutInt(Num()); - - f->PutInt(numLevels); - int i; - for(i = 0; i < numLevels; i++) { - ARegionArray *pRegs = pRegionArrays[i]; - f->PutInt(pRegs->x); - f->PutInt(pRegs->y); - if(pRegs->strName) { - f->PutStr(*pRegs->strName); - } else { - f->PutStr("none"); - } - f->PutInt(pRegs->levelType); - } - - f->PutInt(numberofgates); - forlist(this) ((ARegion *) elem)->Writeout(f); - { - f->PutStr("Neighbors"); - forlist(this) { - ARegion *reg = (ARegion *) elem; - for(i = 0; i < NDIRS; i++) { - if (reg->neighbors[i]) { - f->PutInt(reg->neighbors[i]->num); - } else { - f->PutInt(-1); - } - } - } - } -} - -int ARegionList::ReadRegions(Ainfile *f, AList *factions, ATL_VER v) -{ - int num = f->GetInt(); - - numLevels = f->GetInt(); - CreateLevels(numLevels); - int i; - for(i = 0; i < numLevels; i++) { - int curX = f->GetInt(); - int curY = f->GetInt(); - AString *name = f->GetStr(); - ARegionArray *pRegs = new ARegionArray(curX, curY); - if(*name == "none") { - pRegs->strName = 0; - delete name; - } else { - pRegs->strName = name; - } - pRegs->levelType = f->GetInt(); - pRegionArrays[i] = pRegs; - } - - numberofgates = f->GetInt(); - - ARegionFlatArray fa(num); - - Awrite("Reading the regions..."); - for(i = 0; i < num; i++) { - ARegion *temp = new ARegion; - temp->Readin(f, factions, v); - fa.SetRegion(temp->num, temp); - Add(temp); - - pRegionArrays[temp->zloc]->SetRegion(temp->xloc, temp->yloc, - temp); - } - - Awrite("Setting up the neighbors..."); - { - delete f->GetStr(); - forlist(this) { - ARegion *reg = (ARegion *) elem; - for(i = 0; i < NDIRS; i++) { - int j = f->GetInt(); - if (j != -1) { - reg->neighbors[i] = fa.GetRegion(j); - } else { - reg->neighbors[i] = 0; - } - } - } - } - Awrite("Setting up the hexsides..."); - { - forlist(this) { - ARegion *reg = (ARegion *) elem; - for(i = 0; i < NDIRS; i++) { - if(!reg->hexside[i]) { - if(i<3 && reg->neighbors[i]->hexside[i+3]) reg->hexside[i] = reg->neighbors[i]->hexside[i+3]; - else if(i>2 && reg->neighbors[i]->hexside[i-3]) reg->hexside[i] = reg->neighbors[i]->hexside[i-3]; - else { - Awrite("bugger!"); - #ifdef DEBUG - system("pause"); - #endif - Hexside *temp = new Hexside; - reg->hexside[i] = temp; - } - } - } - } - } - return 1; -} - -ARegion *ARegionList::GetRegion(int n) -{ - forlist(this) { - if (((ARegion *) elem)->num == n) return ((ARegion *) elem); - } - return 0; -} - -ARegion *ARegionList::GetRegion(int x, int y, int z) -{ - - if (z >= numLevels) return NULL; - - ARegionArray *arr = pRegionArrays[z]; - if(!Globals->FLAT_WORLD) { - x = (x + arr->x) % arr->x; - y = (y + arr->y) % arr->y; - } else { - if(x < 0 || x >= arr->x) return 0; - if(y < 0 || y >= arr->y) return 0; - } - - return(arr->GetRegion(x, y)); -} - -Location *ARegionList::FindUnit(int i) -{ - forlist(this) { - ARegion *reg = (ARegion *) elem; - forlist((®->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->num == i) { - Location *retval = new Location; - retval->unit = u; - retval->region = reg; - retval->obj = obj; - return retval; - } - } - } - } - return 0; -} - -void ARegionList::EditNeighSetup(ARegion *r, ARegionArray *ar) -{ - NeighSetup(r,ar); -} - -void ARegionList::NeighSetup(ARegion *r, ARegionArray *ar) -{ - r->ZeroNeighbors(); - - if (r->yloc != 0 && r->yloc != 1) { - r->neighbors[D_NORTH] = ar->GetRegion(r->xloc, r->yloc - 2); - } - if (r->yloc != 0) { - r->neighbors[D_NORTHEAST] = ar->GetRegion(r->xloc + 1, r->yloc - 1); - r->neighbors[D_NORTHWEST] = ar->GetRegion(r->xloc - 1, r->yloc - 1); - } - if (r->yloc != ar->y - 1) { - r->neighbors[D_SOUTHEAST] = ar->GetRegion(r->xloc + 1, r->yloc + 1); - r->neighbors[D_SOUTHWEST] = ar->GetRegion(r->xloc - 1, r->yloc + 1); - } - if (r->yloc != ar->y - 1 && r->yloc != ar->y - 2) { - r->neighbors[D_SOUTH] = ar->GetRegion(r->xloc, r->yloc + 2); - } -} - -void ARegionList::IcosahedralNeighSetup(ARegion *r, ARegionArray *ar) -{ - int scale, x, y, x2, y2, x3, neighX, neighY; - - scale = ar->x / 10; - - r->ZeroNeighbors(); - // x2 is the x-coord of this hex inside its "wedge" - if (y < 5 * scale) - x2 = x % (2 * scale); - else - x2 = (x + 1) % (2 * scale); - // x3 is the distance of this hex from the right side of its "wedge" - x3 = (2 * scale - x2) % (2 * scale); - // y2 is the distance from the SOUTH pole - y2 = 10 * scale - 1 - y; - // Always try to connect in the standard way... - if (y > 1) { - r->neighbors[D_NORTH] = ar->GetRegion(x, y - 2); - } - // but if that fails, use the special icosahedral connections: - if (!r->neighbors[D_NORTH]) { - if (y > 0 & y < 3 * scale) - { - if (y == 2) { - neighX = 0; - neighY = 0; - } - else if (y == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y - 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y - 2; - } - neighX %= (scale * 10); - r->neighbors[D_NORTH] = ar->GetRegion(neighX, neighY); - } - } - if (y > 0) { - neighX = x + 1; - neighY = y - 1; - neighX %= (scale * 10); - r->neighbors[D_NORTHEAST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_NORTHEAST]) { - if (y == 0) { - neighX = 4 * scale; - neighY = 2; - } - else if (y < 3 * scale) { - if (y == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y + 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y; - } - } - else if (y2 < 1) { - neighX = x + 2 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - neighX = x + 2 * (scale - x2); - neighY = y - 2; - } - neighX %= (scale * 10); - r->neighbors[D_NORTHEAST] = ar->GetRegion(neighX, neighY); - } - if (y2 > 0) { - neighX = x + 1; - neighY = y + 1; - neighX %= (scale * 10); - r->neighbors[D_SOUTHEAST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_SOUTHEAST]) { - if (y == 0) { - neighX = 2 * scale; - neighY = 2; - } - else if (y2 < 1) { - neighX = x + 4 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - if (y2 == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y - 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y; - } - } - else if (y < 3 * scale) { - neighX = x + 2 * (scale - x2); - neighY = y + 2; - } - neighX %= (scale * 10); - r->neighbors[D_SOUTHEAST] = ar->GetRegion(neighX, neighY); - } - if (y2 > 1) { - r->neighbors[D_SOUTH] = ar->GetRegion(x, y + 2); - } - if (!r->neighbors[D_SOUTH]) { - if (y2 > 0 & y2 < 3 * scale) - { - if (y2 == 2) { - neighX = 10 * scale - 1; - neighY = y + 2; - } - else if (y2 == 3 * x2) { - neighX = x + 2 * (scale - x2) + 1; - neighY = y + 1; - } - else { - neighX = x + 2 * (scale - x2); - neighY = y + 2; - } - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_SOUTH] = ar->GetRegion(neighX, neighY); - } - } - if (y2 > 0) { - neighX = x - 1; - neighY = y + 1; - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_SOUTHWEST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_SOUTHWEST]) { - if (y == 0) { - neighX = 8 * scale; - neighY = 2; - } - else if (y2 < 1) { - neighX = x + 6 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - if (y2 == 3 * x3 + 4) { - neighX = x + 2 * (x3 - scale) + 1; - neighY = y + 1; - } - else { - neighX = x + 2 * (x3 - scale); - neighY = y; - } - } - else if (y < 3 * scale) { - neighX = x - 2 * (scale - x3) + 1; - neighY = y + 1; - } - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_SOUTHWEST] = ar->GetRegion(neighX, neighY); - } - if (y > 0) { - neighX = x - 1; - neighY = y - 1; - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_NORTHWEST] = ar->GetRegion(neighX, neighY); - } - if (!r->neighbors[D_NORTHWEST]) { - if (y == 0) { - neighX = 6 * scale; - neighY = 2; - } - else if (y < 3 * scale) { - if (y == 3 * x3 + 4) { - neighX = x + 2 * (x3 - scale) + 1; - neighY = y - 1; - } - else { - neighX = x + 2 * (x3 - scale); - neighY = y; - } - } - else if (y2 < 1) { - neighX = x + 8 * scale; - neighY = y - 2; - } - else if (y2 < 3 * scale) { - neighX = x - 2 * (scale - x3) + 1; - neighY = y - 1; - } - neighX = (neighX + scale * 10) % (scale * 10); - r->neighbors[D_NORTHWEST] = ar->GetRegion(neighX, neighY); - } -} - -void ARegionList::CalcDensities() -{ - Awrite("Densities:"); - int arr[R_NUM]; - int i; - for (i=0; itype]++; - } - for (i=0; igate == x) return r; - } - return 0; -} - -int ARegionList::GetPlanarDistance(ARegion *one, ARegion *two, int penalty) -{ - if(one->zloc == ARegionArray::LEVEL_NEXUS || - two->zloc == ARegionArray::LEVEL_NEXUS) - return 10000000; - - if (Globals->ABYSS_LEVEL) { - // make sure you cannot teleport into or from the abyss - int ablevel = Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + 2; - if (one->zloc == ablevel || two->zloc == ablevel) - return 10000000; - } - - int one_x, one_y, two_x, two_y; - int maxy; - ARegionArray *pArr=pRegionArrays[ARegionArray::LEVEL_SURFACE]; - - one_x = one->xloc * GetLevelXScale(one->zloc); - one_y = one->yloc * GetLevelYScale(one->zloc); - - two_x = two->xloc * GetLevelXScale(two->zloc); - two_y = two->yloc * GetLevelYScale(two->zloc); - - maxy = one_y - two_y; - if(maxy < 0) maxy=-maxy; - - int maxx = one_x - two_x; - if(maxx < 0) maxx = -maxx; - - if(!Globals->FLAT_WORLD) { - int max2 = one_x + pArr->x - two_x; - if(max2 < 0) max2 = -max2; - if(max2 < maxx) maxx = max2; - - max2 = one_x - (two_x + pArr->x); - if(max2 < 0) max2 = -max2; - if(max2 < maxx) maxx = max2; - } - - if(maxy > maxx) maxx = (maxx+maxy)/2; - - if(one->zloc != two->zloc) { - int zdist = (one->zloc - two->zloc); - if ((two->zloc - one->zloc) > zdist) - zdist = two->zloc - one->zloc; - maxx += (penalty * zdist); - } - - return maxx; -} - -int ARegionList::GetDistance(ARegion *one, ARegion *two) -{ - if(one->zloc != two->zloc) return(10000000); - - ARegionArray *pArr = pRegionArrays[one->zloc]; - - int maxy; - maxy = one->yloc - two->yloc; - if (maxy < 0) maxy = -maxy; - - int maxx = one->xloc - two->xloc; - if (maxx < 0) maxx = -maxx; - - if(!Globals->FLAT_WORLD) { - int max2 = one->xloc + pArr->x - two->xloc; - if (max2 < 0) max2 = -max2; - if (max2 < maxx) maxx = max2; - - max2 = one->xloc - (two->xloc + pArr->x); - if (max2 < 0) max2 = -max2; - if (max2 < maxx) maxx = max2; - } - - if (maxy > maxx) return (maxx + maxy) / 2; - return maxx; -} - -ARegionArray *ARegionList::GetRegionArray(int level) -{ - return(pRegionArrays[level]); -} - -void ARegionList::CreateLevels(int n) -{ - numLevels = n; - pRegionArrays = new ARegionArray *[n]; -} - -ARegionArray::ARegionArray(int xx, int yy) -{ - x = xx; - y = yy; - regions = new ARegion *[x * y / 2 + 1]; - strName = 0; - - int i; - for(i = 0; i < x * y / 2; i++) regions[i] = 0; -} - -ARegionArray::~ARegionArray() -{ - if (strName) delete strName; - delete [] regions; -} - -void ARegionArray::SetRegion(int xx, int yy, ARegion *r) -{ - regions[xx / 2 + yy * x / 2] = r; -} - -ARegion *ARegionArray::GetRegion(int xx, int yy) -{ - if(!Globals->FLAT_WORLD) { - xx = (xx + x) % x; - yy = (yy + y) % y; - } else { - if(xx<0 || xx>=x) return 0; - if(yy<0 || yy>=y) return 0; - } - if((xx + yy) % 2) return(0); - return(regions[xx / 2 + yy * x / 2]); -} - -void ARegionArray::SetName(char *name) -{ - if(name) { - strName = new AString(name); - } else { - delete strName; - strName = 0; - } -} - -ARegionFlatArray::ARegionFlatArray(int s) -{ - size = s; - regions = new ARegion *[s]; -} - -ARegionFlatArray::~ARegionFlatArray() -{ - if (regions) delete regions; -} - -void ARegionFlatArray::SetRegion(int x, ARegion *r) { - regions[x] = r; -} - -ARegion *ARegionFlatArray::GetRegion(int x) { - return regions[x]; -} - -int ParseTerrain(AString *token) -{ - for (int i = 0; i < R_NUM; i++) { - if (*token == TerrainDefs[i].type) return i; - } - - for (int i = 0; i < R_NUM; i++) { - if (*token == TerrainDefs[i].name) return i; - } - - return (-1); -} - -void ARegion::Fake() -{ - type = R_FAKE; - if(Globals->HEXSIDE_TERRAIN) { - for (int i=0; itype = H_DUMMY; - hexside[i]->road = 0; - hexside[i]->bridge = 0; - hexside[i]->harbour = 0; - } - } - - //gates left so the gate spell doesn't crash - willsink = 0; - untaxed = 0; - if(town) delete town; - town = 0; - //economics stuff - development = 0; - habitat = 0; - mortality = 0; - growth = 0; - migration = 0; - culture = 0; - clearskies = 0; - earthlore = 0; - fog = 0; - flagpole = FL_NULL; - - race = -1; - - population = 0; - basepopulation = 0; - wages = 0; - maxwages = 0; - money = 0; - - elevation = 0; - humidity = 0; - temperature = 0; - vegetation = 0; - - products.DeleteAll(); - markets.DeleteAll(); -} - -void ARegion::SinkRegion(ARegionList *pRegs) -{ - if(TerrainDefs[type].similar_type == R_OCEAN) return; - if(IsCoastal()) type = R_OCEAN; - else type = R_LAKE; - - AString ocean_name = Globals->WORLD_NAME; - ocean_name += " Ocean"; - SetName(ocean_name.Str()); - - forlist(&objects) { - Object *obj = (Object *) elem; - if(obj->IsBoat()) { - if(Globals->HEXSIDE_TERRAIN) obj->hexside = -1; - } else { - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - int drown = 0; - if(u->type == U_WMON) { - // Make sure flying monsters only drown if we - // are in WFLIGHT_NONE mode - if(Globals->FLIGHT_OVER_WATER==GameDefs::WFLIGHT_NONE) - drown = !(u->CanReallySwim()); - else - drown = !(u->CanSwim()); - } else { - switch(Globals->FLIGHT_OVER_WATER) { - case GameDefs::WFLIGHT_UNLIMITED: - drown = !(u->CanSwim()); - break; - case GameDefs::WFLIGHT_MUST_LAND: - drown = !(u->CanReallySwim() || u->leftShip); - u->leftShip = 0; - break; - case GameDefs::WFLIGHT_NONE: - drown = !(u->CanReallySwim()); - break; - default: // Should never happen - drown = 1; - break; - } - } - if (drown) { - Kill(u); - u->Event("Drowns in the ocean."); - } - } - if(obj->type != O_DUMMY) { - //Move non-drowning units out - Object *dest = GetDummy(); - forlist(&obj->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(dest); - } - //if inner object, destroy link (if any) at other end. - if(obj->inner > -1) { - ARegion *newreg = pRegs->GetRegion(obj->inner); - forlist(&newreg->objects) { - Object *ob = (Object *) elem; - if(ob->inner == num) { //if it's inner and pointing here, it dies, even if it's mirror is something else - Object *dest = newreg->GetDummy(); - forlist(&obj->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(dest); - } - newreg->objects.Remove(ob); - delete ob; - } - } - } - //destroy object - objects.Remove(obj); - delete obj; - } - } - } - buildingseq = 1; -// add beaches. -/* Hex Patch Dec '03 */ - if (Globals->HEXSIDE_TERRAIN) { - for(int k=0; k<6; k++) { - if(!neighbors[k]) continue; - if(neighbors[k]->type == R_LAKE) neighbors[k]->type = R_OCEAN; - if(TerrainDefs[neighbors[k]->type].similar_type == R_OCEAN) { - hexside[k]->type = H_DUMMY; - hexside[k]->bridge = 0; - hexside[k]->road = 0; - continue; - } - - int coasttype = H_DUMMY; - if(!(HexsideDefs[H_BEACH].flags & HexsideType::DISABLED)) coasttype = H_BEACH; - if(!(HexsideDefs[H_HARBOUR].flags & HexsideType::DISABLED)) { - if(coasttype == H_DUMMY || getrandom(100) < 10) coasttype = H_HARBOUR; - } - if(!(HexsideDefs[H_ROCKS].flags & HexsideType::DISABLED)) { - if(coasttype == H_DUMMY || getrandom(100) < 5) coasttype = H_ROCKS; - } - - hexside[k]->type = coasttype; - //destroy bridges & roads - hexside[k]->bridge = 0; - hexside[k]->road = 0; - } - } - -// convert neighbour lakes to ocean - for(int k=0; k<6; k++) { - if(!neighbors[k]) continue; - if((TerrainDefs[neighbors[k]->type].similar_type == R_OCEAN) && (neighbors[k]->type != R_OCEAN)) neighbors[k]->type = R_OCEAN; //ie if it's water but not ocean ... - } - - -// redo economy - if(town) { - //move peasants out to a neighbouring region, if there is one. - int emptyregions = 0; - int townregions = 0; - int newdir = -1; - for(int i=0; itype].similar_type != R_OCEAN) { - if(neighbors[i]->town) townregions++; - else { - emptyregions++; - if(!getrandom(emptyregions)) newdir = i; //getrandom(1) is always 0. - } - } - } - - if(newdir != -1) { - neighbors[newdir]->town = town; - town = NULL; - } else { - if(townregions) { - //we can't move the whole town. Move the peasants into neighbouring towns if possible. - int peasants = town->pop; - int basepeasants = town->basepop; - for(int i=0; itown) { - neighbors[i]->town->pop += peasants/townregions; - neighbors[i]->town->basepop += basepeasants/townregions; - peasants -= peasants/townregions; - basepeasants -= basepeasants/townregions; - townregions--; - if(neighbors[i]->town->pop > 6000) { - //new town too big, remove some people. - peasants += neighbors[i]->town->pop - 6000; - basepeasants += neighbors[i]->town->pop - 6000; - neighbors[i]->town->basepop -= neighbors[i]->town->pop - 6000; - neighbors[i]->town->pop = 6000; - } - } - if(peasants) { - //still got some peasants. - //well, bugger that. 6000 people in one town means they're rich anyway. - } - } - } - delete town; - town = NULL; - } - } - - products.DeleteAll(); - SetupProds(); - - markets.DeleteAll(); - - SetupEditRegion(); - UpdateEditRegion(); -} - -void ARegion::OceanToLand() -// exact land type will be set later -// economy to be reset later -{ -int lastocean = -1; - - //have to set this to land to generate lakes properly later - if(TerrainDefs[type].similar_type == R_OCEAN) type = R_MOUNTAIN; - - if(Globals->HEXSIDE_TERRAIN) { - - for(int k=0; k<6; k++) { - if(neighbors[k]) { - if(TerrainDefs[neighbors[k]->type].similar_type == R_OCEAN) lastocean = k; - } - } - - forlist(&objects) { - Object *obj = (Object *) elem; - if(obj->IsBoat()) { - if(Globals->HEXSIDE_TERRAIN && ObjectDefs[obj->type].hexside) obj->hexside = lastocean; // note this may place ocean-only ships on beaches! - } else if(obj->type != O_DUMMY) { - Object *dest = GetDummy(); - forlist(&obj->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(dest); - } - //destroy object - objects.Remove(obj); - delete obj; - } - - } - -// add/remove beaches. - for(int k=0; k<6; k++) { - if(!neighbors[k]) continue; - if(!TerrainDefs[neighbors[k]->type].similar_type == R_OCEAN) { - hexside[k]->type = H_DUMMY; //gets rid of beaches - continue; - } - int coasttype = H_DUMMY; - if(!(HexsideDefs[H_BEACH].flags & HexsideType::DISABLED)) coasttype = H_BEACH; - if(!(HexsideDefs[H_HARBOUR].flags & HexsideType::DISABLED)) { - if(coasttype == H_DUMMY || getrandom(100) < 10) coasttype = H_HARBOUR; - } - if(!(HexsideDefs[H_ROCKS].flags & HexsideType::DISABLED)) { - if(coasttype == H_DUMMY || getrandom(100) < 5) coasttype = H_ROCKS; - } - - hexside[k]->type = coasttype; - //destroy bridges & roads - hexside[k]->bridge = 0; - hexside[k]->road = 0; - } - } - -// convert neighbours to lakes if necessary - for(int k=0; k<6; k++) { - if(!neighbors[k]) continue; - if(TerrainDefs[neighbors[k]->type].similar_type != R_OCEAN) continue; - int lake = 1; - for(int j=0; j<6; j++) { - if(!neighbors[k]->neighbors[j]) continue; - if(TerrainDefs[neighbors[k]->neighbors[j]->type].similar_type == R_OCEAN) { - lake = 0; - break; //if I stick a break in here will it break one loop (good) or both loops (bad) ? - } - } - if(lake) neighbors[k]->type = R_LAKE; - } - #define NUMREGIONNAMES 1000 - - AString tempname = AString(AGetNameString(NUMREGIONNAMES + getrandom(NUMREGIONNAMES))); - - for(int j=0; j<6; j++) { - if(!neighbors[j]) continue; - if(TerrainDefs[neighbors[j]->type].similar_type == R_OCEAN) continue; - tempname = *(neighbors[j]->name); - } - - SetName(tempname.Str()); -} - -void ARegion::Event(const AString &s) -{ - AString *temp = new AString(s); - events.Add(temp); -} - -AString *TerrainDescription(int type) -{ - if(TerrainDefs[type].flags & TerrainType::DISABLED) - return NULL; - - TerrainType *t = &TerrainDefs[type]; - AString *temp = new AString; - *temp += AString(t->name) + ":"; - - if(t->similar_type == R_OCEAN) { - *temp += " This terrain allows sailing of deep water ships."; - *temp += AString(" This terrain takes ") + t->movepoints + " move points for a swimming or sailing unit to enter."; - } else *temp += AString(" This terrain takes ") + t->movepoints + " move points for a walking or riding unit to enter."; - - int canfly = (t->flags & TerrainType::FLYINGMOUNTS); - int canride = (t->flags & TerrainType::RIDINGMOUNTS); - if(canfly || canride) { - if(!canfly) *temp += " Riding"; - else if(!canride) *temp += " Flying"; - else *temp += " Flying and riding"; - *temp += " mounts may be used here in battle"; - - int limfly = (t->flags & TerrainType::FLYINGLIMITED); - int limride = (t->flags & TerrainType::RIDINGLIMITED); - if(limfly || limride) { - if(limfly && canride) *temp += ", although the combat skill bonus will not be added for flying mounts."; - if(limride && canfly) *temp += ", although the combat skill bonus will not be added for riding mounts."; - else *temp += ", although the combat skill bonus will not be added."; - } else *temp += "."; - } - - if(t->flags & TerrainType::RESTRICTEDFOOT) *temp += " This terrain prevents foot troops flanking around outnumbered opponents during battle."; - if(t->flags & TerrainType::RESTRICTEDRANGED) *temp += " During battle, magic and ranged attacks will suffer a penalty of 1 to their " - "chance-to-attack and attack skill values."; - - //put in some if statements for random economy. - if(t->pop) { - *temp += AString(" This terrain supports a base population of between ") + (t->pop/2) + " and " + (t->pop-1) - + " peasants, with wages from " + t->wages + " to " + (t->wages+2) + " silver. You may find "; - int comma = 0; - int last = -1; - for(unsigned int i=0; iraces)/sizeof(int); i++) { - if(t->races[i] != -1) { - if(last != -1) { - if(comma) *temp += ", "; - *temp += ItemDefs[last].names; - comma = 1; - } - last = t->races[i]; - } - } - if(last != -1) { - if(comma) *temp += " or "; - *temp += ItemDefs[last].names; - } - *temp += " here, as well as "; - comma = 0; - last = -1; - for(unsigned int i=0; icoastal_races)/sizeof(int); i++) { - if(t->coastal_races[i] != -1) { - if(last != -1) { - if(comma) *temp += ", "; - *temp += ItemDefs[last].names; - comma = 1; - } - last = t->coastal_races[i]; - } - } - if(last != -1) { - if(comma) *temp += " or "; - *temp += ItemDefs[last].names; - } - *temp += " if the region is adjacent to an ocean, lake or river."; - } - else *temp += " No peasants live in this terrain."; - - *temp += " This terrain will always produce "; - int comma = 0; - int last = -1; - if(t->economy) { - *temp += AString(t->economy) + "-" + (2*t->economy-1) + " livestock or grain"; - comma = 1; - } - for(unsigned int i=0; iprods)/sizeof(Product); i++) { - if(t->prods[i].product != -1 && t->prods[i].chance >= 100) { - if(last != -1) { - if(comma) *temp += ", "; - *temp += AString(t->prods[last].amount) + "-" + (2*t->prods[last].amount-1) + " " + ItemDefs[t->prods[last].product].names; - comma = 1; - } - last = i; - } - } - if(last != -1) { - if(comma) *temp += " and "; - *temp += AString(t->prods[last].amount) + "-" + (2*t->prods[last].amount-1) + " " + ItemDefs[t->prods[last].product].names; - } - *temp += ", and may also produce "; - comma = 0; - last = -1; - for(unsigned int i=0; iprods)/sizeof(Product); i++) { - if(t->prods[i].product != -1 && t->prods[i].chance < 100) { - if(last != -1) { - if(comma) *temp += ", "; - *temp += AString(t->prods[last].amount) + "-" + (2*t->prods[last].amount-1) + " " + ItemDefs[t->prods[last].product].names; - comma = 1; - } - last = i; - } - } - if(last != -1) { - if(comma) *temp += " and "; - *temp += AString(t->prods[last].amount) + "-" + (2*t->prods[last].amount-1) + " " + ItemDefs[t->prods[last].product].names; - } - *temp += "."; - return temp; -} - -int ARegion::GetEthnicity() -{ - if(race < 0) return RA_NA; - ManType *mt = FindRace(ItemDefs[race].abr); - if(!mt) return RA_NA; - return mt->ethnicity; -} diff --git a/arcadia/aregion.h b/arcadia/aregion.h deleted file mode 100644 index 37c408ff2..000000000 --- a/arcadia/aregion.h +++ /dev/null @@ -1,550 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2000/MAR/16 Davis Kulis Added a new reporting Template. -// 2000/MAR/21 Azthar Septragen Added roads. -#ifndef REGION_CLASS -#define REGION_CLASS - -class ARegion; -class ARegionList; - -#include "gamedefs.h" -#include "gameio.h" -#include "faction.h" -#include "alist.h" -#include "unit.h" -#include "fileio.h" -#include "production.h" -#include "market.h" -#include "object.h" -#include - -/* Weather Types */ -enum { - W_NORMAL, - W_WINTER, - W_MONSOON, - W_BLIZZARD -}; - -enum { - FL_NULL, - FL_UNUSED_START_LOC, - FL_USED_START_LOC -}; - -struct Product -{ - int product; - int chance; - int amount; -}; - -class TerrainType -{ - public: - char *name; - char *type; - char marker; - int similar_type; - - enum { - RIDINGMOUNTS = 0x01, - FLYINGMOUNTS = 0x02, - RIDINGLIMITED = 0x04, - FLYINGLIMITED = 0x08, - RESTRICTEDFOOT = 0x10, - RESTRICTEDRANGED = 0x20, - ENHANCEDRANGED = 0x40, //mutually exclusive with RESTRICTEDRANGED (if both are used, ENHANCEDRANGE will have no effect - DISABLED = 0x80, //currently used only in genrules. - }; - int flags; - - int pop; - int wages; - int economy; - int movepoints; - Product prods[7]; - // Race information - // A hex near water will have either one of the normal races or one - // of the coastal races in it. Non-coastal hexes will only have one - // of the normal races. - int races[4]; - int coastal_races[3]; - int wmonfreq; - int smallmon; - int bigmon; - int humanoid; - int lairChance; - int lairs[6]; -}; - -extern TerrainType *TerrainDefs; - -AString *TerrainDescription(int type); - -class Location : public AListElem -{ - public: - Unit *unit; - Object *obj; - ARegion *region; -}; - -Location *GetUnit(AList *, int); - -int AGetName(int town); -char *AGetNameString(int name); - -class ARegionPtr : public AListElem -{ - public: - ARegion *ptr; -}; - -ARegionPtr *GetRegion(AList *, int); - -class Farsight : public AListElem -{ - public: - Farsight(); - - Faction *faction; - Unit *unit; - int level; - int exits_used[NDIRS]; -}; - -Farsight *GetFarsight(AList *, Faction *); - -enum { - TOWN_VILLAGE, - TOWN_TOWN, - TOWN_CITY, - NTOWNS -}; - -AString TownString(int i); - -class TownInfo -{ - public: - TownInfo(); - ~TownInfo(); - - void Readin(Ainfile *, ATL_VER &); - void Writeout(Aoutfile *); - int TownType(); - - AString *name; - int pop; - int basepop; - int activity; - - // Player-Econ stuff - int growth; - int mortality; -}; - -class ARegionArray; - -class ARegion : public AListElem -{ - friend class Game; - friend class ARegionArray; - - public: - ARegion(); - ARegion(int, int); - ~ARegion(); - void Setup(); - - void ZeroNeighbors(); - void SetName(char *); - - void Writeout(Aoutfile *); - void Readin(Ainfile *, AList *, ATL_VER v); - - int CanMakeAdv(Faction *, int); - int HasItem(Faction *, int); - void WriteProducts(Areport *, Faction *, int); - void WriteMarkets(Areport *, Faction *, int); - void WriteEconomy(Areport *, Faction *, int); - void WriteExits(Areport *, ARegionList *pRegs, int *exits_seen); - void WriteReport(Areport *f, Faction *fac, int month, - ARegionList *pRegions); - // DK - void WriteTemplate(Areport *, Faction *, ARegionList *, int); - void WriteTemplateHeader(Areport *, Faction *, ARegionList *, int); - void GetMapLine(char *, int, ARegionList *); - - AString ShortPrint(ARegionList *pRegs); - AString Print(ARegionList *pRegs); - - void Kill(Unit *); - void ClearHell(); - - Unit *GetUnit(int); - Unit *GetUnitAlias(int, int); /* alias, faction number */ - Unit *GetUnitId(UnitId *, int); - Location *GetLocation(UnitId *, int); - - void SetLoc(int, int, int); - int Present(Faction *); - AList *PresentFactions(); - int GetObservation(Faction *, int); - int GetTrueSight(Faction *, int); - - Object *GetObject(int); - Object *GetDummy(); - - int MoveCost(int, ARegion *, int, AString *road); - Unit *Forbidden(Unit *); /* Returns unit that is forbidding */ - Unit *ForbiddenByAlly(Unit *); /* Returns unit that is forbidding */ - int CanTax(Unit *); - int CanPillage(Unit *); - int ForbiddenShip(Object *); - int HasCityGuard(); - int NotifySpell(Unit *, char *, ARegionList *pRegs); - void NotifyCity(Unit *, AString& oldname, AString& newname); - - void DefaultOrders(int peasantfac); - void UpdateTown(); - void PostTurn(ARegionList *pRegs); - void UpdateProducts(); - void SetWeather(int newWeather); - int IsCoastal(); - int IsCoastalOrLakeside(); - void MakeStartingCity(); - int IsStartingCity(); - int IsSafeRegion(); - int CanBeStartingCity(ARegionArray *pRA); - int HasShaft(); - - // AS - int HasRoad(); - int HasExitRoad(int realDirection); - int CountConnectingRoads(); - int HasConnectingRoad(int realDirection); - int GetRoadDirection(int realDirection); - int GetRealDirComp(int realDirection); - void DoDecayCheck(ARegionList *pRegs); - void DoDecayClicks(Object *o, ARegionList *pRegs); - void RunDecayEvent(Object *o, ARegionList *pRegs); - AString GetDecayFlavor(); - int GetMaxClicks(); - int PillageCheck(); - - // JR - int GetPoleDistance(int dir); - void SetGateStatus(int month); - void DisbandInRegion(int, int); - void Recruit(int); - int IsNativeRace(int); - void AdjustPop(int); - void Migrate(); - void CheckTownIncrease(); - int TraceConnectedRoad(int, int, AList *, int); - int CountRoadConnectedTowns(int); - int TownHabitat(); - int Development(); - int TownDevelopment(); - int CheckSea(int, int, int); - int Slope(); - int SurfaceWater(); - int Soil(); - int Winds(); - int TerrainFactor(int, int); - int TerrainProbability(int); - - int CountWMons(); - int IsGuarded(); - - int Wages(); - int LakeEffect(); - AString WagesForReport(); - int Population(); - - AString *name; - int num; - int type; - int buildingseq; - int weather; - int gate; - int gatemonth; - int gateopen; - int willsink; //number of turns until the region will sink (decreased at end of runorders). This should be set to 0 (will never sink) or a positive number. Negative numbers should be ok, but I make no promises! - int untaxed; //amount of silver NOT taxed (used in guard regeneration). - void SinkRegion(ARegionList *pRegs); - void OceanToLand(); - void Fake(); - void SetEthnicity(int ethnicity, ARegionList *pRegs); - int GetEthnicity(); - void RedoAs(int tertype, int town, ARegionList *pRegs); - void Event(const AString &); - AList events; - - TownInfo *town; - int race; - int population; - int basepopulation; - int migration; - int wages; - int maxwages; - int money; - - /* Player-run economy */ - int habitat; - int development; - int growth; - int mortality; - int elevation; - int humidity; - int temperature; - int vegetation; - int culture; - - /* Potential bonuses to economy */ - int clearskies; - int earthlore; - /* Potential malus */ - int fog; - - ARegion *neighbors[NDIRS]; - Hexside *hexside[NDIRS]; - AList objects; - AList hell; /* Where dead units go */ - AList farsees; - // List of units which passed through the region - AList passers; - ProductionList products; - MarketList markets; - int xloc, yloc, zloc; - - int dynamicexits; //are the exits to this region the same for every unit present? Usually ... yes - - void AddEditTown(AString * = 0); - void UpdateEditRegion(); - void SetupEditRegion(int canmakecity = 1); - void EditAdjustAreaName(AString name); -// int GetArcadianTradeAveraged(int numtrade, int producing); - int GetArcadianTrade(int numtrade, int producing); - int marker; //temporary variable you can use for eg marking regions visited during a routine. Clear before using. - int flagpole; //variable, needs to be saved with region. Used in Arcadia for triggering region-specific events. - int timesmarker; //variable for times events. - - private: - /* Private Setup Functions */ - void SetupPop(); - void SetupProds(); - int GetNearestProd(int); - void SetupCityMarket(); - void AddTown(); - void MakeLair(int); - void LairCheck(); - - void WagesFromDevelopment(); -}; - -class ARegionArray -{ - public: - ARegionArray(int, int); - ~ARegionArray(); - - void SetRegion(int, int, ARegion *); - ARegion *GetRegion(int, int); - void SetName(char *name); - - int x; - int y; - ARegion **regions; - AString *strName; - - enum { - LEVEL_NEXUS, - LEVEL_SURFACE, - LEVEL_UNDERWORLD, - LEVEL_UNDERDEEP, - LEVEL_QUEST, - }; - int levelType; -}; - -class ARegionFlatArray -{ - public: - ARegionFlatArray(int); - ~ARegionFlatArray(); - - void SetRegion(int, ARegion *); - ARegion *GetRegion(int); - - int size; - ARegion **regions; -}; - -struct Geography -{ - int elevation; - int humidity; - int temperature; - int vegetation; - int culture; -}; - -class GeoMap -{ - public: - GeoMap(int, int); - void Generate(int spread, int smoothness); - int GetElevation(int, int); - int GetHumidity(int, int); - int GetTemperature(int, int); - int GetVegetation(int, int); - int GetCulture(int, int); - void ApplyGeography(ARegionArray *pArr); - - int size, xscale, yscale, xoff, yoff; - map geomap; - -}; - -class ARegionList : public AList -{ - public: - ARegionList(); - ~ARegionList(); - - ARegion *GetRegion(int); - ARegion *GetRegion(int, int, int); - int ReadRegions(Ainfile *f, AList *, ATL_VER v); - void WriteRegions(Aoutfile *f); - Location *FindUnit(int); - Location *GetUnitId(UnitId *id, int faction, ARegion *cur); - - void ChangeStartingCity(ARegion *, int); - ARegion *GetStartingCity(ARegion *AC, int num, int level, int maxX, - int maxY); - - ARegion *FindGate(int); - int GetDistance(ARegion *, ARegion *); - int GetPlanarDistance(ARegion *, ARegion *, int penalty); - int GetWeather(ARegion *pReg, int month); - - ARegionArray *GetRegionArray(int level); - - int numberofgates; - int numLevels; - ARegionArray **pRegionArrays; - - public: - // - // Public world creation stuff - // - void CreateLevels(int numLevels); - void CreateAbyssLevel(int level, char *name); - void CreateNexusLevel(int level, int xSize, int ySize, char *name); - void CreateSurfaceLevel(int level, int xSize, int ySize, char *name); - void CreateIslandLevel(int level, int nPlayers, char *name); - void CreateUnderworldLevel(int level, int xSize, int ySize, char *name); - void CreateUnderdeepLevel(int level, int xSize, int ySize, char *name); - void AddQuestLevel(int xSize, int ySize, char *name, int type); - - void MakeShaftLinks(int levelFrom, int levelTo, int odds); - void SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY); - void InitSetupGates(int level); - void FinalSetupGates(); - - // JR - void InitGeographicMap(ARegionArray *pRegs); - void CleanUpWater(ARegionArray *pRegs); - void RemoveCoastalLakes(ARegionArray *pRegs); - void SeverLandBridges(ARegionArray *pRegs); - void AddBeaches(ARegionArray *pRegs); - void AddRivers(ARegionArray *pRegs); - int WaterDistance(ARegion *reg); - void ClearRiverNums(ARegionArray *pRegs); - int AddRiverSegment(ARegion *reg,int hexside,int rivernum, int tries); - void CreateRiverSegment(ARegion *reg, int hexside, int rivernum); - void DeleteRiverSegment(ARegion *reg, int hexside); - void RescaleFractalParameters(ARegionArray *pArr); - void SetFractalTerrain(ARegionArray *pArr); - void NameRegions(ARegionArray *pArr); - void UnsetRace(ARegionArray *pRegs); - void RaceAnchors(ARegionArray *pRegs); - void GrowRaces(ARegionArray *pRegs); - - void CalcDensities(); - int GetLevelXScale(int level); - int GetLevelYScale(int level); - - void EditNeighSetup(ARegion *r, ARegionArray *ar); //calls the private neighsetup function for the game editor - - private: - // - // Private world creation stuff - // - void MakeRegions(int level, int xSize, int ySize); - void SetupNeighbors(ARegionArray *pRegs); - void AddHexsides(ARegionArray *pRegs); - void MakeIcosahedralRegions(int level, int xSize, int ySize); - void SetupIcosahedralNeighbors(ARegionArray *pRegs); - void NeighSetup(ARegion *r, ARegionArray *ar); - void IcosahedralNeighSetup(ARegion *r, ARegionArray *ar); - - void SetRegTypes(ARegionArray *pRegs, int newType); - void MakeLand(ARegionArray *pRegs, int percentOcean, int continentSize); - void MakeCentralLand(ARegionArray *pRegs); - - void SetupAnchors(ARegionArray *pArr); - void GrowTerrain(ARegionArray *pArr, int growOcean); - void RandomTerrain(ARegionArray *pArr); - void MakeUWMaze(ARegionArray *pArr); - void MakeIslands(ARegionArray *pArr, int nPlayers); - void MakeOneIsland(ARegionArray *pRegs, int xx, int yy); - - void AssignTypes(ARegionArray *pArr); - void FinalSetup(ARegionArray *); - - void MakeShaft(ARegion *reg, ARegionArray *pFrom, ARegionArray *pTo); - - // - // Game-specific world stuff (see world.cpp) - // - int GetRegType(ARegion *pReg); - int CheckRegionExit(ARegion *pFrom, ARegion *pTo); - - void CheckHexsides(ARegionArray *pArr); - -}; - -int LookupRegionType(AString *); -int ParseTerrain(AString *); - -#endif diff --git a/arcadia/army1.cpp b/arcadia/army1.cpp deleted file mode 100644 index d87718531..000000000 --- a/arcadia/army1.cpp +++ /dev/null @@ -1,2580 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef DEBUG -//#define DEBUG -#endif - -#ifndef DEBUG2 -//#define DEBUG2 -#endif - -#include "army1.h" -#include "gameio.h" -#include "gamedata.h" - - -Army::Army(Unit * ldr,AList * locs,int regtype,int ass) -{ -#ifdef DEBUG -Awrite("Making an army"); -#endif - Unit * tactician = ldr; - - round = 0; - tac = ldr->GetAttribute("seniority"); - count = 0; - hitstotal = 0; - sortedformations = 0; // Formations get sorted in first battle round after fog/darkness is cast. - concealment = 0; - nonillusioncount = 0; - canride = (TerrainDefs[regtype].flags & TerrainType::RIDINGMOUNTS); - - if(TerrainDefs[regtype].flags & TerrainType::RESTRICTEDRANGED) { - rangedbonus = -1; - } else if(TerrainDefs[regtype].flags & TerrainType::ENHANCEDRANGED) { - rangedbonus = 1; - } else rangedbonus = 0; - - - if (ass) { - count = 1; - nonillusioncount = 1; - ldr->losses = 0; - pLeader = ldr; - } else { - forlist(locs) { - Unit * u = ((Location *) elem)->unit; - count += u->GetSoldiers(); - nonillusioncount += u->GetRealSoldiers(); - u->losses = 0; - int temp = u->GetSeniority(); - if (temp > tac) { - tac = temp; - tactician = u; - } - } - pLeader = tactician; - } - - taccontrol = 100; - - // If TACTICS_NEEDS_WAR is enabled, we don't want to push leaders - // from tact-4 to tact-5! Also check that we have skills, otherwise - // we get a nasty core dump ;) - if(!(SkillDefs[S_TACTICS].flags & SkillType::DISABLED)) { - if (Globals->TACTICS_NEEDS_WAR && (tactician->skills.Num() != 0)) { - int currskill = tactician->skills.GetDays(S_TACTICS)/tactician->GetMen(); - if (currskill < 450 - Globals->SKILL_PRACTICE_AMOUNT) { - tactician->PracticeAttribute("tactics"); - } - } else { // Only Globals->TACTICS_NEEDS_WAR == 0 - tactician->PracticeAttribute("tactics"); - } - } - // This looks wrong, but isn't, as the (NUMFORMS+1)th formation contains all the dead soldiers. - for(int i=0; iunit; - Object * obj = ((Location *) elem)->obj; -#ifdef DEBUG2 -cout << *u->name << endl; -#endif - if (ass) { - forlist(&u->items) { - Item * it = (Item *) elem; - if (it) { - if(ItemDefs[ it->type ].type & IT_MAN) { - Soldier *temp = new Soldier(u, obj, regtype, - it->type, ass); - formations[0].AddSoldier(temp); - hitstotal = temp->hits; //used only for rout conditions - temp = 0; - ++x; - goto finished_army; - - } - } - } - } else { - Item *it = (Item *) u->items.First(); - do { - if(IsSoldier(it->type)) { -#ifdef DEBUG2 -cout << ItemDefs[it->type].abr; -#endif - for(int i = 0; i < it->num; i++) { -#ifdef DEBUG2 -cout << "."; -#endif - Soldier *temp = new Soldier(u, obj, regtype, - it->type); -#ifdef DEBUG2 -cout << "|"; -#endif - formations[0].AddSoldier(temp); - if(!temp->illusion) hitstotal += temp->hits; //used only for rout conditions, hence does not include illusions - temp = 0; - ++x; - } - } - it = (Item *) u->items.Next(it); - } while(it); - } - } - -finished_army: -Awrite("Finished Army Construction"); -} - -Army::~Army() -{ - #ifdef DEBUG - Awrite("Army Destructor"); - #endif -} - -int Army::NumAlive() -{ - int numalive = count - formations[NUMFORMS].GetNumMen(); - #ifdef DEBUG - if(numalive < 0) { - Awrite("negative living soldiers!"); - system("pause"); - } - #endif - return numalive; -} - -int Army::NumNonIllusionsAlive() -{ - int na = NumAlive(); - int numalive = 0; - - for(int i=0; i < na; i++) { - const Soldier *pSold = GetSoldier(i); - if(!pSold->illusion) numalive++; - } - - return numalive; -} - -Soldier * Army::GetSoldier(int soldiernum) const -//This should use an input number from 0 to count. Use caution - it may return a dead soldier -//(this needs to be able to as it gets used in the post-battle routines). -{ - for(int i=0; i= formations[i].GetNumMen()) soldiernum -= formations[i].GetNumMen(); - else return formations[i].GetSoldier(soldiernum); - } - Awrite("Invalid Soldier"); - return 0; -} - -int Army::Broken() -{ - if(Globals->ARMY_ROUT == GameDefs::ARMY_ROUT_FIGURES) { - if(NumAlive() * 2 < count) return 1; - } else { //one of the gamedef options effectively disabled here - int hitsalive = 0; - for(int i=0; i= formations[i].CanAttack()) attackernum -= formations[i].CanAttack(); - else return formations[i].GetAttacker(attackernum); - } - Awrite("Invalid Attacker"); - return 0; -} - -int Army::GetTarget(Army *attackers, int attackerform, int attackType, int *targetform, char* special, Battle *b) -//this sequence gets an enemy soldier to attack. -//"this" is the army of the defending unit. -{ - int tarnum = -1; - #ifdef DEBUG2 - cout << "getting new target"; - #endif - - SpecialType *sp = FindSpecial(special); - if (sp && sp->targflags) { - #ifdef DEBUG2 - cout << " special attack" << endl; - #endif - //this is a special which only hits certain people (other specials, which hit anyone, - //are dealt with as normal attacks) - int validtargs = 0; - if(attackers != this) { //ie attacking enemy, so check formation stuff. - // Search Engaged Formations - for(int i=0; iengagements[attackerform][i] == ENGAGED_ENGAGED) { - for(int j=0; jengagements[attackerform][i] == ENGAGED_ENGAGED) { - for(int j=0; jengagements[attackerform][i] == ENGAGED_TRYATTACK) { - for(int j=0; jengagements[attackerform][i] == ENGAGED_TRYATTACK) { - for(int j=0; jengagements[attackerform][i] == ENGAGED_ENGAGED) { - engaged = 1; - tars += formations[i].GetNumMen(); - } - } - if(tars) { - tarnum = getrandom(tars); - for(int i=0; iengagements[attackerform][i] == ENGAGED_ENGAGED) { - if(tarnum >= formations[i].GetNumMen() ) tarnum -= formations[i].GetNumMen(); - else { - *targetform = i; - return tarnum; - } - } - } - } else if(engaged) { - //engaged with an empty formation. Clear the engagement. - for(int i=0; iengagements[attackerform][i] = ENGAGED_NONE; - } - } - //if this soldier is melee, see if we can engage a new enemy formation. - //if we are behind 1 this will return with no target. - if(attackType == ATTACK_COMBAT || attackType == ATTACK_RIDING) { - int newtarget = attackers->GetMidRoundTarget(attackerform,this, b); - #ifdef DEBUG - cout << "New target: " << newtarget << endl; - #endif - - if(newtarget > -1) { - if(formations[newtarget].GetNumMen()) { - *targetform = newtarget; - tars = formations[newtarget].GetNumMen(); - return getrandom(tars); - } else { - //we shouldn't really get to here :( - #ifdef DEBUG - cout << "New target is empty" << endl; - system("pause"); - #endif - return -1; - } - } - //this is a melee soldier and we could not engage a target (perhaps we are behind). - //Return with no target. - return newtarget; //this is either -1 (no target found) or -2 (soldier has been moved out). Either way, quit the attack sequence. - - //The order here could be changed to make GetMidRoundTarget only called if deleting old - //engagements - } - - //This soldier is ranged, and not engaged with anyone. It wants to hit someone it - //is trying to attack. - tars = 0; //just in case - engaged = 0; - for(int i=0; iengagements[attackerform][i] == ENGAGED_TRYATTACK) { - engaged = 1; - tars += formations[i].GetNumMen(); - } - } - if(tars) { - tarnum = getrandom(tars); - for(int i=0; iengagements[attackerform][i] == ENGAGED_TRYATTACK) { - if(tarnum >= formations[i].GetNumMen() ) tarnum -= formations[i].GetNumMen(); - else { - *targetform = i; - return tarnum; - } - } - } - } else if(engaged) { - //tryattacking empty formations only. Clear engagements with empty enemy formations. - for(int i=0; iengagements[attackerform][i] = ENGAGED_NONE; - } - //our old tryattack targets are empty. Get new ones. If we are a behind 0 formation will get none. - int newtarget = attackers->GetMidRoundRangedTarget(attackerform,this); - if(newtarget>-1 && formations[newtarget].GetNumMen()) { - *targetform = newtarget; - tars = formations[newtarget].GetNumMen(); - return getrandom(tars); - } - - } - - //This soldier is ranged, and has no-one it wants to attack. As a last resort, - //hit a random enemy. This will only be called when we are down to enemy reserves & behind formations - tars = NumAlive(); - tarnum = getrandom(tars); - for(int i=0; i= formations[i].GetNumMen() ) tarnum -= formations[i].GetNumMen(); - else { - *targetform = i; - return tarnum; - } - } - } else { - //hitting one's own army. Get a random soldier. - tarnum = getrandom( NumAlive() ); - for(int i=0; i= formations[i].GetNumMen() ) tarnum -= formations[i].GetNumMen(); - else { - *targetform = i; - return tarnum; - } - } - } - #ifdef DEBUG - Awrite("Fell through Target Selection"); - #endif - return -1; // This should never get called - unless perhaps a multi-attack soldiers kills the last enemy? -} - -//needed for DoAnAttack below. -int pow(int b,int p) -{ - int b2 = b; - for(int i=1; id) { - tohit = pow(2,a-d); - } else if (d>a) { - tomiss = pow(2,d-a); - } - if (getrandom(tohit+tomiss) < tohit) return 1; - return 0; -} - -int Army::DoAnAttack(char *special, int numAttacks, int race, int attackType, int attackLev, - int flags, int weaponClass, char *effect, int mountBonus, Army *attackers, int attackerform, Battle *b, int strength) - /* The army in question is the army DEFENDING! - */ - -{ -#ifdef DEBUG2 -cout << "doing an attack" << endl; -#endif - /* 1. Check against Global effects (not sure how yet). BS: What does this even mean? */ - - /* 2. Attack shield */ - Shield *hi; - int combat = 0; - int canShield = 0; - switch(attackType) { - case ATTACK_RANGED: - canShield = 1; - // fall through - case ATTACK_COMBAT: - case ATTACK_RIDING: - combat = 1; - break; - case ATTACK_ENERGY: - case ATTACK_WEATHER: - case ATTACK_SPIRIT: - canShield = 1; - break; - } - if(canShield) { - int shieldType = attackType; - - hi = shields.GetHighShield(shieldType); - if (hi) { -#ifdef DEBUG -cout << "Passing shield strength " << hi->shieldskill << endl; -b->AddLine(AString("Testing shield strength ") + hi->shieldskill); -#endif - /* Check if we get through shield */ - if(!Hits(attackLev, hi->shieldskill)) { - return -1; - } -#ifdef DEBUG -b->AddLine("Through"); -#endif - if(effect == NULL && !combat) { - /* We got through shield... if killing spell, downgrade shield */ - DowngradeShield(hi); - } - if(combat && !getrandom(80/numAttacks) ) { - /* Damaging shot, downgrade shield */ - DowngradeShield(hi); -#ifdef DEBUG -b->AddLine(AString("Damaged Shield ") + hi->shieldskill); -#endif - } - } - } - - // Now, loop through and do attacks - // - int ret = 0; //number of successful attacks! - for(int i = 0; i < numAttacks; i++) { - //initialise variables - int attackLevel = attackLev; - - - /* 3. Get the target */ - int formhit = -1; - int tarnum = GetTarget(attackers,attackerform,attackType,&formhit, special, b); - if(tarnum<0) return ret; //This is needed whenever no target is found - //(all enemies dead, or no valid target for that attacker, - //or that attacker moved to a new formation). - - #ifdef DEBUG - if(formhit<0) { - cout << "Invalid target formation! " << formhit << " with tarnum " << tarnum << endl; - system("pause"); - return ret; - } - #endif - - Soldier *tar = formations[formhit].GetSoldier(tarnum); - - #ifdef DEBUG - if(!tar) { - Awrite("Invalid target!"); - system("pause"); - return ret; - } - #endif - - int tarFlags = 0; - if(tar->weapon != -1) { - WeaponType *pw = FindWeapon(ItemDefs[tar->weapon].abr); - tarFlags = pw->flags; - } - - - /* 4. Add in any effects, if applicable */ - int tlev = 0; //target's defence skill - if(attackType != NUM_ATTACK_TYPES) - tlev = tar->dskill[ attackType ]; - if(special != NULL) { - SpecialType *sp = FindSpecial(special); - if((sp->effectflags & SpecialType::FX_NOBUILDING) && tar->building) - tlev -= 2; //this assumes building defence bonus is 2! Not always right. - } - - /* 4.1 Check whether defense is allowed against this weapon */ - if((flags & WeaponType::NODEFENSE) && (tlev > 0)) tlev = 0; - - if(!(flags & WeaponType::RANGED)) { - /* 4.2 Check relative weapon length */ - int attLen = 1; - int defLen = 1; - if(flags & WeaponType::LONG) attLen = 2; - else if(flags & WeaponType::SHORT) attLen = 0; - if(tarFlags & WeaponType::LONG) defLen = 2; - else if(tarFlags & WeaponType::SHORT) defLen = 0; - if(attLen > defLen) attackLevel++; - else if(defLen > attLen) tlev++; - - //Arcadia lines only: - if(attLen != 1 || defLen != 1) b->AddLine("Length weapon detected. Please contact your GM!"); //Arcadia only! - } - - //Check whether the formation has a combat bonus/penalty - //This also gives a bonus/penalty to %chance to attack below. - int attackbonus = 0; - attackbonus += attackers->formations[attackerform].bonus; - if((attackType != ATTACK_COMBAT) && (attackType != ATTACK_RIDING)) { - ManType *mt = FindRace(ItemDefs[race].abr); - if(attackers->rangedbonus < 0) { - //elves don't get ranged penalties //?for archers? - if(!mt || mt->ethnicity != RA_ELF /*|| attackType != ATTACK_RANGED*/) attackbonus += attackers->rangedbonus; - //non-elves only get ranged bonuses for magic - } else if( (mt && mt->ethnicity == RA_ELF) || attackType != ATTACK_RANGED) { - attackbonus += attackers->rangedbonus; //we know this bonus is >= 0 now! - } - } - - attackLevel += attackbonus; //adding here since protection values aren't supposed to be added - - /* 4.3 Add bonuses versus mounted */ - if(tar->riding != -1) attackLevel += mountBonus; // this and the previous line will mess up multi-attacks. - - /* 5. Attack soldier */ - if(!(flags & WeaponType::ALWAYSREADY)) { - if(Globals->ADVANCED_FORTS) { - attackbonus -= (tar->protection[attackType]+1)/2; - } - - //if bonus==0, 50%. if bonus = 1, 67%. if bonus = -1, 33% - //if bonus = 2, 75% - //getrandom(tohit+tofail) < tohit - //eg gr(2) < 1 = 50%. gr(3) < 1/2 = 33%/67% - - //this is to get a chance to attack, not the actual attack. - int tohit = 1+attackbonus; - int tomiss = 1-attackbonus; - if(tohit<1) tohit = 1; - if(tomiss<1) tomiss = 1; - if(getrandom(tohit+tomiss) < tomiss) { - continue; - } - } - -#ifdef DEBUG -b->AddLine(AString("TargetFac: ") + tar->unit->faction->num + " Attack: " + attackLevel + " Defence: " + tlev); -#endif - - if (attackType != NUM_ATTACK_TYPES) { //this excludes dispel illusions, anti-demons, etc. - if (!Hits(attackLevel,tlev)) { - continue; - } - } - /* 6. If attack got through, apply effect, or kill */ - if (effect == NULL) { - /* 7. Last chance... Check armor */ - if (tar->ArmorProtect(weaponClass)) { - continue; - } - //toughness gets a 1:level chance to dodge ranged/magic attacks: - if(attackType != ATTACK_COMBAT && attackType != ATTACK_RIDING && getrandom(tar->unit->GetSkill(S_TOUGHNESS)+1) ) { - continue; - } - - if((flags & WeaponType::RESTINPEACE) && strength >= tar->hits) { - //this soldier is going to die! - unless he has an amy of i in which case he'll never die anyway ... - tar->restinpeace = 1; - } -#ifdef DEBUG -b->AddLine(AString("Kill!")); -#endif - /* 8. Seeya! */ - formations[formhit].Kill(tarnum, this, strength); - ret++; - } else { - if (tar->HasEffect(effect)) { - continue; - } - tar->SetEffect(effect, formhit, this); - ret++; - } - } - return ret; -} - -void Army::AddLine(const AString & s) -{ - AString * temp = new AString(s); - armytext.Add(temp); -} - -void Army::WriteLosses(Battle * b) { - b->AddLine(*(pLeader->name) + " loses " + (count - NumAlive()) + "."); - b->casualties += count - NumAlive(); - - if (NumAlive() != count) { - AList units; - for (int i=NumAlive(); iunit)) { - UnitPtr *u = new UnitPtr; - u->ptr = GetSoldier(i)->unit; - units.Add(u); - } - } - - int comma = 0; - AString damaged; - forlist (&units) { - UnitPtr *u = (UnitPtr *) elem; - if (comma) { - damaged += AString(", ") + AString(u->ptr->num); - } else { - damaged = AString("Damaged units: ") + AString(u->ptr->num); - comma = 1; - } - } - - units.DeleteAll(); - b->AddLine(damaged + "."); - } -} - -int Army::Lose(Battle *b,ItemList *spoils, int ass) -//If speed is an issue, can create Formation::Lose/Tie/Win methods and not cycle through GetSoldier repeatedly. -{ - int numdead = 0; - DoExperience(); - WriteLosses(b); - if(ass && Globals->ARCADIA_MAGIC) AssassinationResurrect(); - for (int i=0; iisdead) { - s->Alive(LOSS); - } else { - if ((s->unit->type==U_WMON) && (ItemDefs[s->race].type&IT_MONSTER)) - GetMonSpoils(spoils,s->race,s->unit->free); - if(!s->illusion) numdead++; - s->Dead(); - } - delete s; - } - return numdead; -} - -void Army::Tie(Battle * b) -{ - DoExperience(); - WriteLosses(b); - for(int x=0; xisdead) { - if(round > 1) s->Alive(WIN_NO_MOVE); - else s->Alive(WIN_MOVE); //if only one round, can still move. - } else { - s->Dead(); - } - delete s; - } -} - -void Army::Win(Battle * b,ItemList * spoils, int enemydead) -{ - int wintype; - DoExperience(enemydead); - DoHeal(b, enemydead); - WriteLosses(b); - int na = NumNonIllusionsAlive(); - - if (nonillusioncount != na && round > 1) { - wintype = WIN_NO_MOVE; //if only one round OR no casualties, can still move! - b->AddLine(""); - b->AddLine("The victor's units are forbidden from further movement this month."); - } else { - wintype = WIN_MOVE; - b->AddLine(""); - b->AddLine("All surviving units remain able to move"); - } - -#ifdef DEBUG - if(nonillusioncount < na) { - b->AddLine("Problem with non-illusion count, please contact your GM"); - } -#endif - - - //Distribute the Spoils - na = NumAlive(); - AList units; - forlist(spoils) { - Item *i = (Item *) elem; - if(i && na) { - Unit *u; - UnitPtr *up; - - //reset marker for every new spoil - for(int x = 0; x < na; x++) { - GetSoldier(x)->unit->marker = 0; - } - - int numsol = 0; - - // Make a list of units who can get this type of spoil - for(int x = 0; x < na; x++) { - u = GetSoldier(x)->unit; - if(u->CanGetSpoil(i)) { - numsol++; //total number of soldiers collecting this spoil - if(!u->marker) { //this is the first time we've visited this unit; add it to the list - up = new UnitPtr; - up->ptr = u; - units.Add(up); - } - } - u->marker++; //marks number of spoil-claiming soldiers in the unit. - } - //first pass through, we are as fair as possible - - int numunits = units.Num(); - if(numunits > 0) { //we have some units claiming spoils - int initialnum = i->num; //initial number of spoils - - forlist(&units) { - up = (UnitPtr *)elem; - int num = up->ptr->marker * initialnum / numsol; //soldiers in unit * num items / total soldiers. Rounded down - int num2 = up->ptr->CanGetSpoil(i); //total number of spoil unit is allowed to take - if(num2 < num) num = num2; - up->ptr->items.SetNum(i->type, - up->ptr->items.GetNum(i->type) + num); - i->num -= num; - up->ptr->faction->DiscoverItem(i->type, 0, 1); - } - #ifdef DEBUG - if(i->num < 0) Awrite("Item distribution is whacked!"); - #endif - //i->num spoils remain to be divided. Some of the units may no longer be able to accept spoils - while((i->num > 0) && units.Num()) { - //We are no longer caring about being fair, just give the items away ok! - int luckyunit = getrandom(units.Num()); - up = (UnitPtr *)units.First(); - while(luckyunit > 0) { - up = (UnitPtr *)units.Next(up); - luckyunit--; - } - int num = up->ptr->CanGetSpoil(i); //total number of spoil unit is allowed to take - if(num > i->num) num = i->num; - up->ptr->items.SetNum(i->type, up->ptr->items.GetNum(i->type)+num); - i->num -= num; - up->ptr->faction->DiscoverItem(i->type, 0, 1); - units.Remove(up); //we have given up all it can take, so remove it from the list - } - //we have given away all we can :) - } - units.DeleteAll(); - } - } - - for(int x = 0; x < count; x++) { - Soldier * s = GetSoldier(x); - if (!s->isdead) s->Alive(wintype); - else s->Dead(); - delete s; - } -} - -int Army::CanBeHealed() -{ - for (int i=NumAlive(); icanbehealed) return 1; - } - return 0; -} - -void Army::DoHeal(Battle * b, int enemydead) -{ - // Do magical healing - for(int i = 6; i > 0; --i) - DoHealLevel(b, i, 0); - // Do Normal healing - DoHealLevel(b, 1, 1); - // Do resurrection - formations[NUMFORMS].ResetHeal(); //resets dead to be able to be healed again. - DoResurrect(b); - DoNecromancy(b, enemydead); -} - -void Army::DoHealLevel(Battle *b, int type, int useItems) -{ -//This is also cloned below as DoResurrectLevel() -//NB: There is no healing of illusions! - int rate = HealDefs[type].rate; - - for (int i=0; ihealtype <= 0) continue; - // This should be here.. Use the best healing first - if(s->healtype != type) continue; - if(!s->healing) continue; - if(useItems) { - if(s->healitem == -1) continue; - if (s->healitem != I_HEALPOTION) s->unit->Practice(S_HEALING); - } else { - if(s->healitem != -1) continue; - s->unit->Practice(S_MAGICAL_HEALING); - int mevent = s->unit->MysticEvent(); - if(mevent) { - b->AddLine( *(s->unit->name) + " tries to heal, but his spells fizzle."); - continue; - } - int max = ( 120 * s->unit->GetEnergy() )/ s->unit->GetCombatCost(S_MAGICAL_HEALING, 1); //cost is per 120 corpses - if(max < 1) continue; - if(max < s->healing) s->healing = max; - } - - while (s->healing) { - if (!CanBeHealed()) break; - int j = getrandom(count - NumAlive()) + NumAlive(); - Soldier * temp = GetSoldier(j); - if (temp->canbehealed) { //this scales as n*n so could take a long time! - s->healing--; - if (getrandom(100) < rate) { - healed++; - //return soldier to life! - temp->isdead = 0; - formations[NUMFORMS].TransferSoldier((j-NumAlive()), &formations[NUMFORMS-1]); - } else { - temp->canbehealed = 0; - failed++; - } - } - } - if(useItems == 0) { - //magical healing - int cost = s->unit->GetCombatCost(S_MAGICAL_HEALING, failed+healed); - cost = (cost+119)/120; - s->unit->energy -= cost; - int exper = (30*failed) / HealDefs[type].num; - if(exper > 15) exper = 15; - s->unit->Experience(S_MAGICAL_HEALING, exper); - } else if(s->healitem != I_HEALPOTION) s->unit->Experience(S_HEALING,healed+failed,0); - - b->AddLine(*(s->unit->name) + " heals " + healed + "."); - - } -} - -void Army::DoResurrect(Battle *b) -{ - //self-resurrection - int undead_return = 0; - - for (int i=NumAlive(); irace].type & IT_UNDEAD && - s->unit->type == U_MAGE && - getrandom(100) < Globals->MAGE_UNDEAD_INVINCIBLE && - !s->restinpeace) { - undead_return++; - s->isdead = 0; - formations[NUMFORMS].TransferSoldier((i-NumAlive()), &formations[NUMFORMS-1]); - } - if(s->unit->type == U_MAGE && (ItemDefs[s->race].type & IT_MAN) && s->unit->GetSkill(S_RESURRECTION) >= 5 && - s->unit->GetEnergy() >= s->unit->GetCastCost(S_RESURRECTION, 4)) { - //unit can resurrect himself. - s->unit->resurrects++; - int mevent = s->unit->MysticEvent(); - if(mevent) { - s->unit->resurrects++; - s->unit->Event("Rises from the dead, but chaotic spirits exact twice the usual cost."); - } else s->unit->Event("Rises from the dead."); - s->unit->energy -= s->unit->GetEnergy(); //resurrected mage is exhausted. - s->isdead = 0; - formations[NUMFORMS].TransferSoldier((i-NumAlive()), &formations[NUMFORMS-1]); - } - } - - if(undead_return) { - b->AddLine(AString(undead_return) + " slain undead come back to life."); - } - - //resurrection of others. NB no resurrection of illusions. - int rate = 50; - - for (int i=0; iunit->type != U_MAGE || !(ItemDefs[s->race].type & IT_MAN)) continue; - int level = s->unit->GetSkill(S_RESURRECTION); - if(!level) continue; - int mevent = s->unit->MysticEvent(); - if(mevent) { - b->AddLine( *(s->unit->name) + " tries to resurrect, but the spell fizzles."); - continue; - } - - int max = 4 * level * level; // 4 at level 1, 144 at level 6 - int max2 = ( 3 * s->unit->GetEnergy() )/ s->unit->GetCombatCost(S_RESURRECTION, 1); //cost is per 3 corpses - if(max2 < max) max = max2; - s->unit->Practice(S_RESURRECTION); - - while (max) { - if (!CanBeHealed()) break; - int j = getrandom(count - NumAlive()) + NumAlive(); - Soldier * temp = GetSoldier(j); - if (temp->canbehealed) { - max--; - if (getrandom(100) < rate) { - raised++; - //return soldier to life! - temp->isdead = 0; - formations[NUMFORMS].TransferSoldier((j-NumAlive()), &formations[NUMFORMS-1]); - if(temp->unit->type == U_MAGE) { - temp->unit->resurrects++; - temp->unit->energy -= temp->unit->GetEnergy(); //resurrected mages are exhausted - } - } else { - temp->canbehealed = 0; - failed++; - } - } - } - - int cost = s->unit->GetCombatCost(S_RESURRECTION, failed+raised); - cost = (cost+2)/3; - s->unit->energy -= cost; - - if(raised) b->AddLine(*(s->unit->name) + " resurrects " + raised + "."); - int exper = (failed*40)/(4*level*level); - if(exper>20) exper = 20; - s->unit->Experience(S_RESURRECTION,exper,0); - } -} - -void Army::AssassinationResurrect() -{ - Soldier * s = GetSoldier(0); //assassination target - //check if the soldier can resurrect himself (soldier is always a man, not a creature belonging to a mage) - if(s->unit->type == U_MAGE && s->unit->GetSkill(S_RESURRECTION) >= 5 && - s->unit->GetEnergy() >= s->unit->GetCastCost(S_RESURRECTION, 4)) { - //unit can resurrect himself. - s->unit->resurrects++; - int mevent = s->unit->MysticEvent(); - if(mevent) { - s->unit->resurrects++; - s->unit->Event("Rises from the dead, but chaotic spirits exact twice the usual cost."); - } else s->unit->Event("Rises from the dead."); - s->unit->energy -= s->unit->GetEnergy(); //resurrected mage is exhausted. - s->isdead = 0; - formations[NUMFORMS].TransferSoldier(0, &formations[NUMFORMS-1]); - } - - - ARegion *reg = s->unit->object->region; - Unit * bestmage = 0; - int skill = 0; - forlist(®->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if(u->type != U_MAGE) continue; - if(u->faction->GetAttitude(s->unit->faction->num) < A_ALLY) continue; - int reskill = u->GetSkill(S_RESURRECTION); - if(reskill < 3) continue; //needs at least level 3. - if(reskill > skill) { - if(u->GetEnergy() >= u->GetCastCost(S_RESURRECTION, 1) ) { //note use cast cost here, and combat cost for normal battles above. - skill = reskill; - bestmage = u; - } - } - } - } - if(!bestmage) return; - bestmage->energy -= bestmage->GetCastCost(S_RESURRECTION, 1); - int mevent = bestmage->MysticEvent(); - if(mevent) { - bestmage->Event("Tries to resurrect assassination target, but the spell fizzles."); - return; - } - int savechance = 15*skill; - if(getrandom(100) > savechance) { - bestmage->Event("Tries to resurrect assassination target, but is unsuccessful."); - return; - } - bestmage->Event(AString("Resurrects ") + *(s->unit->name)); - s->unit->Event(AString("Is resurrected by ") + *(bestmage->name)); - if(s->unit->type == U_MAGE) { - s->unit->resurrects++; - s->unit->energy -= s->unit->GetEnergy(); - } - s->isdead = 0; - formations[NUMFORMS].TransferSoldier(0, &formations[NUMFORMS-1]); -} - -void Army::DoNecromancy(Battle *b, int enemydead) -{ -//NB: There is no necromancy on illusions! - int deadmen = enemydead; - for(int i = NumAlive(); i < count; i++) { - Soldier * temp = GetSoldier(i); - if(!temp->illusion) deadmen++; - } - for(int l = 6; l > 0; --l) { - int rate = 30 + 10*l; - if(!deadmen) break; - for (int i=0; iunit->type != U_MAGE || !(ItemDefs[s->race].type & IT_MAN)) continue; - int max = s->unit->GetSkill(S_NECROMANCY); - if(max != l) continue; - int mevent = s->unit->MysticEvent(); - if(mevent) { - b->AddLine( *(s->unit->name) + " tries to raise skeletons, but the spell fizzles."); - continue; - } - - max = ( 120 * s->unit->GetEnergy() )/ s->unit->GetCombatCost(S_NECROMANCY, 1); //cost of 120 corpses. - s->unit->Practice(S_NECROMANCY); - int raised = 0; - int failed = 0; - - while(max && deadmen) { - max--; - deadmen--; - if (getrandom(100) < rate) raised++; - else failed++; - } - - int cost = s->unit->GetCombatCost(S_NECROMANCY, failed+raised); - cost = (cost+119)/120; - s->unit->energy -= cost; - - //give n skeletons - s->unit->items.SetNum(I_SKELETON, s->unit->items.GetNum(I_SKELETON) + raised); - b->AddLine(*(s->unit->name) + " raises " + raised + " skeletons."); - - failed = (failed + 1)/2; - if(failed > 25) failed = 25; - s->unit->Experience(S_NECROMANCY,failed,0); - } - } -} - -void Army::Regenerate(Battle *b) -{ - for(int i=0; iMONSTER_NO_SPOILS > 0) && - (free >= Globals->MONSTER_SPOILS_RECOVERY)) { - // This monster is in it's period of absolutely no spoils. - return; - } - - /* First, silver */ - MonType *mp = FindMonster(ItemDefs[monitem].abr, - (ItemDefs[monitem].type & IT_ILLUSION)); - int silv = mp->silver; - if((Globals->MONSTER_NO_SPOILS > 0) && (free > 0)) { - // Adjust the spoils for length of freedom. - silv *= (Globals->MONSTER_SPOILS_RECOVERY-free); - silv /= Globals->MONSTER_SPOILS_RECOVERY; - } - spoils->SetNum(I_SILVER,spoils->GetNum(I_SILVER) + getrandom(silv)); - - int thespoil = mp->spoiltype; - - if (thespoil == -1) return; - if (thespoil == IT_NORMAL && getrandom(2) && silv >= 60) thespoil = IT_TRADE; //note that silver is a "normal" item, so can be generated here too! - // silv >= 60 used because otherwise no trade items are selected. - int count = 0; - int i; - for (i=0; isilver * 2); - if((Globals->MONSTER_NO_SPOILS > 0) && (free > 0)) { - // Adjust for length of monster freedom. - val *= (Globals->MONSTER_SPOILS_RECOVERY-free); - val /= Globals->MONSTER_SPOILS_RECOVERY; - } - - spoils->SetNum(thespoil,spoils->GetNum(thespoil) + - (val + getrandom(ItemDefs[thespoil].baseprice)) / - ItemDefs[thespoil].baseprice); - //The above gives val/baseprice + rand(0,1), rounded down. This makes sense in all situations I can think of. -} - -void Army::CombineEngagements(int formfrom, int formto, Army *enemy) -//This should be called after moving soldiers from formfrom to formto during a battle. -{ - for(int i=0; i engagements[formto][i] ) engagements[formto][i] = engagements[formfrom][i]; - if( enemy->engagements[i][formfrom] > engagements[i][formto] ) engagements[i][formto] = engagements[i][formfrom]; - //if old one is empty, clear engagements. - if(!formations[formfrom].GetNumMen()) { - engagements[formfrom][i] = ENGAGED_NONE; - engagements[i][formfrom] = ENGAGED_NONE; - } - } - //ie if could catch old formation, can catch new one. Mostly the new formation will - //have been empty (though not always) so the new one just inherits the stats of the - //old. -} - -int Army::GetMidRoundTarget(int formnum, Army *enemy, Battle *b) -{ - //we are no longer attacking our previous target. Subtract any target-specific bonus. - formations[formnum].RemoveTemporaryBonus(); - //if this formation is behind, it does not want to engage anything. - if(formations[formnum].Behind() != 0) return -1; - - //Are we in reserve? - if(formations[formnum].Reserve() != 0) { - //needs to deal with reserve formations that don't want to engage (unless their frontline - //is wiped out and the enemy has archers) quickly. ie if reserve and still has a frontline, - //then return if there are no enemy flank 2s. - - //check there are no flank 2 enemies (flank 1 enemies should have been engaged with - //when they became flank 1) - int flanktwos = -1; - for(int i=2*NUMFORMS/3; iformations[i].GetNumMen() != 0) { - flanktwos = i; - engagements[formnum][i] = ENGAGED_ENGAGED; - //The enemy has chosen its own target, so doesn't want to engage us at this stage - } - } - if(flanktwos != -1) return flanktwos; - - //If we are in reserve and have frontline troops, quit - if(formations[0].GetNumMen()) return -1; - - //there is no frontline. If there is an enemy frontline, exit as we have to stay in - //defence against them till the next tactical phase. - if(enemy->formations[0].GetNumMen()) return -1; - //the enemy does not have a frontline either, and thus must be down to reserves - //and behind formations. Let's attack a behind formation, by falling through to - //treatment of non-reserves. - } - - //We have a formation which is not behind and if was in reserve, wishes to move out. - //If we are flank 0 or 1, we need to move all our soldiers to flank 1 or 2, - //and exit gracefully. The current soldier will skip his - //remaining attacks as a movement penalty. - - //NOT DONE! Before this though, if flank 0, check if there are flank 2 enemies, and engage them! - - if(formations[formnum].Flank() < FORM_FLANKED) { - //Move soldiers out, while keeping attack ability of most. - formations[formnum].MoveSoldiers(&formations[formnum+(NUMFORMS/FORM_DEAD)]); //ie move them to formnum+6 - CombineEngagements(formnum, formnum+(NUMFORMS/FORM_DEAD), enemy); - AString temp; - temp = *(pLeader->name) + "'s"; - if(formations[formnum].Flank() == FORM_FLANKING) temp += " flanking"; - else if(formnum == 0) temp += " frontline"; - else temp += " reserve"; - switch(formations[formnum].Type()) { - case FORM_FOOT: - temp += " infantry"; - break; - case FORM_RIDE: - temp += " cavalry"; - break; - case FORM_FLY: - temp += " aerial cavalry"; - break; - } - - if(formations[formnum+(NUMFORMS/FORM_DEAD)].Flank() == FORM_FLANKING) { - //new formation is flank 1, so sure it is intercepted. The flank 2's - //will select a target in their own time. If it cannot be intercepted, - //it will come back here and the soldiers will become flank 2. - temp += " flanks"; - int comma = 0; - for(int i=0; iformations[i].Reserve() ) continue; - if(enemy->engagements[i][formnum+(NUMFORMS/FORM_DEAD)] == ENGAGED_NONE) continue; //ie cannot catch this formation. - //'i' is an enemy reserve formation able to catch ours. Dual-engage. - engagements[formnum+(NUMFORMS/FORM_DEAD)][i] = ENGAGED_ENGAGED; - enemy->engagements[i][formnum+(NUMFORMS/FORM_DEAD)] = ENGAGED_ENGAGED; - comma = 1; - if(!comma) temp += ", but is intercepted"; - } - temp += "."; - b->AddLine(temp); - return -2; - } - temp += " breaks through to their enemy's backline."; - b->AddLine(temp); - return -2; - } - - // We have a flanked (flank 2) formation. It should engage a new target of its choice. - - //This means finding a tryattack target - //If no tryattack targets, select from canattack - //Both of these are covered in: - return GetFlankedTarget(b, enemy, formnum); -} - - -int Army::GetMidRoundRangedTarget(int formnum, Army *enemy) -{ - //if this formation is in front, it does not want to disrupt its (melee) - //tryattack listings for the sake of a ranged soldier. - if(formations[formnum].Behind() != 1) return -1; - - int newtarget = -1; - //tryattack any flank 2 formations with men in them - for(int i=2*(NUMFORMS/FORM_DEAD); iformations[i].Flank() != FORM_FLANKED) { - Awrite("Flanked form not flanked!"); - system("pause"); } - if(engagements[formnum][i] >= ENGAGED_TRYATTACK) { - Awrite("Targetless unit has a target!"); - system("pause"); } - #endif - if(enemy->formations[i].GetNumMen()) { - newtarget = i; - engagements[formnum][i] = ENGAGED_TRYATTACK; - } - } - if(newtarget != -1) return newtarget; //returns the highest number target just tryattacked - - //else tryattack any flank 1 formations with men in them - for(int i=(NUMFORMS/FORM_DEAD); i<2*(NUMFORMS/FORM_DEAD); i++) { - #ifdef DEBUG - if(enemy->formations[i].Flank() != FORM_FLANKING) { - Awrite("Flanking form not flanking!"); - system("pause"); } - if(engagements[formnum][i] >= ENGAGED_TRYATTACK) { - Awrite("Targetless unit has a target!"); - system("pause"); } - #endif - if(enemy->formations[i].GetNumMen()) { - newtarget = i; - engagements[formnum][i] = ENGAGED_TRYATTACK; - } - } - if(newtarget != -1) return newtarget; - - //else tryattack front formation - #ifdef DEBUG - if(engagements[formnum][0] >= ENGAGED_TRYATTACK) { - Awrite("Targetless unit has a target!"); - system("pause"); } - #endif - if(enemy->formations[0].GetNumMen()) { - newtarget = 0; - engagements[formnum][0] = ENGAGED_TRYATTACK; - } - if(newtarget != -1) return newtarget; - - //else tryattack front formations in reserve - if(enemy->formations[2].GetNumMen()) { - newtarget = 2; - engagements[formnum][2] = ENGAGED_TRYATTACK; - } - if(enemy->formations[4].GetNumMen()) { - newtarget = 4; - engagements[formnum][4] = ENGAGED_TRYATTACK; - } - if(newtarget != -1) return newtarget; - - //else tryattack behind formations - for(int i=1; i<(NUMFORMS/FORM_DEAD); i += 2) { - #ifdef DEBUG - if(engagements[formnum][i] >= ENGAGED_TRYATTACK) { - Awrite("Targetless unit has a target!"); - system("pause"); } - #endif - if(enemy->formations[i].GetNumMen()) { - newtarget = i; - engagements[formnum][i] = ENGAGED_TRYATTACK; - } - } - return newtarget; -} - -void Army::PenaltyToHit(int penalty) -{ - for( int i=0; iengagements[j][i] = ENGAGED_NONE; - } - } else { - //if someone engaged us, we engage them. - for(int j=0; jengagements[j][i] == ENGAGED_ENGAGED) engagements[i][j] = ENGAGED_ENGAGED; - } - } - } -} - -void Army::FlankFlankers(Battle *b, Army *enemy) -//If flanking formations are unengaged, they become flanked. -{ - //cycle through the flanking formations only - for(int i=(NUMFORMS/FORM_DEAD); i < 2*(NUMFORMS/FORM_DEAD); i++ ) { - if(formations[i].GetNumMen() < 1) continue; - if(formations[i].Engaged(this)) continue; - //unengaged, therefore move all soldiers to flank 2 formation. - int moving = formations[i].GetNumMen(); - formations[i].MoveSoldiers(&formations[i+(NUMFORMS/FORM_DEAD)]); //ie move them to formnum+6 - CombineEngagements(i, i+(NUMFORMS/FORM_DEAD), enemy); - AString temp; - temp = AString(moving) + " of "; - temp += *(pLeader->name) + "'s flanking"; - switch(formations[i].Type()) { - case FORM_FOOT: - temp += " infantry"; - break; - case FORM_RIDE: - temp += " cavalry"; - break; - case FORM_FLY: - temp += " aerial cavalry"; - break; - } - temp += " break through to their enemy's backline."; - b->AddLine(temp); - } -} - -void Army::AssignFrontTargets(Battle *b, Army *enemy, int ass) -//if Formation[0] unengaged: attack enemy flank 2s, then form[0], then flank. -{ - if(formations[0].GetNumMen() < 1) return; - if(formations[0].Engaged(this) ) return; - int done = 0; - //check if there are enemy flank 2s - for(int i=2*(NUMFORMS/FORM_DEAD); iformations[i].GetNumMen() ) { - done = 1; - engagements[0][i] = ENGAGED_ENGAGED; - enemy->engagements[i][0] = ENGAGED_ENGAGED; - } - } - if(done) { - b->AddLine(*(pLeader->name) + "'s frontline infantry attempts to rescue their 'behind' soldiers"); - return; - } - - if(enemy->formations[0].GetNumMen() ) { - engagements[0][0] = ENGAGED_ENGAGED; - enemy->engagements[0][0] = ENGAGED_ENGAGED; - if(!ass) b->AddLine("The frontlines engage"); - return; - } - - //flank! - formations[0].MoveSoldiers(&formations[(NUMFORMS/FORM_DEAD)]); //ie move them to form 6 - CombineEngagements(0, (NUMFORMS/FORM_DEAD), enemy); - AString temp; - temp = *(pLeader->name) + "'s frontline infantry flanks."; - b->AddLine(temp); -} - -void Army::SplitOverwhelmingFrontFormations(Battle *b, Army *enemy) -{ -//reserves should never be engaged with formation 0, so there shouldn't be -//double counting between here and the later splitoverwhelmingflankingformations - - float ratio = (float) 3 * (200 + 3 * enemy->taccontrol ) / (200 + 4 * taccontrol); - // This gives 3 for taccontrol = 0 for both sides, or 2.5 for taccontrol = 100 for both - //it gives 7.5 if enemy=100 own=0, or 1.0 if enemy = 0 own=100. - - int canblock[NUMFORMS]; - for(int i=0; iformations[i].GetSize() * ratio + 0.99); - } - - int size = formations[0].GetSize(); - int engaged = 0; - for(int j=0; j= size) { - canblock[j] -= size; - size = 0; - break; - } else { - size -= canblock[j]; - canblock[j] = 0; - } - } - if(size < 1) return; - //we have some men who can flank - they were not blocked. - int concealedbonus = 0; - if(getrandom(3) < concealment) concealedbonus = (NUMFORMS/FORM_DEAD); - int moved = formations[0].MoveSoldiers(&formations[(NUMFORMS/FORM_DEAD)+concealedbonus], size, 0); - //do not combine engagements, as these men have got past. - - if(moved) { - AString temp; - temp = AString(moved) + " of "; - temp += *(pLeader->name) + "'s infantry flank"; - if(engaged) temp += " around their overwhelmed opponents"; - temp += "."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - } -} - -void Army::SplitOverwhelmingFlankingFormations(Battle *b, Army *enemy, int regtype) -{ - //multiple formations can be engaged with each other, making counting difficult. - //set the ratio needed before can overwhelm - float ratio = (float) 3 * (200 + 3 * enemy->taccontrol ) / (200 + 4 * taccontrol); - // This gives 3 for taccontrol = 0 for both sides, or 2.5 for taccontrol = 100 for both - //it gives 7.5 if enemy=100 own=0, or 1.0 if enemy = 0 own=100. - - int canblock[NUMFORMS]; - for(int i=0; iformations[i].GetSize() * ratio + 0.99); - } - - for(int i=(NUMFORMS/FORM_DEAD); i<2*(NUMFORMS/FORM_DEAD); i++) { - if(formations[i].Type() == FORM_FOOT && (TerrainDefs[regtype].flags & TerrainType::RESTRICTEDFOOT) ) continue; - - int size = formations[i].GetSize(); - int engaged = 0; - for(int j=0; j= size) { - canblock[j] -= size; - size = 0; - break; - } else { - size -= canblock[j]; - canblock[j] = 0; - } - } - if(size < 1) continue; - //we have some men who can flank - they were not blocked. - int moved = formations[i].MoveSoldiers(&formations[i+(NUMFORMS/FORM_DEAD)], size, 0); - //do not combine engagements, as these men have got past. - if(moved < 1) continue; - - AString temp; - temp = AString(moved) + " of "; - temp += *(pLeader->name) + "'s flanking"; - switch(formations[i].Type()) { - case FORM_FOOT: - temp += " infantry"; - break; - case FORM_RIDE: - temp += " cavalry"; - break; - case FORM_FLY: - temp += " aerial cavalry"; - break; - } - - if(engaged) temp += " flank around their overwhelmed opponents and"; - temp += " reach their enemy's backline."; - b->AddLine(temp); - } -} - -void Army::SetCanAttack(Army *enemy) -{ - for(int i=0; iformations[j].Flank() == FORM_FLANKED) engagements[i][j] = ENGAGED_CONDITIONAL; - if(enemy->formations[j].Type() == FORM_FOOT) engagements[i][j] = ENGAGED_CANATTACK; - else if(enemy->formations[j].Type() == FORM_RIDE) { - if(formations[i].Type() == FORM_FOOT && (getrandom(100) < 40) ) engagements[i][j] = ENGAGED_CANATTACK; - else if(formations[i].Type() == FORM_FOOT && (getrandom(100) < 30) ) engagements[i][j] = ENGAGED_CONDITIONAL; - else if(formations[i].Type() == FORM_RIDE && (getrandom(100) < 100) ) engagements[i][j] = ENGAGED_CANATTACK; //currently 100%! - else if(formations[i].Type() == FORM_RIDE && (getrandom(100) < 60) ) engagements[i][j] = ENGAGED_CONDITIONAL; - else if(formations[i].Type() == FORM_FLY) engagements[i][j] = ENGAGED_CANATTACK; - } - else if(enemy->formations[j].Type() == FORM_FLY) { - if(formations[i].Type() == FORM_FOOT && (getrandom(100) < 10) ) engagements[i][j] = ENGAGED_CANATTACK; - else if(formations[i].Type() == FORM_FOOT && (getrandom(100) < 10) ) engagements[i][j] = ENGAGED_CONDITIONAL; - else if(formations[i].Type() == FORM_RIDE && (getrandom(100) < 30) ) engagements[i][j] = ENGAGED_CANATTACK; - else if(formations[i].Type() == FORM_RIDE && (getrandom(100) < 30) ) engagements[i][j] = ENGAGED_CONDITIONAL; - else if(formations[i].Type() == FORM_FLY && (getrandom(100) < 50) ) engagements[i][j] = ENGAGED_CANATTACK; - else if(formations[i].Type() == FORM_FLY && (getrandom(100) < 50) ) engagements[i][j] = ENGAGED_CONDITIONAL; - } - - } - } -} - -void Army::ReservesIntercept(Army *enemy) -{ - int reserves = 2; - if(formations[2].GetNumMen() == 0) { - reserves--; - for(int i=0; iformations[j].Flank() != FORM_FLANKING) continue; - //...with men in them... - if(enemy->formations[j].GetNumMen() == 0) continue; - //...that we can catch. - if(engagements[2][j] > ENGAGED_NONE) { - //if we can attack, or if we can conditionally attack and the other reserves can attack, then engage. - if((engagements[2][j] > ENGAGED_CONDITIONAL) || (engagements[4][j] > ENGAGED_CONDITIONAL)) { - engagements[2][j] = ENGAGED_ENGAGED; - enemy->engagements[j][2] = ENGAGED_ENGAGED; - } - } - if(engagements[4][j] > ENGAGED_NONE) { - //if we can attack, or if we can conditionally attack and the other reserves can attack, then engage. - if((engagements[2][j] > ENGAGED_CONDITIONAL) || (engagements[4][j] > ENGAGED_CONDITIONAL)) { - engagements[4][j] = ENGAGED_ENGAGED; - enemy->engagements[j][4] = ENGAGED_ENGAGED; - } - } - - } -} - -int Army::SizeFrontFliers() -{ - int size = 0; - for(int i=0; iSizeFrontFliers() + enemy->SizeFrontRiders()) == 0) { - //the enemy has no cavalry to defend against. If they have any units which have not - //flanked, lets flank! - int backline = 0; - for(int i=0; i<(NUMFORMS/FORM_DEAD); i++) { - if(enemy->formations[i].GetNumMen()) backline = 1; - } - if(!backline) return; //the enemy troops must have flanked, so lets intercept them as reserves. - int moved = formations[4].GetNumMen(); - - formations[4].MoveSoldiers(&formations[16]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " flank around the enemy unhindered."; - b->AddLine(temp); - return; - } - - int concealedbonus = 0; - if(getrandom(3) < concealment) concealedbonus = (NUMFORMS/FORM_DEAD); - - if(SizeBehind() ) { - for(int i=0; iformations[i].GetNumMen()) { - if(enemy->formations[i].Type() == FORM_FLY) catcheffect = 0.7; - else catcheffect = 1; - - top += enemy->formations[i].NumRangedAttacks() * catcheffect; - bottomtwo += enemy->formations[i].NumMeleeAttacks() * catcheffect; - } - } - float divisor = (float) enemy->SizeBehind(); - if(SizeFrontFliers() > divisor) divisor = (float) SizeFrontFliers(); //sizefrontfliers > 0 - #ifdef DEBUG - if(divisor == 0) { - Awrite("ReservesMayFlank dividing by zero"); - system("pause"); - } - #endif - top /= divisor; - bottomtwo /= divisor; - divisor = (float) SizeBehind(); - if(SizeFrontFliers() > divisor) divisor = (float) SizeFrontFliers(); - #ifdef DEBUG - if(divisor == 0) { - Awrite("ReservesMayFlank dividing by zero"); - system("pause"); - } - #endif - bottomone /= divisor; - behindscore = top / (bottomone + bottomtwo); - } else if (enemy->SizeBehind() ) { - //no behind for us, but behind for them. Flank! - int moved = formations[4].GetNumMen(); - formations[4].MoveSoldiers(&formations[10+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } else { - //neither side has a behind. For sake of balance, whichever side has more fliers gets to flank. - if(enemy->SizeFrontFliers() > SizeFrontFliers() ) return; - //if enemy has flanked, return - if(enemy->formations[10].GetSize() || enemy->formations[16].GetSize()) return; - //flank all troops. - int moved = formations[4].GetNumMen(); - formations[4].MoveSoldiers(&formations[10+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } - - //we now have a behindscore, which tells us how favourable attacking their behind - //looks compared to defending our own (1 = neutral, >1 is good, <1 is poor). We know - //we have fliers, and the enemy has either fliers or cavalry. - - if(behindscore > 1 && (enemy->SizeFrontFliers() == 0)) { - //we want to flank and the enemy has no defending fliers. Flank! - int moved = formations[4].GetNumMen(); - formations[4].MoveSoldiers(&formations[10+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } - - //lets get the ratio of our cavalry to the enemy's. - float inverseratio = enemy->SizeFrontFliers() / SizeFrontFliers(); - float inversecombined = (enemy->SizeFrontFliers() + enemy->SizeFrontRiders()) / (SizeFrontFliers() + SizeFrontRiders()); - - //if flanking is unattractive and the cavalry ratio is worse than the flying one, use the - //cavalry ratio. - if((behindscore <= 1) && (inversecombined > inverseratio)) inverseratio = inversecombined; - - //inverseratio should now be non-zero - #ifdef DEBUG - if(inverseratio == 0) { - Awrite("ReservesMayFlank inverse ratio is zero"); - system("pause"); - } - #endif - float critical = 0.8; - if(pLeader->tactics == TACTICS_AGGRESSIVE) critical /= 4; - else if(pLeader->tactics == TACTICS_DEFENSIVE) critical *= 4; - // if tactitians are able to be aggressive or defensive, adjust this number to - // 0.2 or 3.2 respectively. - - if( (behindscore / inverseratio) < critical && (inverseratio > (1/3))) return; //decided not to flank, too much opposition. - if( inverseratio > 4 ) return; //too much opposition to try and flank. - - //we are flanking. Split by two conditions to see how many men flank, and how many - //stay in reserve. - - if(behindscore < 2) { - int tosend = (int) ((float) (2 * behindscore * SizeFrontFliers()) / 5); - int tostay = SizeFrontFliers() - tosend; - if(tostay < enemy->SizeFrontFliers() / 4) tostay = 0; //this only occurs above about r = 1.5 with the default critical condition, but can occur for lower r if aggressive. - if(tostay > 3 * enemy->SizeFrontFliers() ) tostay = 3 * enemy->SizeFrontFliers(); - - //we use tostay, because tosend includes soldiers sent in earlier rounds and now - //in formations 6 and 10. Note MoveSoldiers(,,) is robust enough to handle negative - //numbers of soldiers to move, and will move no-one if that is the case. - int moved = formations[4].MoveSoldiers(&formations[10+concealedbonus], (formations[4].GetSize() - tostay), 1); - //do not combine engagements - if(!moved) return; - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } else { - //behindscore 2 or more. - if(behindscore * inverseratio > 1 ) { - //very attractive target. Everyone flanks. - int moved = formations[4].GetNumMen(); - formations[4].MoveSoldiers(&formations[10+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } else { - int tostay = SizeFrontFliers() / 4; - if(tostay > 3 * enemy->SizeFrontFliers() ) tostay = 3 * enemy->SizeFrontFliers(); - int moved = formations[4].MoveSoldiers(&formations[10+concealedbonus], (formations[4].GetSize() - tostay), 1); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s aerial cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } - } -} - -void Army::RidingReservesMayFlank(Battle *b, Army *enemy) -//This is almost, but not quite, a copy of the method above. Unfortunately -//the difference is big enough to make combining it into one method difficult. -{ - //Now, lets just look at the riders - if(!formations[2].GetSize()) return; - - float top = 0; - float bottomone = 1; - float bottomtwo = 0; - float catcheffect; - float behindscore = 1; - - if(enemy->SizeFrontRiders() == 0) { - //the enemy has no cavalry to defend against. If they have any units which have not - //flanked, lets flank! - int backline = 0; - for(int i=0; i<(NUMFORMS/FORM_DEAD); i++) { - if(enemy->formations[i].GetNumMen()) backline = 1; - } - if(!backline) return; //the enemy troops must have flanked, so lets intercept them as flanked ourselves. - int moved = formations[2].GetNumMen(); - formations[2].MoveSoldiers(&formations[14]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " flank around the enemy unhindered."; - b->AddLine(temp); - return; - } - - int concealedbonus = 0; - if(getrandom(3) < concealment) concealedbonus = (NUMFORMS/FORM_DEAD); - - if(SizeBehind() ) { - for(int i=0; iformations[i].GetNumMen()) { - if(formations[i].Type() == FORM_FLY) catcheffect = 0.4; - else if(formations[i].Type() == FORM_RIDE) catcheffect = 0.8; - else catcheffect = 1; - - top += enemy->formations[i].NumRangedAttacks() * catcheffect; - bottomtwo += enemy->formations[i].NumMeleeAttacks() * catcheffect; - } - } -//b->AddLine(AString("top ") + (int) top); -//b->AddLine(AString("bottom ") + (int) bottomone + " " + (int) bottomtwo); - float divisor = (float) enemy->SizeBehind(); - if(SizeFrontRiders() > divisor) divisor = (float) SizeFrontRiders(); //sizefrontfliers > 0 - #ifdef DEBUG - if(divisor == 0) { - Awrite("ReservesMayFlank dividing by zero"); - system("pause"); - } - #endif - top /= divisor; - bottomtwo /= divisor; - divisor = (float) SizeBehind(); - if(SizeFrontRiders() > divisor) divisor = (float) SizeFrontRiders(); - #ifdef DEBUG - if(divisor == 0) { - Awrite("ReservesMayFlank dividing by zero"); - system("pause"); - } - #endif - bottomone /= divisor; - behindscore = top / (bottomone + bottomtwo); -//b->AddLine((int) behindscore); - } else if (enemy->SizeBehind() ) { - //no behind for us, but behind for them. Flank! - int moved = formations[2].GetNumMen(); - formations[2].MoveSoldiers(&formations[8+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } else { - //neither side has a behind. For sake of balance, whichever side has more fliers gets to flank. - if(enemy->SizeFrontFliers() > SizeFrontFliers() ) return; - //if enemy has flanked, return - if(enemy->formations[8].GetSize() || enemy->formations[14].GetSize()) return; - //flank all troops. - int moved = formations[2].GetNumMen(); - formations[2].MoveSoldiers(&formations[8+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } - - //we now have a behindscore, which tells us how favourable attacking their behind - //looks compared to defending our own (1 = neutral, >1 is good, <1 is poor). We know - //we have riders, and the enemy has either fliers or cavalry. - - if(behindscore > 1 && ((enemy->SizeFrontRiders() + enemy->SizeFrontFliers()) == 0)) { - //we want to flank and the enemy has no defending cavalry. Flank! - int moved = formations[2].GetNumMen(); - formations[2].MoveSoldiers(&formations[8+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } - - //lets get the ratio of our cavalry to the enemy's. - float inverseratio = (float) enemy->SizeFrontRiders() / SizeFrontRiders(); - float inversecombined = (float) (enemy->SizeFrontFliers() + enemy->SizeFrontRiders()) / (SizeFrontFliers() + SizeFrontRiders()); - - //if flanking is attractive and the combined ratio is better than the flying one, use the - //combined ratio. - if((behindscore >= 1) && (inversecombined < inverseratio)) inverseratio = inversecombined; - - //inverseratio should be non-zero -// #ifdef DEBUG - if(inverseratio == 0) { - Awrite("ReservesMayFlank inverse ratio is zero"); - b->AddLine("ReservesMayFlank Inverseratio is zero, please contact your GM!"); -// system("pause"); - } -// #endif - float critical = 0.8; - if(pLeader->tactics == TACTICS_AGGRESSIVE) critical /= 2; - else if(pLeader->tactics == TACTICS_DEFENSIVE) critical *= 3; - // if tactitians are able to be aggressive or defensive, adjust this number to - // 0.4 or 2.4 respectively. - if( (behindscore / inverseratio) < critical && (inverseratio > (1/3))) return; //decided not to flank, too much opposition. (second part says we have less than three times the number of enemy cav) - if( inverseratio >= 4 && pLeader->tactics != TACTICS_AGGRESSIVE) return; //too much opposition to try and flank. - - //we are flanking. Split by two conditions to see how many men flank, and how many - //stay in reserve. - if(behindscore < 2) { - int tosend = (int) ((float) (2 * behindscore * SizeFrontFliers()) / 5); - if(pLeader->tactics == TACTICS_AGGRESSIVE) tosend = (tosend*4)/3; - int tostay = SizeFrontFliers() - tosend; - if(tostay < enemy->SizeFrontFliers() / 4) tostay = 0; //this only occurs above about r = 1.5 with the default critical condition, but can occur for lower r if aggressive. - if(tostay > 3 * enemy->SizeFrontFliers() ) tostay = 3 * enemy->SizeFrontFliers(); - - //we use tostay, because tosend includes soldiers sent in earlier rounds and now - //in formations 6 and 10. Note MoveSoldiers(,,) is robust enough to handle negative - //numbers of soldiers to move, and will move no-one if that is the case. - int moved = formations[2].MoveSoldiers(&formations[8+concealedbonus], (formations[2].GetSize() - tostay), 1); - //do not combine engagements - if(!moved) return; - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } else { - //behindscore 2 or more. - if(behindscore * inverseratio > 1 ) { - //very attractive target. Everyone flanks. - int moved = formations[2].GetNumMen(); - formations[2].MoveSoldiers(&formations[8+concealedbonus]); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } else { - int tostay = SizeFrontFliers() / 4; - if(tostay > 3 * enemy->SizeFrontFliers() ) tostay = 3 * enemy->SizeFrontFliers(); - int moved = formations[2].MoveSoldiers(&formations[8+concealedbonus], (formations[2].GetSize() - tostay), 1); - //do not combine engagements - AString temp; - temp = AString(moved) + " of "; - temp = *(pLeader->name) + "'s cavalry"; - temp += " attempt to flank around the enemy."; - if(concealedbonus) temp += " Their passage is concealed and they reach their enemy's backline unhindered."; - b->AddLine(temp); - return; - } - } -} - -void Army::AssignRangedTargets(Army *enemy) -{ - for(int i=0; i>defence, return 1 -//if attack< 4.2) return 0.95; - if (diff < -4.2) return 0.05; - while(diff > 0.3) { // max 14 cycles ... not too time intensive. - diff -= 0.3; - tohit *= 1.231; - } - while(diff < -0.3) { - diff += 0.3; - tomiss *= 1.231; - } - return (tohit / (tohit + tomiss)); -} - -int Army::GetFlankedTarget(Battle *b, Army *enemy, int formnum) -{ -//return of -1 means already engaged. -//return of -2 means cannot find any target. - - //timesaving: if we have no men, return - if(!formations[formnum].GetNumMen()) return -2; -//this assumes we are a melee formation. If we ever allow ranged formations to flank, will have -//to write a new section for them. - int besttarget = -1; - //if we are already engaged, return. - for(int j=0; jformations[j].GetSize()) { - #ifdef DEBUG - cout << "Attacking a tryattack formation"; - #endif - engagements[formnum][j] = ENGAGED_ENGAGED; - if(enemy->formations[j].Flank() != FORM_FLANKED ) enemy->engagements[j][formnum] = ENGAGED_ENGAGED; //they are forced to engage us ... but NOT if they are a flank 2 formation! - else if(enemy->engagements[j][formnum] < ENGAGED_CANATTACK) enemy->engagements[j][formnum] = ENGAGED_CANATTACK; //BUT, they should be _able_ to since we are fighting them - besttarget = j; - } else { - //try attack target empty - engagements[formnum][j] = ENGAGED_CANATTACK; //don't want to set it to none in case someone moves into this formation later - } - } - } - if(besttarget != -1) { - AString temp = *(pLeader->name) + "'s "; - temp += AString(formations[formnum].GetNumMen()); - switch(formations[formnum].Type()) { - case FORM_RIDE: - temp += " flanked cavalry"; - break; - case FORM_FLY: - temp += " flanked aerial cavalry"; - break; - default: - temp += " flanked infantry"; - break; - } - temp += " engage the enemy"; - if(enemy->formations[besttarget].Behind()) temp += " ranged"; - else if(besttarget == 0) formations[formnum].SetTemporaryBonus(1); - switch(enemy->formations[besttarget].Type()) { - case FORM_RIDE: - temp += " cavalry."; - break; - case FORM_FLY: - temp += " aerial cavalry"; - break; - default: - temp += " infantry"; - break; - } - if(besttarget == 0) temp += " from behind"; - temp += "."; - b->AddLine(temp); - return besttarget; - } - float bestscore = 0; - int secondbesttarget = -1; - float secondbestscore; - float ourattackl = formations[formnum].MeleeAttackLevel(); - float ourdefencel = formations[formnum].MeleeDefenceLevel(); - float ourattacks = formations[formnum].NumMeleeAttacks(); - - float score; - - for(int i=0; iformations[i].GetSize() < 1) continue; - //if we cannot catch this formation, forget about engaging it! - - if(engagements[formnum][i] == ENGAGED_NONE) continue; - //there is some doubt here - what if a later formation engages this one? Best solution I - //can think of is to do the flying flankers first when called from tactical phase, - //because these are most likely to be able to engage if they choose to. - if(engagements[formnum][i] == ENGAGED_CONDITIONAL && !enemy->formations[i].Engaged(enemy) ) continue; - //if there are non flank-2 enemies, do not choose a flank 2 enemy. Note flank 2 enemies - //are checked last, so this should work :). - if(besttarget != -1 && enemy->formations[i].Flank() == FORM_FLANKED) continue; - - //these all get used regardless of whether formation is ranged or melee. - float rangedattacks = (float) enemy->formations[i].NumRangedAttacks(); - float meleeattacks = (float) enemy->formations[i].NumMeleeAttacks(); - float defence = enemy->formations[i].MeleeDefenceLevel(); - float attack = enemy->formations[i].MeleeAttackLevel(); - float size = (float) enemy->formations[i].GetSize(); - if(enemy->formations[i].Behind() != 0) { - //ranged formation - - //score is 'how many friendlies we save': kx - y. k = enemy kills per size. - //x = our expected kills. y = extra kills their melee do. - //k = numrangedattacks / 2 / size (assume they are skilled enough to get 50% kills) - //x = ourattacks * chance[ourattack,theirdefence] / 2 - //y = nummeleeattacks / 2 * chance[theirattack,ourdefence] - #friendlysengaged with them (min 0). - - score = rangedattacks * ourattacks * KillChance(ourattackl, defence) / (4 * size); - - float penalty = meleeattacks * KillChance(attack, ourdefencel) / 2; - //NOT DONE: If we are in anti-ranged terrain, the score should be multiplied by 2/3 - //(to bring hit chance to 1/3) and - //the penalty should include 1/6 of their ranged attacks. - - for(int j=0; jengagements[i][j] == ENGAGED_ENGAGED) penalty -= formations[j].GetSize(); - } - if(penalty > 0) score -= penalty; - //if we are agressive, we want to hit behind formations, so double this score. - //melee scores are never negative, so if this is negative doubling has no effect on choice order. - if(pLeader->tactics == TACTICS_AGGRESSIVE) score *= 2; - - //we have a target score; - if(besttarget == -1 || score > bestscore) { - secondbesttarget = besttarget; - secondbestscore = bestscore; - besttarget = i; - bestscore = score; - } else if(secondbesttarget == -1 || score > secondbestscore) { - secondbesttarget = i; - secondbestscore = score; - } - } else { - //melee formation - //score is 'how many friendlies we save': kx. - // k = enemy kills per man (when directed at us), x = our expected kills. - //Because flanking formations will tend to be of high attack score, - //the fact that k is kills directed at us (not at whoever they're fighting) - //means that melee formations will be artificially reduced in score, ie flankers - //will usually prefer to fight ranged formations. This is probably as it should be, - //but just to balance it out we'll include the +1 combat bonus here in both our kills - //AND their kills (even though they actually get a -1 bonus in the fight). - // k = numranged / 2 + nummelee / 2 * chance[theirattack+1,ourdefence] / size - // x = ourattacks * chance[ourattack+1,theirdefence] / 2 - - score = (rangedattacks + meleeattacks * KillChance(attack + 1, ourdefencel) ) / (4 * size); - score *= ourattacks * KillChance(ourattackl + 1, defence); - - //if this formation is flanking or in reserve, penalise it by factor of 2 (score is always positive). - if(i != 0) score /= 2; - - //we have a target score; - if(besttarget == -1 || score > bestscore) { - secondbesttarget = besttarget; - secondbestscore = bestscore; - besttarget = i; - bestscore = score; - } else if(secondbesttarget == -1 || score > secondbestscore) { - secondbesttarget = i; - secondbestscore = score; - } - } - } - //by now we hopefully have the two best targets. - if(besttarget == -1) { - //no best target! - //this means we are not going to fight anyone! - return -2; - } - engagements[formnum][besttarget] = ENGAGED_ENGAGED; - if(enemy->formations[besttarget].Flank() != FORM_FLANKED ) enemy->engagements[besttarget][formnum] = ENGAGED_ENGAGED; //they don't necessarily engage us back if they are flank 2. - else if(enemy->engagements[besttarget][formnum] < ENGAGED_CANATTACK) enemy->engagements[besttarget][formnum] = ENGAGED_CANATTACK; //BUT, they should be able to since we are fighting them - if(secondbesttarget != -1) engagements[formnum][secondbesttarget] = ENGAGED_TRYATTACK; - - AString temp = *(pLeader->name) + "'s "; - temp += AString(formations[formnum].GetNumMen()); - switch(formations[formnum].Type()) { - case FORM_RIDE: - temp += " flanked cavalry"; - break; - case FORM_FLY: - temp += " flanked aerial cavalry"; - break; - default: - temp += " flanked infantry"; - break; - } - temp += " engage the enemy"; - if(enemy->formations[besttarget].Behind()) temp += " ranged"; - else if(besttarget == 0) formations[formnum].SetTemporaryBonus(1); - switch(enemy->formations[besttarget].Type()) { - case FORM_RIDE: - temp += " cavalry."; - break; - case FORM_FLY: - temp += " aerial cavalry"; - break; - default: - temp += " infantry"; - break; - } - if(besttarget == 0) temp += " from behind"; - temp += "."; - b->AddLine(temp); - return besttarget; -} - -void Army::FlankersEngage(Battle *b, Army *enemy) -{ - //search through flank 2 formations - for(int i=NUMFORMS-1; i >= 2*(NUMFORMS/FORM_DEAD); i--) { - //search backwards, so flying formations engage first - GetFlankedTarget(b,enemy,i); - } -} - -void Army::ClearEmptyEngagements() -{ - for(int i=0; iformations[0].GetSize() < 1) return; - //one of our frontline units has engaged the enemy frontline. Any of our flanked - //units which have engaged the enemy frontline get a +1 temp bonus - //TODO: Add in a check that these units haven't engaged others also - if so, they shouldn't get the bonus. - for(int i=2*(NUMFORMS/FORM_DEAD); i less experience: - if (count < 50) exp *= (float) (50+count)/100; //scaled down for small battles. - - //small experience for victor based on enemies killed. Not yet dependent on who killed them. Not yet dependent on who dies (ie wolf or dragon count the same) - float exp2 = (float) (30 * enemydead) / count; - int divisor = 1; - while(exp2 > 20) { - exp += (float) 20/divisor; - divisor++; //20, then 10, then 7, then 5 - exp2 -= 20; - } - exp += (float) exp2/divisor; - - for(int x = 0; x < count; x++) { - Soldier * s = GetSoldier(x); - if(!(ItemDefs[s->race].type & IT_MAN)) continue; - int exper = (int) exp; - //if riding leader, give 2/3 of normal bonus to riding skill & normal skill - - if(s->unit->GetSkill(S_FRENZY)) s->unit->Experience(S_FRENZY,(2*exper/3),0); - if(s->unit->GetSkill(S_BASE_BATTLETRAINING)) s->unit->Experience(S_BASE_BATTLETRAINING,(2*exper/3),0); - - if(s->riding != -1) { - //has riding skill. - if(s->unit->GetSkill(S_SWIFTNESS)) s->unit->Experience(S_SWIFTNESS,(exper/3),0); - if(!s->unit->IsNormal()) { - exper = (int) (2*exp/3); - s->unit->Experience(S_RIDING,exper,0); - } else s->unit->Experience(S_RIDING,exper,0); - } - - if(s->weapon != -1) { - WeaponType *pWep = FindWeapon(ItemDefs[s->weapon].abr); - AString skname; - skname = pWep->baseSkill; - int skill = LookupSkill(&skname); - skname = pWep->orSkill; - int orskill = LookupSkill(&skname); - if(orskill != -1) { - if(s->unit->GetSkill(orskill) > s->unit->GetSkill(skill) ) skill = orskill; - } - if(skill == -1) skill = S_COMBAT; - //we want to practise skill - s->unit->Experience(skill,exper,0); - - } else if(!s->special) s->unit->Experience(S_COMBAT,exper,0); - //practise special if we are a mage. - if(s->special && s->unit->IsMage() && s->unit->combat != -1) { - //spells which do not get experience awarded during battle (eg are not cast as spells) get more exp here: - if(s->unit->combat == S_UNITY) { - s->unit->Experience(s->unit->combat,(int) (exp), 0); - } else { - s->unit->Experience(s->unit->combat,(int) (exp/3), 0); - } - } - } -} - -#ifdef DEBUG -void Army::WriteEngagements(Battle *b) -{ - for(int i=0; iAddLine(temp); - } - b->AddLine(""); -} -#endif - -int RoundRandom(float input) -//rounds a positive float to one of the adjacent integers while preserving overall mean. eg 2.2 would have a 20% chance of rounding to 3, and 80% chance of rounding to 2. -{ - if(input < 0) return 0; - int min = (int) input; - input -= min; - //input is now between 0 and 1. - input = input*10000 - 0.5; - int val = (int) input; - if(getrandom(10000) < val) return (min+1); - return min; -} - -void Army::DoEthnicMoraleEffects(Battle *b) -{ - int racecount[RA_NA]; - for(int i=0; ispecial == SkillDefs[S_UNITY].special) unity += s->slevel*s->slevel; - ManType *mt = FindRace(ItemDefs[s->race].abr); - if(mt) { - racecount[mt->ethnicity]++; - totalmen++; - } - else if(ItemDefs[s->race].type & IT_UNDEAD) { - racecount[RA_OTHER]++; //don't affect orcs! - totalmen++; // monsters other than undead do not contribute to morale penalty - } - } -#ifdef DEBUG2 -cout << " !"; -#endif - unity *= 50; //unity 'heals' 50 men * lvl * lvl. - - float racepenalty[RA_NA]; - for(int i=0; irace].abr); - int ethnic = -1; - if(mt) ethnic = mt->ethnicity; //monsters do not suffer morale penalties. - if(ethnic != -1) { - int penalty = RoundRandom(racepenalty[ethnic]); - if(penalty && unity > 0) { - unity--; - if(getrandom(2)) { - unityhelps++; - penalty = 0; - } - } - if(penalty) racecount[ethnic]++; - s->askill -= penalty; - s->dskill[ATTACK_COMBAT] -= penalty; - } - } - int total = 0; - for(int i=0; iname + "'s soldiers."; - if(unityhelps) b->AddLine(temp); - - temp = AString(total) + " of " + *pLeader->name + "'s soldiers suffer a morale penalty due to the presence of soldiers from different ethnic groups."; - if(total) b->AddLine(temp); -} diff --git a/arcadia/army1.h b/arcadia/army1.h deleted file mode 100644 index 9395d0238..000000000 --- a/arcadia/army1.h +++ /dev/null @@ -1,148 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef ARMY_CLASS -#define ARMY_CLASS - -#include -#include -using namespace std; - -class Army; - -#include "soldier1.h" -#include "formation1.h" -#include "unit.h" -#include "alist.h" -#include "items.h" -#include "object.h" -#include "shields.h" -#include "helper.h" - -class Army -{ - public: - Army(Unit *,AList *,int,int = 0); - ~Army(); - - int NumAlive(); //includes illusions - int NumNonIllusionsAlive(); - Soldier * GetSoldier(int soldiernum) const; //soldiernum should be from 0 to count-1. - - int Broken(); - void Reset(); - void ResetEngagements(); - int NumSpoilers() const; - - int CanAttack(); - Soldier * GetAttacker(int attackernum); //attackernum should be from 0 to CanAttack()-1. - //For some reason this can't be set constant - may want to check this if problems. - - int ShieldIsUseful(char *special) const; - int IsSpecialTarget(char *special) const; - int GetTarget(Army *attackers, int formation, int attackType, int *targetform, char* special, Battle *b); - int DoAnAttack(char *special, int numAttacks, int race, int attackType, int attackLevel, - int flags, int weaponClass, char *effect, int mountBonus, Army *attackers, int formation, Battle *b, - int strength = 1); - - AList armytext; - void AddLine(const AString &); - - void WriteLosses(Battle *); - int Lose(Battle *,ItemList *, int ass = 0); - void Tie(Battle *); - void Win(Battle *,ItemList *, int enemydead); - int CanBeHealed(); - void DoHeal(Battle *, int enemydead); - void DoHealLevel(Battle *,int,int useItems ); - void DoResurrect(Battle *); - void AssassinationResurrect(); - void DoNecromancy(Battle *, int enemydead); - void Regenerate(Battle *); - void DoExperience(int enemydead = 0); - - void GetMonSpoils(ItemList *,int, int); - - void DowngradeShield(Shield *hi); //This is in shields.cpp - void DoBindingAttack(Soldier *pAtt, Battle *b); //This is in specials.cpp - void DoDragonBindingAttack(Soldier *pAtt, Battle *b, Army *atts); - - //Formation Engagement Details - void CombineEngagements(int formfrom, int formto, Army *enemy); - int GetMidRoundTarget(int formation, Army *enemy, Battle *b); ///returns formnumber of newly engaged enemy formation, or -1 if none. - int GetMidRoundRangedTarget(int formation, Army *enemy); //returns formnumber of a randomg newly tryattacked enemy formation, or -1 if none. - - //Formation Phase - void PenaltyToHit(int penalty); - void SortFormations(Battle *b, int regtype); - void MirrorEngagements(Army *enemy); - void FlankFlankers(Battle *b, Army *enemy); - void AssignFrontTargets(Battle *b, Army *enemy, int ass = 0); - void SplitOverwhelmingFrontFormations(Battle *b, Army *enemy); - void SplitOverwhelmingFlankingFormations(Battle *b, Army *enemy, int regtype); - void SetCanAttack(Army *enemy); - void ReservesIntercept(Army *enemy); - void AssignRangedTargets(Army *enemy); - - int SizeFrontFliers(); - int SizeFrontRiders(); - int SizeBehind(); - - float KillChance(float attack, float defence); - void FlyingReservesMayFlank(Battle *b, Army *enemy); - void RidingReservesMayFlank(Battle *b, Army *enemy); - int GetFlankedTarget(Battle *b, Army *enemy, int formnum); - void FlankersEngage(Battle *b, Army *enemy); - - void ClearEmptyEngagements(); - void SetTemporaryBonuses(Army *enemy); - void DoEthnicMoraleEffects(Battle *b); - - Unit * pLeader; - ShieldList shields; - int round; - int tac; - int taccontrol; - int misassigned; - int canride; - int count; - int nonillusioncount; //used in win conditions - int rangedbonus; //as for bonus in formations, but only affects ranged attacks made by army. - int concealment; - - int hitstotal; // Number of hits at start of battle, excluding illusions. - - - /* Formations Stuff */ - #define NUMFORMS 18 - Formation formations[NUMFORMS+1]; - int engagements[NUMFORMS][NUMFORMS]; - int sortedformations; - - #ifdef DEBUG - void WriteEngagements(Battle *b); - #endif -}; - -#endif diff --git a/arcadia/astring.cpp b/arcadia/astring.cpp deleted file mode 100644 index 48fe24231..000000000 --- a/arcadia/astring.cpp +++ /dev/null @@ -1,377 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "astring.h" -#include -#include - -AString::AString() -{ - len = 0; - str = new char[1]; - str[0] = '\0'; -} - -AString::AString(char *s) -{ - len = 0; - if (s) len = strlen(s); - str = new char[len + 1]; - str[0] = '\0'; - if (s) strcpy(str,s); -} - -AString::AString(const char *s) -{ - len = 0; - if (s) len = strlen(s); - str = new char[len + 1]; - str[0] = '\0'; - if (s) strcpy(str,s); -} - -AString::AString(int l) -{ - char buf[16]; - sprintf(buf,"%d",l); - len = strlen(buf); - str = new char[len+1]; - strcpy(str,buf); -} - -AString::AString(unsigned int l) -{ - char buf[16]; - sprintf(buf,"%u",l); - len = strlen(buf); - str = new char[len+1]; - strcpy(str,buf); -} - -AString::AString(char c) -{ - len = 1; - str = new char[2]; - str[0] = c; - str[1] = '\0'; -} - -AString::~AString() -{ - if (str) delete str; - str = NULL; -} - -AString::AString(const AString &s) -{ - len = s.len; - str = new char[len + 1]; - strcpy(str,s.str); -} - -AString & AString::operator=(const AString &s) -{ - len = s.len; - if (str) delete str; - str = new char[len + 1]; - strcpy(str,s.str); - return *this; -} - -AString & AString::operator=(const char *c) -{ - len = 0; - if (c) len = strlen(c); - if (str) delete str; - str = new char[len + 1]; - if (c) strcpy(str,c); - return *this; -} - -int AString::operator==(char *s) -{ - return isEqual(s); -} - -int AString::operator==(const char *s) -{ - return isEqual(s); -} - -int AString::operator==(const AString &s) -{ - return isEqual(s.str); -} - -int AString::isEqual(const char *temp2) -{ - char *temp1 = str; - - // Handle comparisons with null - if (temp1 && !temp2) return 0; - if (temp2 && !temp1) return 0; - if (!temp1 && !temp2) return 1; - - while ((*temp1) && (*temp2)) { - char t1 = *temp1; - if ((t1 >= 'A') && (t1 <= 'Z')) - t1 = t1 - 'A' + 'a'; - if (t1 == '_') t1 = ' '; - char t2 = *temp2; - if ((t2 >= 'A') && (t2 <= 'Z')) - t2 = t2 - 'A' + 'a'; - if (t2 == '_') t2 = ' '; - if (t1 != t2) return 0; - temp1++; - temp2++; - } - if (*temp1==*temp2) return 1; - return 0; -} - -AString AString::operator+(const AString &s) -{ - char *temp = new char[len+s.len+1]; - int i; - for (i=0; i= len) return 0; - if (str[place] == ';') return 0; - - if (str[place] == '"') { - place++; - while (place < len && str[place] != '"') { - buf[place2++] = str[place++]; - } - if (place != len) { - /* Get rid of extra " */ - place++; - } else { - /* Unmatched "" return 0 */ - delete str; - str = new char[1]; - len = 0; - str[0] = '\0'; - return 0; - } - } else { - while (place= len) { - return 0; - } - return( new AString( &str[ place ] )); -} - -int AString::getat() -{ - int place = 0; - while (place < len && (str[place] == ' ' || str[place] == '\t')) - place++; - if (place >= len) return 0; - if (str[place] == '@') { - str[place] = ' '; - return 1; - } - return 0; -} - -int AString::getexclamation() -{ - int place = 0; - while (place < len && (str[place] == ' ' || str[place] == '\t')) - place++; - if (place >= len) return 0; - if (str[place] == '!') { - str[place] = ' '; - return 1; - } - return 0; -} - -char islegal(char c) -{ - if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || - c=='!' || c=='[' || c==']' || c==',' || c=='.' || c==' ' || - c=='{' || c=='}' || c=='@' || c=='#' || c=='$' || c=='%' || - c=='^' || c=='&' || c=='*' || c=='-' || c=='_' || c=='+' || - c=='=' || c==';' || c==':' || c=='<' || c=='>' || c=='?' || - c=='/' || c=='~' || c=='\'' || c== '\\' || c=='`') - return 1; - return 0; -} - -AString *AString::getlegal() -{ - char * temp = new char[len+1]; - char * temp2 = temp; - int j = 0; - for (int i=0; i(val-back); i--) { - if (str[i] == ' ') { - str[i] = '\0'; - return new AString(&(str[i+1])); - } - } - AString * temp = new AString(&(str[val])); - str[val] = '\0'; - return temp; -} - -int AString::value() //this cannot handle negative numbers! -{ - int place = 0; - int ret = 0; - while ((str[place] >= '0') && (str[place] <= '9')) { - ret *= 10; - // Fix bug where int could be overflowed. - if (ret < 0) return 0; - ret += (str[place++] - '0'); - } - return ret; -} - -ostream & operator <<(ostream & os,const AString & s) -{ - os << s.str; - return os; -} - -istream & operator >>(istream & is,AString & s) -{ - char * buf = new char[256]; - is >> buf; - s.len = strlen(buf); - s.str = new char[s.len + 1]; - strcpy(s.str,buf); - delete buf; - return is; -} diff --git a/arcadia/astring.h b/arcadia/astring.h deleted file mode 100644 index c6077c6a9..000000000 --- a/arcadia/astring.h +++ /dev/null @@ -1,76 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef ASTRING_CLASS -#define ASTRING_CLASS - -#include -#include "alist.h" - -using namespace std; - -class AString : public AListElem { - friend ostream & operator <<(ostream &os, const AString &); - friend istream & operator >>(istream &is, AString &); -public: - - AString(); - AString(char *); - AString(const char *); - AString(int); - AString(unsigned int); - AString(char); - AString(const AString &); - ~AString(); - - int operator==(const AString &); - int operator==(char *); - int operator==(const char *); - int CheckPrefix(const AString &); - AString operator+(const AString &); - AString & operator+=(const AString &); - - AString & operator=(const AString &); - AString & operator=(const char *); - - char *Str(); - int Len(); - - AString *gettoken(); - int getat(); - int getexclamation(); - AString *getlegal(); - AString *Trunc(int, int back=30); - int value(); - AString *StripWhite(); - -private: - - int len; - int size; - char *str; - int isEqual(const char *); -}; - -#endif diff --git a/arcadia/battle1.cpp b/arcadia/battle1.cpp deleted file mode 100644 index b37bee586..000000000 --- a/arcadia/battle1.cpp +++ /dev/null @@ -1,1136 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "game.h" -#include "battle1.h" -#include "army1.h" -#include "formation1.h" -#include "gamedefs.h" -#include "gamedata.h" - -#ifndef DEBUG -//#define DEBUG -#endif -#ifndef DEBUG2 -//#define DEBUG2 -#endif - -BattlePtr::BattlePtr() -{ - ptr = 0; -} - -void Game::GetDFacs(ARegion * r,Unit * t,AList & facs) -{ - int AlliesIncluded = 0; - - // First, check whether allies should assist in this combat - if (Globals->ALLIES_NOAID == 0) { - AlliesIncluded = 1; - } else { - // Check whether any of the target faction's - // units aren't set to noaid - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->IsReallyAlive()) { - if (u->faction == t->faction && - !t->GetFlag(FLAG_NOAID)) { - AlliesIncluded = 1; - break; - } - } - if (AlliesIncluded == 1) break; // forlist(units) - } - if (AlliesIncluded == 1) break; // forlist (objects) - } - } - - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->IsReallyAlive()) { - if (u->faction == t->faction || - (AlliesIncluded == 1 && - u->guard != GUARD_AVOID && - u->GetAttitude(r,t) == A_ALLY)) { - if (!GetFaction2(&facs,u->faction->num)) { - FactionPtr * p = new FactionPtr; - p->ptr = u->faction; - facs.Add(p); - } - } - } - } - } -} - - -void Game::GetAFacs(ARegion *r, Unit *att, Unit *tar, AList &dfacs, - AList &afacs, AList &atts) -{ - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->canattack && u->IsReallyAlive()) { - int add = 0; - if ((u->faction == att->faction || - u->GetAttitude(r,tar) == A_HOSTILE) && - (u->guard != GUARD_AVOID || u == att)) { - add = 1; - } else { - if (u->guard == GUARD_ADVANCE && - u->GetAttitude(r,tar) != A_ALLY) { - add = 1; - } else { - if (u->attackorders) { - forlist(&(u->attackorders->targets)) { - UnitId * id = (UnitId *) elem; - Unit *t = r->GetUnitId(id, u->faction->num); - if (!t) continue; - if (t == tar) { - u->attackorders->targets.Remove(id); - delete id; - } - if(t->faction == tar->faction) add = 1; - } - } - } - } - - if (add) { - if (!GetFaction2(&dfacs,u->faction->num)) { - Location * l = new Location; - l->unit = u; - l->obj = obj; - l->region = r; - atts.Add(l); - if (!GetFaction2(&afacs,u->faction->num)) { - FactionPtr * p = new FactionPtr; - p->ptr = u->faction; - afacs.Add(p); - } - } - } - } - } - } -} - -int Game::CanAttack(ARegion * r,AList * afacs,Unit * u) { - int see = 0; - int ride = 0; - forlist(afacs) { - FactionPtr * f = (FactionPtr *) elem; - if (f->ptr->CanSee(r,u) == 2) { - if (ride == 1) return 1; - see = 1; - } - if (f->ptr->CanCatch(r,u)) { - if (see == 1) return 1; - ride = 1; - } - } - return 0; -} - -void Game::GetSides(ARegion *r, AList &afacs, AList &dfacs, AList &atts, - AList &defs, Unit *att, Unit *tar, int ass, int adv) -{ - att->crossbridge = 0; - tar->crossbridge = 0; - - if (ass) { - /* Assassination attempt */ - Location * l = new Location; - l->unit = att; - l->obj = r->GetDummy(); - l->region = r; - atts.Add(l); - - l = new Location; - l->unit = tar; - l->obj = r->GetDummy(); - l->region = r; - defs.Add(l); - - return; - } - - int j=NDIRS; - int noaida = 0, noaidd = 0; - for (int i=-1;i=0) { - r2 = r->neighbors[i]; - if (!r2) continue; - forlist(&r2->objects) { - /* Can't get building bonus in another region */ - ((Object *) elem)->capacity = 0; - } - } else { - forlist(&r2->objects) { - Object * o = (Object *) elem; - /* Set building capacity */ - if (o->incomplete < 1 && o->IsBuilding()) { - o->capacity = ObjectDefs[o->type].protect; - } - } - } - forlist (&r2->objects) { - Object * o = (Object *) elem; - forlist (&o->units) { - Unit * u = (Unit *) elem; - int add = 0; - u->crossbridge = 0; -#define ADD_ATTACK 1 -#define ADD_DEFENSE 2 - /* First, can the unit be involved in the battle at all? */ - if ((i==-1 || u->GetFlag(FLAG_HOLDING) == 0) && u->IsReallyAlive()) { - if (GetFaction2(&afacs,u->faction->num)) { - /* - * The unit is on the attacking side, check if the - * unit should be in the battle - */ - if (i == -1 || (!noaida)) { - if (u->canattack && - (u->guard != GUARD_AVOID || u==att) && - u->CanMoveTo(r2,r) && - !::GetUnit(&atts,u->num)) { - add = ADD_ATTACK; - } - } - } else { - /* The unit is not on the attacking side */ - /* - * First, check for the noaid flag; if it is set, - * only units from this region will join on the - * defensive side - */ - if (!(i != -1 && noaidd)) { - if (u->type == U_GUARD) { - /* The unit is a city guardsman */ - if (i == -1/* && adv == 0*/ && u->faction->ethnicity == tar->faction->ethnicity) - add = ADD_DEFENSE; - } else if(u->type == U_GUARDMAGE) { - /* the unit is a city guard support mage */ - if(i == -1/* && adv == 0*/ && u->faction->ethnicity == tar->faction->ethnicity) - add = ADD_DEFENSE; - } else { - /* - * The unit is not a city guardsman, check if - * the unit is on the defensive side - */ - if (GetFaction2(&dfacs,u->faction->num)) { - if (u->guard == GUARD_AVOID) { - /* - * The unit is avoiding, and doesn't - * want to be in the battle if he can - * avoid it - */ - if (u == tar || - (u->faction == tar->faction && - i==-1 && - CanAttack(r,&afacs,u))) { - add = ADD_DEFENSE; - } - } else { - /* - * The unit is not avoiding, and wants - * to defend, if it can - */ - if (u->CanMoveTo(r2,r)) { - add = ADD_DEFENSE; - } - } - } - } - } - } - } - - if (add == ADD_ATTACK) { - Location * l = new Location; - l->unit = u; - l->obj = o; - l->region = r2; - atts.Add(l); - } else if (add == ADD_DEFENSE) { - Location * l = new Location; - l->unit = u; - l->obj = o; - l->region = r2; - defs.Add(l); - } - } - } - // - // If we are in the original region, check for the noaid status of - // the units involved - // - if (i == -1) { - noaida = 1; - forlist (&atts) { - Location *l = (Location *) elem; - if (!l->unit->GetFlag(FLAG_NOAID)) { - noaida = 0; - break; - } - } - } - - noaidd = 1; - { - forlist (&defs) { - Location *l = (Location *) elem; - if (!l->unit->GetFlag(FLAG_NOAID)) { - noaidd = 0; - break; - } - } - } - } -} - -void Game::KillDead(Location * l) -{ - if (!l->unit->IsReallyAlive()) { - l->region->Kill(l->unit); //this deletes all non-mage units which are dead. Otherwise transfers items and moves to dummy region. - if(l->unit->dead) { //ie a mage. - //ARCADIA_MAGIC Patch - Faction *fac = GetFaction(&factions, ghostfaction); - if(fac) l->unit->faction = fac; - else { - l->unit->MoveUnit(0); //routine for destroying a unit, from ARegion::Kill() - l->region->hell.Add(l->unit); - } - } - } else { - if (l->unit->advancefrom) { - l->unit->MoveUnit( l->unit->advancefrom->GetDummy() ); - } - } -} - -int Game::RunBattle(ARegion * r,Unit * attacker,Unit * target,int ass, - int adv) -{ - AList afacs,dfacs; - AList atts,defs; - FactionPtr * p; - int result; - - if (ass) { - if(attacker->GetAttitude(r,target) == A_ALLY) { - attacker->Error("ASSASSINATE: Can't assassinate an ally."); - return BATTLE_IMPOSSIBLE; - } - /* Assassination attempt */ - p = new FactionPtr; - p->ptr = attacker->faction; - afacs.Add(p); - p = new FactionPtr; - p->ptr = target->faction; - dfacs.Add(p); - } else { - if( r->IsSafeRegion() ) { - attacker->Error("ATTACK: No battles allowed in safe regions."); - return BATTLE_IMPOSSIBLE; - } - if(attacker->GetAttitude(r,target) == A_ALLY) { - attacker->Error("ATTACK: Can't attack an ally."); - return BATTLE_IMPOSSIBLE; - } - GetDFacs(r,target,dfacs); - if (GetFaction2(&dfacs,attacker->faction->num)) { - attacker->Error("ATTACK: Can't attack an ally."); - return BATTLE_IMPOSSIBLE; - } - GetAFacs(r,attacker,target,dfacs,afacs,atts); - } - GetSides(r,afacs,dfacs,atts,defs,attacker,target,ass,adv); - - if(atts.Num() <= 0) { - // This shouldn't happen, but just in case - Awrite(AString("Cannot find any attackers!")); - return BATTLE_IMPOSSIBLE; - } - if(defs.Num() <= 0) { - // This shouldn't happen, but just in case - Awrite(AString("Cannot find any defenders!")); - return BATTLE_IMPOSSIBLE; - } - - Battle * b = new Battle(r); - b->WriteSides(r,attacker,target,&atts,&defs,ass, ®ions ); - - battles.Add(b); - forlist(&factions) { - Faction * f = (Faction *) elem; - if (GetFaction2(&afacs,f->num) || GetFaction2(&dfacs,f->num) || - r->Present(f)) { - BattlePtr * p = new BattlePtr; - p->ptr = b; - f->battles.Add(p); - } - } - - result = b->Run(r,attacker,&atts,target,&defs,ass, ®ions ); - /* Remove all dead units */ -#ifdef DEBUG -Awrite("Killing attackers"); -#endif - { - forlist(&atts) { - KillDead((Location *) elem); - } - } -#ifdef DEBUG -Awrite("Killing defenders"); -#endif - { - forlist(&defs) { - KillDead((Location *) elem); - } - } -#ifdef DEBUG -Awrite("Battle all run"); -#endif - return result; -} - -Battle::Battle(ARegion *r) -{ - asstext = 0; - region = r; - casualties = 0; -} - -Battle::~Battle() -{ - #ifdef DEBUG - Awrite("Battle Destructor"); - #endif - - if (asstext) delete asstext; - text.DeleteAll(); - - #ifdef DEBUG - Awrite("End of Battle Destructor"); - #endif -} - -int Battle::Run( ARegion * region, - Unit * att, - AList * atts, - Unit * tar, - AList * defs, - int ass, - ARegionList *pRegs ) -{ -#ifdef DEBUG -Awrite("battles 1"); -#endif - - Army * armies[2]; - AString temp; - assassination = ASS_NONE; - attacker = att->faction; - - int amts = 0; - if(ass > 1) { - ass = 1; //setting it back to 1 - set to 2 earlier for proportional AMTS usage, but no longer used. - amts = 1; - } - - armies[0] = new Army(att,atts,region->type,2*ass); //ass = 2 for attacker, 1 for defender. This is used for armour selection. - -#ifdef DEBUG -Awrite("battles 2"); -#endif - - armies[1] = new Army(tar,defs,region->type,ass); -#ifdef DEBUG2 -Awrite("battles 2.1"); -#endif - if(!ass) { - WriteTerrainMessage(region->type); -#ifdef DEBUG2 -Awrite("battles 2.2"); -#endif - WriteAggressionMessage(armies[0],armies[1]); -#ifdef DEBUG2 -Awrite("battles 2.3"); -#endif - armies[0]->DoEthnicMoraleEffects(this); -#ifdef DEBUG2 -Awrite("battles 2.4"); -#endif - armies[1]->DoEthnicMoraleEffects(this); - } - -#ifdef DEBUG -Awrite("battles 3"); -#endif - - int round = 1; - while (!armies[0]->Broken() && !armies[1]->Broken() && round < 26) { - NormalRound(round++,armies[0],armies[1],region->type, 0,0,ass); - } - -#ifdef DEBUG -Awrite("battles 4"); -#endif - - if ((armies[0]->Broken() && !armies[1]->Broken()) || - (!armies[0]->NumAlive() && armies[1]->NumAlive())) { - if (ass) assassination = ASS_FAIL; - - if (armies[0]->NumAlive()) { - AddLine(*(armies[0]->pLeader->name) + " is routed!"); - NormalRound(round++,armies[0],armies[1],region->type,1); - } else { - AddLine(*(armies[0]->pLeader->name) + " is destroyed!"); - } - AddLine("Total Casualties:"); - - ItemList *spoils = new ItemList; - int loserdead = armies[0]->Lose(this, spoils); - GetSpoils(atts, spoils, ass); - if (spoils->Num()) { - temp = AString("Spoils: ") + spoils->Report(2,0,1) + "."; - } else { - temp = "Spoils: none."; - } -#ifdef DEBUG -Awrite("battles 5"); -#endif - armies[1]->Win(this, spoils, loserdead); //change the Win function for better spoils handling -// AddLine(""); - AddLine(temp); - AddLine(""); - delete spoils; - //soldiers seem to have already been deleted in win/lose/tie methods - delete armies[0]; - delete armies[1]; -#ifdef DEBUG -Awrite("returning loss"); -#endif - return BATTLE_LOST; - } - -#ifdef DEBUG -Awrite("battles 6"); -#endif - - if ((armies[1]->Broken() && !armies[0]->Broken()) || - (!armies[1]->NumAlive() && armies[0]->NumAlive())) { - if (ass) { - assassination = ASS_SUCC; - asstext = new AString(*(armies[1]->pLeader->name) + - " is assassinated in " + - region->ShortPrint( pRegs ) + - "!"); - } - if (armies[1]->NumAlive()) { - AddLine(*(armies[1]->pLeader->name) + " is routed!"); - NormalRound(round++,armies[0],armies[1],region->type,2); - } else { - AddLine(*(armies[1]->pLeader->name) + " is destroyed!"); - } -#ifdef DEBUG -Awrite("battles 7"); -#endif - AddLine("Total Casualties:"); - ItemList *spoils = new ItemList; - int loserdead = armies[1]->Lose(this, spoils, ass); //dead soldiers are removed from units here, and skills lost. - GetSpoils(defs, spoils, ass+amts); //spoils allocated according to u->GetMen() and u->losses. - if (spoils->Num()) { - temp = AString("Spoils: ") + spoils->Report(2,0,1) + "."; - } else { - temp = "Spoils: none."; - } - armies[0]->Win(this, spoils, loserdead); -// AddLine(""); - AddLine(temp); - AddLine(""); - - delete spoils; - delete armies[0]; - delete armies[1]; -#ifdef DEBUG -Awrite("returning won"); -#endif - return BATTLE_WON; - } -#ifdef DEBUG -Awrite("battles 8"); -#endif - AddLine("The battle ends indecisively."); - AddLine(""); - AddLine("Total Casualties:"); - armies[0]->Tie(this); - armies[1]->Tie(this); - temp = "Spoils: none."; - AddLine(""); - AddLine(temp); - AddLine(""); -#ifdef DEBUG -Awrite("battles 8.5"); -#endif - delete armies[0]; -#ifdef DEBUG -Awrite("battles 9"); -#endif - delete armies[1]; -#ifdef DEBUG -Awrite("returning draw"); -#endif - return BATTLE_DRAW; -} - -void Battle::NormalRound(int round,Army * armya,Army * armyb, int regtype, int bias, int ambush, int ass) -{ - /* Write round header */ - AddLine(AString("Round ") + round + ":"); - /* Initialize variables */ - armya->round++; - armyb->round++; - /* Setup Formations */ - FormationsPhase(armya,armyb,regtype,bias, ambush, ass); - armya->Reset(); - armyb->Reset(); - int aalive = armya->NumAlive(); - int aialive = aalive; - int balive = armyb->NumAlive(); - int bialive = balive; - int aatt = armya->CanAttack(); - int batt = armyb->CanAttack(); - /* Run attacks until done */ -#ifdef DEBUG -Awrite("Doing attacks"); -#endif - while (aalive && balive && (aatt || batt)) - { - int num = getrandom(aatt + batt); - if (num >= aatt) - { - num -= aatt; - Soldier * s = armyb->GetAttacker(num); //this decrements the canattack, and swops the attacker into the cannot attack section of the formation. - DoAttack(armyb->round, s, armyb, armya); - } - else - { - Soldier * s = armya->GetAttacker(num); - DoAttack(armya->round, s, armya, armyb); - } - aalive = armya->NumAlive(); - balive = armyb->NumAlive(); - aatt = armya->CanAttack(); - batt = armyb->CanAttack(); -#ifdef DEBUG -AddLine(AString("Attacks left: ") + aatt + " - " + batt); -#endif - } -#ifdef DEBUG -Awrite("Done attacks"); -#endif - /* Finish round */ - armya->Regenerate(this); - armyb->Regenerate(this); - aialive -= aalive; - AddLine(*(armya->pLeader->name) + " loses " + aialive + "."); - bialive -= balive; - AddLine(*(armyb->pLeader->name) + " loses " + bialive + "."); - AddLine(""); -#ifdef DEBUG -Awrite("Done round"); -#endif -} - -void Battle::DoAttack(int round, Soldier *a, Army *attackers, Army *def, int ass) //'attackers' is the army the soldier is from. -{ //ass no longer used here -#ifdef DEBUG2 -cout << a->unit->num; -#endif - DoSpecialAttack(round, a, attackers, def); -#ifdef DEBUG2 -cout << "."; -#endif - if (!def->NumAlive()) return; - - if (a->riding != -1) { - MountType *pMt = FindMount(ItemDefs[a->riding].abr); - // This does mount special attack. Adjust it so cannot behind formations cannot hit non-engaged formations (ie its not ranged) - if(pMt->mountSpecial != NULL) { - int i, num, tot = -1; - SpecialType *spd = FindSpecial(pMt->mountSpecial); - for(i = 0; i < 4; i++) { - int times = spd->damage[i].value; - if(spd->effectflags & SpecialType::FX_USE_LEV) - times *= pMt->specialLev; - int realtimes = spd->damage[i].minnum + getrandom(times) + - getrandom(times); - num = def->DoAnAttack(pMt->mountSpecial, realtimes, a->race, - spd->damage[i].type, pMt->specialLev, - spd->damage[i].flags, spd->damage[i].dclass, - spd->damage[i].effect, 0, attackers, a->inform, this); - if(num != -1) { - if(tot == -1) tot = num; - else tot += num; - } - } - if(tot != -1) { - AddLine(a->name + " " + spd->spelldesc + ", " + - spd->spelldesc2 + tot + spd->spelltarget + "."); - } - } - } - if(!def->NumAlive()) return; - - int numAttacks = a->attacks; - if(a->attacks < 0) { - if(round % ( -1 * a->attacks ) == 0) //This used to be 1 (ie xbow attacks in round 1,3,5. Setting it to zero means xbow attacks in rounds 2,4,6) - numAttacks = 1; - else - numAttacks = 0; - } else if(ass && (Globals->MAX_ASSASSIN_FREE_ATTACKS > 0) && - (numAttacks > Globals->MAX_ASSASSIN_FREE_ATTACKS)) { - numAttacks = Globals->MAX_ASSASSIN_FREE_ATTACKS; - } - - int strength = 1; - int frenzy = 0; - if((ItemDefs[a->race].type & IT_MAN)) frenzy = a->unit->GetSkill(S_FRENZY); //used to upgrade attack below - if(frenzy > 1) strength = frenzy; - - int kills = 0; - - for (int i = 0; i < numAttacks; i++) { - WeaponType *pWep = NULL; - if(a->weapon != -1) - pWep = FindWeapon(ItemDefs[a->weapon].abr); - - int flags = 0; - int attackType = a->attacktype; //this is set to weapon attack type in soldier::soldier - int mountBonus = 0; - int attackClass = SLASHING; - if(pWep) { - flags = pWep->flags; - mountBonus = pWep->mountBonus; - attackClass = pWep->weapClass; - } - - - if(frenzy) { //upgrade attack type by 1. - if(attackClass != ARMORPIERCING) attackClass = ARMORPIERCING; - else attackClass = NUM_WEAPON_CLASSES; - } - - kills += def->DoAnAttack(NULL, 1, a->race, attackType, a->askill, flags, attackClass, - NULL, mountBonus, attackers, a->inform, this, strength); -#ifdef DEBUG2 -cout << "."; -#endif - if (!def->NumAlive()) break; - } - - if(frenzy) AddLine(AString(*a->unit->name) + " attacks with unholy strength, killing " + kills); -} - -void Battle::FormationsPhase(Army * armya, Army * armyb, int regtype, int bias, int ambush, int ass) -{ -//This section is responsible for most of the interactions between formations. -//The remaining few are handled in Army::GetMidRoundTarget based on the engagement -//table set up in this section. -//Formations have four engagement levels to other formations. -//ENGAGED_ENGAGED: Formations is actively engaged in melee combat with its target -//ENGAGED_TRYATTACK: If it becomes free, it would like to attack this target. If -//the soldier in question is ranged, it will do so without engaging, if melee AND -//the formation is behind 0, it will engage. This does not have relevance for -//flank 0 and 1 formations, as they will flank rather than engage a tryattack. -//ENGAGED_CANATTACK: Formation doesn't particularly want to engage this target, -//but it is able to if it runs out of enemies classified higher. This has meaning only for -//flank 2 formations and reserves, but is set anyway for all. -//ENGAGED_CONDITIONAL: If the enemy is engaged, this counts as ENGAGED_CANATTACK. Else -//it counts as ENGAGED_NONE. (ie can catch enemy only if they are already engaged). -//ENGAGED_NONE: Formation is not able to engage the target in melee combat. This has -//meaning only for flank 2 formations, but is set anyway for others. - -//Formation setup reminder: -//Formation 0-5 are flank 0 (form_front). Formation 6-11 are flank 1 (form_flanking). -//Formations 12-17 are flank 2 (form_flanked). Formation 18 is dead. -//In the current setup, behind formations will not try to flank, and thus 6 formations -//will always be empty. However, they are included because it might be a nice -//future addition if behind formations can flank in order to target enemy -//behind formations in their "tryattack list". - -//Basic structure: formation[0] is the foot frontlines, and will always try to engage an -//enemy. #s 2 and 4 are fron cavalry, who are in reserve. -//For now, #s 1, 3 and 5 will always stay flank 0 behind 1, these are discriminated between only -//by their ability to be caught. The players always has the FIGHTAS command to merge -//them. -//Units which try to flank will be intercepted by enemy reserves if they can be caught by -//them. Reserves will fight all flanking enemies, then fight all flanked enemies, then go -//back to doing nothing unless there are no non-behind/reserve enemies left to defend against, -//in which case they will come out of reserve and try to find a target. -//If a unit gets through enemy reserves either because (a) there are none, (b) they -//can't catch the unit, or (c) the flanking unit is concealed, then it will become "flanked" -//and select a target to engage - usually a behind enemy. Once it is flanked, it can always -//be caught. - - -#ifdef DEBUG -Awrite("Updating Shields"); -#endif - // Update both army's shields - armya->shields.DeleteAll(); - armyb->shields.DeleteAll(); - UpdateShields(armya, armyb); - UpdateShields(armyb, armya); - - // Reset engagement table (tryattack/canattack to zero) - armya->ResetEngagements(); - armyb->ResetEngagements(); - -#ifdef DEBUG -Awrite("Updating Round Spells"); -#endif - //Darkness, Fog and Concealment - UpdateRoundSpells(armya,armyb); - - if(ass) { - armya->AssignFrontTargets(this, armyb, 1); - return; - } - - //bias is the army which is penalised. - if(bias == 1) armya->PenaltyToHit(1); - if(bias == 2) armyb->PenaltyToHit(1); - -#ifdef DEBUG -Awrite("Sorting Armies"); -#endif - //Sort armies if in first round - if(armya->round == 1) armya->SortFormations(this, regtype); - if(armyb->round == 1+ambush) armyb->SortFormations(this, regtype); - - WriteBattleSituation(armya,armyb); - - //mirror any engagements that occured last round - armya->MirrorEngagements(armyb); - armyb->MirrorEngagements(armya); -#ifdef DEBUG -Awrite("Flanking"); -#endif - //If formation is engaged,return. - //If flank 1, move everyone to flank 2. - armya->FlankFlankers(this, armyb); - armyb->FlankFlankers(this, armya); - - //if Formation[0] unengaged: attack enemy flank 2s, then form[0], then flank (cannot catch - //any flank 1 enemies except form 6, and enemy form 6 is empty until our form 0 is overwhelmed). - armya->AssignFrontTargets(this, armyb); - armyb->AssignFrontTargets(this, armya); - -#ifdef DEBUG -Awrite("Overwhelming"); -#endif - //split overwhelming flank 0 formations. if concealed, go straight to flank 2 - if(!(TerrainDefs[regtype].flags & TerrainType::RESTRICTEDFOOT) ) { - if(bias != 1) armya->SplitOverwhelmingFrontFormations(this,armyb); - if(bias != 2) armyb->SplitOverwhelmingFrontFormations(this,armya); - } - - //choose if reserves flank - //flank choice - //if concealed, flank 0 goes straight to flank 2. Otherwise, soldiers get added to - //flank 1 formations. - if(bias != 1) armya->FlyingReservesMayFlank(this, armyb); - if(bias != 2) armyb->FlyingReservesMayFlank(this, armya); - - if(bias != 1) armya->RidingReservesMayFlank(this, armyb); - if(bias != 2) armyb->RidingReservesMayFlank(this, armya); - -#ifdef DEBUG -Awrite("Setting CanAttack"); -#endif - //canattack lists - armya->SetCanAttack(armyb); - armyb->SetCanAttack(armyb); - -//armya->WriteEngagements(this); - - //reserves intercept flankers - armya->ReservesIntercept(armyb); - armyb->ReservesIntercept(armya); - - //split overwhelming flank 1 formations - //any formation with sufficiently more troops than are engaging it can send some to - //flank around the enemy. Any unengaged formation will also flank. Hence, this must - //be placed after reserves have a chance to intercept flank 1s, and effectively pushes - //flank 1s to flank 2 if they do not get intercepted. - //If foot are restricted, they cannot flank here. - if(bias != 1) armya->SplitOverwhelmingFlankingFormations(this,armyb,regtype); //need to modify so foot don't flank in restricted terrain. - if(bias != 2) armyb->SplitOverwhelmingFlankingFormations(this,armya,regtype); - - //flank 2s engage & get combat bonus if appropriate (as tempbonus). - //second choice of target (if any) is set as tryattack, or first choice if no men in the formation. - armya->FlankersEngage(this, armyb); - armyb->FlankersEngage(this, armya); - //assign ranged tryattack lists (can call getmidroundrangedtarget) - armya->AssignRangedTargets(armyb); - armyb->AssignRangedTargets(armya); - -#ifdef DEBUG -Awrite("Clearing Empty Engagements"); -#endif - //Clear engagement table for empty formations - if people move during battle, they'll inherit the old specifics. - armya->ClearEmptyEngagements(); - armyb->ClearEmptyEngagements(); - - armya->SetTemporaryBonuses(armyb); - armyb->SetTemporaryBonuses(armya); -//armya->WriteEngagements(this); -} - -void Battle::GetSpoils(AList * losers, ItemList *spoils, int ass) -{ - forlist(losers) { - Unit * u = ((Location *) elem)->unit; - int numalive = u->GetSoldiers(); - int numdead = u->losses; - if(ass && numdead == 0) { - numdead++; //assassinations with resurrected targets still get spoils. - numalive --; - } - forlist(&u->items) { - Item * i = (Item *) elem; - if(IsSoldier(i->type)) continue; - // New rule: Assassins with RINGS cannot get AMTS in spoils - // This rule is only meaningful with Proportional AMTS usage - // is enabled, otherwise it has no effect. - if((ass == 2) && (i->type == I_AMULETOFTS)) continue; - float percent = (float)numdead/(float)(numalive+numdead); - int num = (int)(i->num * percent); - int num2 = (num + getrandom(2))/2; - //if some types of items should never be lost, set num2 = num here for those item types. - if(ItemDefs[i->type].flags & ItemType::NEVERLOST) num2 = num; - spoils->SetNum(i->type, spoils->GetNum(i->type) + num2); - u->items.SetNum(i->type, i->num - num); - } - } -} - -void Battle::WriteSides(ARegion * r, Unit * att, Unit * tar, AList * atts, - AList * defs, int ass, ARegionList *pRegs ) -{ - if (ass) { - AddLine(*att->name + " attempts to assassinate " + *tar->name - + " in " + r->ShortPrint( pRegs ) + "!"); - } else { - AddLine(*att->name + " attacks " + *tar->name + " in " + - r->ShortPrint( pRegs ) + "!"); - } - AddLine(""); - - int dobs = 0; - int aobs = 0; - { - forlist(defs) { - int a = ((Location *)elem)->unit->GetAttribute("observation"); - if(a > dobs) dobs = a; - } - } - - AddLine("Attackers:"); - { - forlist(atts) { - int a = ((Location *)elem)->unit->GetAttribute("observation"); - if(a > aobs) aobs = a; - AString * temp = ((Location *) elem)->unit->BattleReport(dobs); - AddLine(*temp); - delete temp; - } - } - AddLine(""); - AddLine("Defenders:"); - { - forlist(defs) { - AString * temp = ((Location *) elem)->unit->BattleReport(aobs); - AddLine(*temp); - delete temp; - } - } - AddLine(""); -} - -void Battle::WriteTerrainMessage(int regtype) -{ - AString temp; - int terrainflags = TerrainDefs[regtype].flags; - if ((terrainflags & TerrainType::FLYINGMOUNTS) && (terrainflags & TerrainType::RIDINGMOUNTS)) { - if (!(terrainflags & TerrainType::FLYINGLIMITED) && !(terrainflags & TerrainType::RIDINGLIMITED)) - temp = "The terrain allows riding and flying."; - else if (!(terrainflags & TerrainType::FLYINGLIMITED) && (terrainflags & TerrainType::RIDINGLIMITED)) - temp = "The terrain allows flying and limited riding. Riding soldiers do not receive a combat bonus due to their riding skill."; - else if ((terrainflags & TerrainType::FLYINGLIMITED) && !(terrainflags & TerrainType::RIDINGLIMITED)) - temp = "The terrain allows riding and limited flying. Flying soldiers do not receive a combat bonus due to their riding skill."; - else - temp = "The terrain allows limited riding and limited flying. Soldiers do not receive a combat bonus due to their riding skill."; - } else if (terrainflags & TerrainType::FLYINGMOUNTS) { - if (terrainflags & TerrainType::FLYINGLIMITED) - temp = "The terrain allows limited flying. Flying soldiers do not receive a combat bonus due to their riding skill. Riding soldiers are forced to fight on foot."; - else temp = "The terrain allows flying but not riding. All riding soldiers fight on foot."; - } else if (terrainflags & TerrainType::RIDINGMOUNTS) { - if (terrainflags & TerrainType::RIDINGLIMITED) - temp = "The terrain allows limited riding. Flying soldiers are forced to ride on the ground. Mounted soldiers do not receive a combat bonus due to their riding skill."; - else temp = "The terrain allows riding but not flying. All flying soldiers ride on the ground."; - } else { - temp = "The terrain does not allow riding or flying. Mounted soldiers are forced to fight on foot."; - } - /*Xanaxino mod*/ -// if(regtype == R_JUNGLE || regtype == R_FOREST) temp += " In addition, elven soldiers gain +1 to all defences."; - - AddLine(temp); - AddLine(""); -} - -void Battle::WriteAggressionMessage(Army *a, Army *b) -{ - if(a->pLeader->tactics == TACTICS_AGGRESSIVE) AddLine(*(a->pLeader->name) + " fights aggressively."); - if(a->pLeader->tactics == TACTICS_DEFENSIVE) AddLine(*(a->pLeader->name) + " fights defensively."); - if(b->pLeader->tactics == TACTICS_AGGRESSIVE) AddLine(*(b->pLeader->name) + " fights aggressively."); - if(b->pLeader->tactics == TACTICS_DEFENSIVE) AddLine(*(b->pLeader->name) + " fights defensively."); - AddLine(""); -} - -void Battle::TransferMessages(Army *a, Army *b) -{ - forlist(&a->armytext) { - AString *temp = (AString *) elem; - AddLine(*temp); - } - a->armytext.DeleteAll(); - forlist_reuse(&b->armytext) { - AString *temp = (AString *) elem; - AddLine(*temp); - } - b->armytext.DeleteAll(); -} - -void Battle::AddLine(const AString & s) -{ - #ifdef DEBUG - Awrite(s); - #endif - AString * temp = new AString(s); - text.Add(temp); -} - -void Battle::Report(Areport * f,Faction * fac) { - if (assassination == ASS_SUCC && fac != attacker) { - f->PutStr(*asstext); - f->PutStr(""); - return; - } - forlist(&text) { - AString * s = (AString *) elem; - f->PutStr(*s); - } -} - -void Battle::WriteBattleSituation(Army *armya, Army *armyb) -{ - //flanked cavalry ranged flanked air - //reserve cavalry flanked foot reserve air - //flanking cavalry front+fl flanking air - AddLine("The Battle Position:"); - AString temp; - temp = *(armya->pLeader->name); - int length = temp.Len(); - int spaces = 22 - (length/2); - temp = ""; - while(spaces-- > 0) temp += " "; - temp += *(armya->pLeader->name); - AddLine(temp); - - temp = " "; - temp += WriteBattleFormation('C', '*', armyb->formations[14].GetSize()); - temp += WriteBattleFormation('R', '#', armya->formations[1].GetSize() + armya->formations[3].GetSize() + armya->formations[5].GetSize()); - temp += WriteBattleFormation('A', '*', armyb->formations[16].GetSize()); - AddLine(temp); - temp = " "; - temp += WriteBattleFormation('C', '#', armya->formations[2].GetSize()); - temp += WriteBattleFormation('I', '*', armyb->formations[12].GetSize()); - temp += WriteBattleFormation('A', '#', armya->formations[4].GetSize()); - AddLine(temp); - temp = " "; - temp += WriteBattleFormation('C', '#', armya->formations[8].GetSize()); - temp += WriteBattleFormation('I', '#', armya->formations[0].GetSize() + armya->formations[6].GetSize()); - temp += WriteBattleFormation('A', '#', armya->formations[10].GetSize()); - AddLine(temp); - temp = " "; - temp += WriteBattleFormation('C', '*', armyb->formations[8].GetSize()); - temp += WriteBattleFormation('I', '*', armyb->formations[0].GetSize() + armyb->formations[6].GetSize()); - temp += WriteBattleFormation('A', '*', armyb->formations[10].GetSize()); - AddLine(temp); - temp = " "; - temp += WriteBattleFormation('C', '*', armyb->formations[2].GetSize()); - temp += WriteBattleFormation('I', '#', armya->formations[12].GetSize()); - temp += WriteBattleFormation('A', '*', armyb->formations[4].GetSize()); - AddLine(temp); - temp = " "; - temp += WriteBattleFormation('C', '#', armya->formations[14].GetSize()); - temp += WriteBattleFormation('R', '*', armyb->formations[1].GetSize() + armyb->formations[3].GetSize() + armyb->formations[5].GetSize()); - temp += WriteBattleFormation('A', '#', armya->formations[16].GetSize()); - AddLine(temp); - temp = *(armyb->pLeader->name); - length = temp.Len(); - spaces = 22 - (length/2); - temp = ""; - while(spaces-- > 0) temp += " "; - temp += *(armyb->pLeader->name); - AddLine(temp); -} - -AString Battle::WriteBattleFormation(char f, char g, int size) -{ - AString temp; - if(size<1) { - temp = " "; - return temp; - } - temp = AString(f) + g + ": " + size; - - while(size < 100000) { - temp += " "; - size *= 10; - } - return temp; -} - diff --git a/arcadia/battle1.h b/arcadia/battle1.h deleted file mode 100644 index fe8d7e595..000000000 --- a/arcadia/battle1.h +++ /dev/null @@ -1,103 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef BATTLE_CLASS -#define BATTLE_CLASS - -class Battle; - -#include "astring.h" -#include "alist.h" -#include "fileio.h" -#include "army1.h" -#include "items.h" - -enum { - ASS_NONE, - ASS_SUCC, - ASS_FAIL -}; - -enum { - BATTLE_IMPOSSIBLE, - BATTLE_LOST, - BATTLE_WON, - BATTLE_DRAW -}; - -class BattlePtr : public AListElem -{ - public: - BattlePtr(); - Battle * ptr; -}; - -class Battle : public AListElem -{ - public: - Battle(ARegion *); - ~Battle(); - - int Run(ARegion *, Unit *, AList *, Unit *, AList *, int ass, - ARegionList *pRegs); - void NormalRound(int round,Army *,Army *,int regtype, int bias = 0, int ambush=0, int assassination=0); - void DoAttack(int round, Soldier *a, Army *attackers, Army *def, - int ass = 0); - void FormationsPhase(Army * a, Army * b, int regtype, int bias, int ambush, int ass); /// - - void GetSpoils(AList *,ItemList *, int); - - // - // These functions should be implemented in specials.cpp - // - void UpdateShields(Army *a, Army *enemy); - void DoBinding(Army *att, Army *def); - void UpdateRoundSpells(Army * a, Army * b); - int GetRoundSpellLevel(Army *a, Army *b, int type, int spell, int antispell); - void DoSpecialAttack( int round, Soldier *a, Army *attackers, Army *def); - - void WriteSides(ARegion *,Unit *,Unit *,AList *,AList *,int, - ARegionList *pRegs ); - - void WriteTerrainMessage(int regtype); - void WriteAggressionMessage(Army *a, Army *b); - void TransferMessages(Army *a, Army *b); - void AddLine(const AString &); - void Report(Areport *,Faction *); - - void WriteBattleSituation(Army *a, Army *b); - AString WriteBattleFormation(char f, char g, int size); - - int assassination; - Faction * attacker; /* Only matters in the case of an assassination */ - AString * asstext; - AList text; - - //Used for statistics / times reports - ARegion *region; - int casualties; - -}; - -#endif diff --git a/arcadia/economy.cpp b/arcadia/economy.cpp deleted file mode 100644 index 59a021022..000000000 --- a/arcadia/economy.cpp +++ /dev/null @@ -1,1791 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include -#include -#include "game.h" -#include "gamedata.h" - -/* TownType */ - -int TownInfo::TownType() -{ - if (pop < 1000*Globals->POP_LEVEL) return TOWN_VILLAGE; - if (pop < 2000*Globals->POP_LEVEL) return TOWN_TOWN; - return TOWN_CITY; -} - -int ARegion::Population() -{ - if (town) { - return population + town->pop; - } else { - return population; - } -} - -void ARegion::WagesFromDevelopment() -{ - // Calculate new wages - wages = 0; - if (Population() == 0) return; - int level = 1; - int last = 0; - int dv = Development(); - while (dv >= level) { - wages++; - last = level; - level += wages+1; - } - wages *= 10; - if (dv > last) - wages += 10 * (dv - last) / (level - last); -} - -int ARegion::Wages() -{ - int retval; - if (Globals->PLAYER_ECONOMY) { - WagesFromDevelopment(); - retval = (int) wages/10; - } else { - retval = wages; - if (town) { - // hack, assumes that TownType + 1 = town wages - retval = retval + town->TownType() + 1; - } - // AS - if (CountConnectingRoads() > 1) retval++; - - // Check Lake Wage Effect - if(LakeEffect()) retval++; - } - - if (earthlore) retval++; - if (clearskies) retval++; - return retval; -} - -int ARegion::LakeEffect() -{ - int raise = 0; - if (Globals->LAKE_WAGE_EFFECT != GameDefs::NO_EFFECT) { - int adjlake = 0; - for (int d = 0; d < NDIRS; d++) { - ARegion *check = neighbors[d]; - if(!check) continue; - if(check->type == R_LAKE) adjlake++; - } - if (adjlake > 0) { - // If lakes affect everything around them - if (Globals->LAKE_WAGE_EFFECT & GameDefs::ALL) - raise = 1; - if (TerrainDefs[type].similar_type != R_PLAIN) { - // If lakes affect towns, but only in non-plains - if ((Globals->LAKE_WAGE_EFFECT & - GameDefs::NONPLAINS_TOWNS_ONLY) && town) - raise = 1; - // If lakes affect all towns - if ((Globals->LAKE_WAGE_EFFECT & GameDefs::TOWNS) && town) - raise = 1; - // If lakes affect any non plains terrain - if (Globals->LAKE_WAGE_EFFECT & GameDefs::NONPLAINS) - raise = 1; - // If lakes affect only desert - if((Globals->LAKE_WAGE_EFFECT & GameDefs::DESERT_ONLY) && - (TerrainDefs[type].similar_type == R_DESERT)) - raise = 1; - } else { - // If lakes affect any town, even those in plains - if ((Globals->LAKE_WAGE_EFFECT & GameDefs::TOWNS) && town) - raise = 1; - } - } - } - return raise; -} - -AString ARegion::WagesForReport() -{ - Production *p = products.GetProd(I_SILVER, -1); - if (p) { - if (Globals->PLAYER_ECONOMY) { - return AString("$") + (p->productivity / 10) + - "." + (p->productivity % 10) + " (Max: $" + p->amount + ")"; - } else { - return AString("$") + p->productivity + " (Max: $" + p->amount + ")"; - } - } else - return AString("$") + 0; -} - -void ARegion::SetupPop() -{ - - TerrainType *typer = &(TerrainDefs[type]); - habitat = typer->pop+1; - if (habitat < 100) habitat = 100; - habitat *= Globals->POP_LEVEL; - - int pop = typer->pop*Globals->POP_LEVEL; - int mw = typer->wages; - - // fix economy when MAINTENANCE_COST has been adjusted - mw += Globals->MAINTENANCE_COST - 10; - if (mw < 0) mw = 0; - - if (pop == 0) { - population = 0; - basepopulation = 0; - wages = 0; - maxwages = 0; - money = 0; - if(typer->similar_type == R_OCEAN) race = I_MERMEN; - - /* - if(Globals->PLAYER_ECONOMY) { - // All regions need silver production - // even if no income can be gained - Production *p = new Production; - p->itemtype = I_SILVER; - p->amount = 0; - p->skill = -1; - p->productivity = 0; - products.Add(p); - - p = new Production; - p->itemtype = I_SILVER; - p->amount = 0; - p->skill = S_ENTERTAINMENT; - p->productivity = Globals->ENTERTAIN_INCOME; - products.Add(p); - } - */ - - return; - } - // Only select race here if it hasn't been set during Race Growth - // in the World Creation process. - if ((race == -1) || (!Globals->GROW_RACES)) { - int noncoastalraces = sizeof(typer->races)/sizeof(int); - int allraces = - noncoastalraces + sizeof(typer->coastal_races)/sizeof(int); - - race = -1; - while (race == -1 || (ItemDefs[race].flags & ItemType::DISABLED)) { - int n = getrandom(IsCoastal() ? allraces : noncoastalraces); - if(n > noncoastalraces-1) { - race = typer->coastal_races[n-noncoastalraces-1]; - } else - race = typer->races[n]; - } - } - if(Globals->PLAYER_ECONOMY) { - if(Globals->RANDOM_ECONOMY) habitat = habitat * 2/3 + getrandom(habitat/3); - ManType *mt = FindRace(ItemDefs[race].abr); - if (mt->terrain == typer->similar_type) { - habitat = (habitat * 9)/8; - } - if (!IsNativeRace(race)) { - habitat = (habitat * 4)/5; - } - basepopulation = habitat; - // hmm... somewhere not too far off equilibrium pop - population = habitat * 66 / 100; - } else { - if(Globals->RANDOM_ECONOMY) { - population = (pop + getrandom(pop)) / 2; - } else { - population = pop; - } - basepopulation = population; - } - // Setup wages - if(Globals->PLAYER_ECONOMY) { - int level = 1; - development = 1; - int prev = 0; - while (level < mw) { - development++; - prev++; - if(prev > level) { - level++; - prev = 0; - } - } - if(Globals->RANDOM_ECONOMY) { - development += getrandom(36); - } - } else { - if(Globals->RANDOM_ECONOMY) { - mw += getrandom(3); - } - wages = mw; - maxwages = mw; - } - if(Globals->TOWNS_EXIST) { - int adjacent = 0; - int prob = Globals->TOWN_PROBABILITY; - if (prob < 1) prob = 100; - int townch = (int) 80000 / prob; - if (Globals->TOWNS_NOT_ADJACENT) { - for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = neighbors[d]; - if ((newregion) && (newregion->town)) adjacent++; - } - } - if(Globals->LESS_ARCTIC_TOWNS) { - int dnorth = GetPoleDistance(D_NORTH); - int dsouth = GetPoleDistance(D_SOUTH); - if (dnorth < 9) - townch = townch + 25 * (9 - dnorth) * - (9 - dnorth) * Globals->LESS_ARCTIC_TOWNS; - if (dsouth < 9) - townch = townch + 25 * (9 - dsouth) * - (9 - dsouth) * Globals->LESS_ARCTIC_TOWNS; - } - int spread = Globals->TOWN_SPREAD; - if(spread > 100) spread = 100; - int townprob = (TerrainDefs[type].economy * 4 * (100 - spread) + - 100 * spread) / 100; - if (adjacent > 0) townprob = townprob * (100 - Globals->TOWNS_NOT_ADJACENT) / 100; - if (getrandom(townch) < townprob) AddTown(); - } - - Production *p = new Production; - p->itemtype = I_SILVER; - money = Population() * (Wages() - (Globals->MAINTENANCE_COST/2)) / (2*Globals->POP_LEVEL); //BS Edit - - if(Globals->PLAYER_ECONOMY) { - WagesFromDevelopment(); - maxwages = wages; - money = Population() * (wages - 100) / 10; - } - - if (money < 0) money = 0; - p->amount = money / Globals->WORK_FRACTION; - p->skill = -1; - if (Globals->PLAYER_ECONOMY) p->productivity = wages; - else p->productivity = Wages(); - products.Add(p); - - // - // Setup entertainment - // - p = new Production; - p->itemtype = I_SILVER; - p->amount = money / Globals->ENTERTAIN_FRACTION; - p->skill = S_ENTERTAINMENT; - p->productivity = Globals->ENTERTAIN_INCOME; - products.Add(p); - - float ratio = ItemDefs[race].baseprice / (float)Globals->BASE_MAN_COST; - // Setup Recruiting - Market *m = new Market(M_BUY, race, (int)(Wages()*4*ratio), - Population()/(5*Globals->POP_LEVEL), 0, 10000, 0, 2000); - markets.Add(m); - - if(Globals->LEADERS_EXIST) { - ratio = ItemDefs[I_LEADERS].baseprice / (float)Globals->BASE_MAN_COST; - m = new Market(M_BUY, I_LEADERS, (int)(Wages()*4*ratio), - Population()/(25*Globals->POP_LEVEL), 0, 10000, 0, 400); - markets.Add(m); - } -} - -void ARegion::DisbandInRegion(int item, int amt) -{ - if (!Globals->PLAYER_ECONOMY) return; - if (amt > 0) { - if (amt > Population()) { - // exchange region race! - race = item; - population = 0; - if(town) town->pop = 0; - AdjustPop(amt); - } else { - if (race != item) amt = amt * 2 / 3; - AdjustPop(amt); - } - } -} - -void ARegion::Recruit(int amt) -{ - if (!Globals->PLAYER_ECONOMY) return; - AdjustPop(-amt); -} - -void ARegion::AdjustPop(int adjustment) -{ - if(!town) { - population += adjustment; - return; - } - - // split between town and rural pop - int tspace = town->basepop - town->pop; - int rspace = habitat - population; - town->pop += adjustment * tspace / (tspace + rspace); - if(town->pop < 0) town->pop = 0; - population += adjustment * rspace / (tspace + rspace); - if (population < 0) population = 0; - -} - -void ARegion::SetupCityMarket() -{ - int numtrade = 0; - int cap; - int offset = 0; - int citymax = Globals->CITY_POP*Globals->POP_LEVEL; - ManType *locals = FindRace(ItemDefs[race].abr); - if(!locals) locals = FindRace("SELF"); - /* compose array of possible supply & demand items */ - int supply[NITEMS]; - int demand[NITEMS]; - /* possible advanced and magic items */ - int rare[NITEMS]; - int antiques[NITEMS]; - int i; - for (i=0; iCanProduce(i); - int isUseful = 0; - // Check if the item is useful to the locals - isUseful = locals->CanUse(i); - //Normal Items - if(ItemDefs[ i ].type & IT_NORMAL) { - - if (i==I_GRAIN || i==I_LIVESTOCK || i==I_FISH) { - // Add foodstuffs directly to market - int amt = Globals->CITY_MARKET_NORMAL_AMT; - int price; - - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - price = (ItemDefs[i].baseprice * (100 + getrandom(50))) / - 100; - } else { - price = ItemDefs[ i ].baseprice; - } - - //reduce grain/livestock demand in ocean - if(i != I_FISH && TerrainDefs[type].similar_type == R_OCEAN) amt /= 10; - - cap = (citymax * 3/4) - 1000; - if(cap < 0) cap = citymax/2; - - Market * m = new Market (M_SELL, i, price, amt, population, - population+cap, amt, amt*2); - markets.Add(m); - } else if (i == I_FOOD) { - // Add foodstuffs directly to market - int amt = Globals->CITY_MARKET_NORMAL_AMT; - int price; - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - price = (ItemDefs[i].baseprice * (120 + getrandom(80))) / - 100; - } else { - price = ItemDefs[ i ].baseprice; - } - - cap = (citymax / 8); - if(cap < citymax) cap = (citymax * 3/4); - Market * m = new Market (M_BUY, i, price, amt, population+cap, - population+6*cap, amt, amt*5); - markets.Add(m); - } else if (ItemDefs[i].pInput[0].item == -1) { //Arcadia mods - // Basic resource - // Add to supply? - if(canProduceHere) supply[i] = 4; //forget the canproduce stuff - // Add to demand? - else demand[i] = 4; - - if(i == I_ROUGHGEM) { //specific item mod for Arcadia - if(getrandom(2)) demand[i] = 2; - else demand[i] = 0; - } - - } else { - if(canProduceHere) supply[i] = 2; //forget the canproduce stuff - else demand[i] = 2; - } - } // end Normal Items - // Advanced Items - else if((Globals->CITY_MARKET_ADVANCED_AMT) - && (ItemDefs[i].type & IT_ADVANCED)) { - if(isUseful) rare[i] = 4; - else rare[i] = 4; //Arcadia mod - if(ItemDefs[i].hitchItem > 0) rare[i] = 2; - } - // Magic Items - else if((Globals->CITY_MARKET_MAGIC_AMT) - && (ItemDefs[i].type & IT_MAGIC)) { - if(isUseful) antiques[i] = 4; - else antiques[i] = 1; - if(ItemDefs[i].hitchItem > 0) antiques[i] = 2; - } - } - /* Check for advanced item */ - if((Globals->CITY_MARKET_ADVANCED_AMT) && (getrandom(4) == 1)) { - int ad = 0; - for(int i=0; iCITY_MARKET_ADVANCED_AMT; - int price; - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - price = (ItemDefs[i].baseprice * (100 + getrandom(50))) / 100; - } else { - price = ItemDefs[ i ].baseprice; - } - - cap = (citymax *3/4) - 1000; - if(cap < citymax/2) cap = citymax / 2; - offset = citymax / 8; - if (cap+offset < citymax) { - Market * m = new Market (M_SELL, i, price, amt/6, population+cap+offset, - population+citymax, 0, amt); - markets.Add(m); - } - } - } - /* Check for magic item */ - if((Globals->CITY_MARKET_MAGIC_AMT) && (getrandom(8) == 1)) { - int mg = 0; - for(int i=0; iCITY_MARKET_MAGIC_AMT; - int price; - - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - price = (ItemDefs[i].baseprice * (100 + getrandom(50))) / - 100; - } else { - price = ItemDefs[ i ].baseprice; - } - - cap = (citymax *3/4) - 1000; - if(cap < citymax/2) cap = citymax / 2; - offset = (citymax/20) + ((citymax/5) * 2); - Market * m = new Market (M_SELL, i, price, amt/6, population+cap, - population+citymax, 0, amt); - markets.Add(m); - } - } - - /* Add demand (normal) items */ - int num = 3; - int sum = 1; - while((num > 0) && (sum > 0)) { - int dm = 0; - for(int i=0; i= sum) continue; //should not occur - - int amt = Globals->CITY_MARKET_NORMAL_AMT; - amt = demand[i] * amt / 4; - int price; - - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - price = (ItemDefs[i].baseprice * - (100 + getrandom(50))) / 100; - } else { - price = ItemDefs[i].baseprice; - } - - cap = (citymax/4); - offset = - (citymax/20) + ((5-num) * citymax * 3/40); - Market * m = new Market (M_SELL, i, price, amt/6, - population+cap+offset, population+citymax, 0, amt); - markets.Add(m); - demand[i] = 0; - num--; - } - - /* Add supply (normal) items */ - num = 1; - sum = 1; - while((num > 0) && (sum > 0)) { - int su = 0; - for(int i=0; i= sum) continue; - - int amt = Globals->CITY_MARKET_NORMAL_AMT; - amt = supply[i] * amt / 4; - if(i == I_WOOD || i == I_IRON) amt /= 2; //Arcadia mod - else if(i == I_STONE || i == I_HERBS) amt = (amt*3)/2; //ie half iron/wood, normal fur/horse, increased stone/herbs. - int price; - - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - price = (ItemDefs[i].baseprice * - (150 + getrandom(50))) / 100; - } else { - price = ItemDefs[ i ].baseprice; - } - - cap = (citymax/4); - offset = ((3-num) * citymax * 3 / 40); - if (supply[i] < 4) offset += citymax / 20; - Market * m = new Market (M_BUY, i, price, 0, - population+cap+offset, population+citymax, - 0, amt); - markets.Add(m); - supply[i] = 0; - if (ItemDefs[i].pInput[0].item == -1) num--; //Arcadia mod - } - /* Set up the trade items */ -/* int buy1 = getrandom(numtrade); - int buy2 = getrandom(numtrade); - int sell1 = getrandom(numtrade); - int sell2 = getrandom(numtrade); -*/ - int buy1 = GetArcadianTrade(numtrade,0); - int buy2 = GetArcadianTrade(numtrade,0); - int sell1 = GetArcadianTrade(numtrade,1); - int sell2 = GetArcadianTrade(numtrade,1); - int tradebuy = 0; - int tradesell = 0; - offset = 0; - cap = 0; - -/* while (buy1 == buy2) buy2 = getrandom(numtrade); - while (sell1 == buy1 || sell1 == buy2) sell1 = getrandom(numtrade); - while (sell2 == sell1 || sell2 == buy2 || sell2 == buy1) - sell2 = getrandom(numtrade); -*/ - - while (buy1 == buy2) buy2 = GetArcadianTrade(numtrade,0); - while (sell1 == buy1 || sell1 == buy2) sell1 = GetArcadianTrade(numtrade,1); - while (sell2 == sell1 || sell2 == buy2 || sell2 == buy1) sell2 = GetArcadianTrade(numtrade,1); - - for (int i=0; iCITY_MARKET_TRADE_AMT; - int price; - - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - if(Globals->MORE_PROFITABLE_TRADE_GOODS) { - price=(ItemDefs[i].baseprice*(400+getrandom(100)))/100; //BS Arcadia increase from 250 to 350. - } else { - price=(ItemDefs[i].baseprice*(150+getrandom(50)))/100; - } - } else { - price = ItemDefs[ i ].baseprice; - } - -// cap = (citymax/2); //2000 - cap = 1200*Globals->POP_LEVEL; - offset = tradesell++ *(citymax/9); // 0,445 - 1200-1645 - if(cap + offset < citymax) { - Market * m = new Market (M_SELL, i, price, amt/5, cap+population+offset, - citymax+population+offset, 0, amt); //BS offset added into maxpop - markets.Add(m); - } - } -//60-90 (90-145) : 240-300 (360-450) buy prices : sell prices - if(addsell) { - int amt = Globals->CITY_MARKET_TRADE_AMT; - int price; - - if(Globals->RANDOM_ECONOMY) { - amt += getrandom(amt); - if(Globals->MORE_PROFITABLE_TRADE_GOODS) { - price=(ItemDefs[i].baseprice*(100+getrandom(50)))/100; //BS Arcadia decrease from 90 to 50 - } else { - price=(ItemDefs[i].baseprice*(100+getrandom(50)))/100; - } - } else { - price = ItemDefs[ i ].baseprice; - } - -// cap = (citymax/2); //2000 - cap = 1250*Globals->POP_LEVEL; - offset = tradebuy++ * (citymax/12); //0 or 333 - 1250-1583 - if(cap+offset < citymax) { - Market * m = new Market (M_BUY, i, price, amt/6, cap+population+offset, - citymax+population+offset, 0, amt); // BS : +offset added into max - markets.Add(m); - } - } - } - } -} -/* -int ARegion::GetArcadianTradeAveraged(int numtrade, int producing) -{ - int sales[NITEMS]; - int buys[NITEMS]; - - for(int i=0; itown) continue; - forlist(&r->markets) { - Market *m = (Market *) elem; - if(!(ItemDefs[m->type].type & IT_TRADE)) continue; - if(m->type == M_SELL) sales[m->item]++; - else buys[m->item]++; - total++; - } - } - } - - total /= 2; - int tradebuys[numtrade]; - int tradesales[numtrade]; - int j = 0; - for(int i=0; iethnicity) { - case RA_HUMAN: - return getrandom(4); //wine, wool, orchids, caviar - case RA_ELF: - return 4+getrandom(4); //silk, perfume, chocolate, cashmere - case RA_DWARF: - return 8+getrandom(4); //jewelry, figurines, dye, truffles - default: - return getrandom(numtrade); - } - } else { - switch(mt->ethnicity) { - case RA_HUMAN: - return 4+getrandom(8); - case RA_ELF: - if(getrandom(2)) return getrandom(4); - else return 8+getrandom(4); - case RA_DWARF: - return getrandom(8); - default: - return getrandom(numtrade); - } - } - return getrandom(numtrade); //should never occur -} - -void ARegion::SetupProds() -{ - Production *p = NULL; - TerrainType *typer = &(TerrainDefs[type]); - - if(Globals->FOOD_ITEMS_EXIST) { - if (typer->economy) { - // Foodchoice = 0 or 1 if inland, 0, 1, or 2 if coastal - int foodchoice = getrandom(2 + - (Globals->COASTAL_FISH && IsCoastal())); - switch (foodchoice) { - case 0: - if (!(ItemDefs[I_GRAIN].flags & ItemType::DISABLED)) - p = new Production(I_GRAIN, typer->economy); - break; - case 1: - if (!(ItemDefs[I_LIVESTOCK].flags & ItemType::DISABLED)) - p = new Production(I_LIVESTOCK, typer->economy); - break; - case 2: - if (!(ItemDefs[I_FISH].flags & ItemType::DISABLED)) - p = new Production(I_FISH, typer->economy); - break; - } - products.Add(p); - } - } - - for(unsigned int c= 0; c < (sizeof(typer->prods)/sizeof(Product)); c++) { - int item = typer->prods[c].product; - int chance = typer->prods[c].chance; - int amt = typer->prods[c].amount; - if(item != -1) { - if(!(ItemDefs[item].flags & ItemType::DISABLED) && - (getrandom(100) < chance)) { - p = new Production(item, amt); - products.Add(p); - } - } - } -} - -void ARegion::AddTown() -{ - town = new TownInfo; - town->name = new AString(AGetNameString(AGetName(1))); - // PLAYER_ECONOMY - // basepop is the town's habitat - // set pop to a base level at first - if(Globals->PLAYER_ECONOMY) { - town->basepop = TownHabitat(); - town->pop = town->basepop * 2 / 3; - town->activity = 0; - town->growth = 0; - town->mortality = 0; - SetupCityMarket(); - return; - } - - if(Globals->RANDOM_ECONOMY) { - int popch = 2000*Globals->POP_LEVEL; - if(Globals->LESS_ARCTIC_TOWNS) { - int dnorth = GetPoleDistance(D_NORTH); - int dsouth = GetPoleDistance(D_SOUTH); - int dist = dnorth; - // - // On small worlds or the underworld levels, a city could be - // within 9 of both poles.. chose the one it's closest to - if (dsouth < dist) dist = dsouth; - if (dist < 9) - popch = popch - (9 - dist) * ((9 - dist) + 10) * 15; - } - town->pop = 500*Globals->POP_LEVEL+getrandom(popch); - } else { - town->pop = 500*Globals->POP_LEVEL; - } - town->basepop = town->pop; - town->activity = 0; - - SetupCityMarket(); -} - -void ARegion::AddEditTown(AString *townname) -{ -#define NUMTOWNNAMES 1000 -/* This should be a direct copy of the above except for the naming*/ - if(!townname) townname = new AString(AGetNameString(getrandom(NUMTOWNNAMES))); - if(town) delete town; - town = new TownInfo; - town->name = townname; - // PLAYER_ECONOMY - // basepop is the town's habitat - // set pop to a base level at first - if(Globals->PLAYER_ECONOMY) { - town->basepop = TownHabitat(); - town->pop = town->basepop * 2 / 3; - town->activity = 0; - town->growth = 0; - town->mortality = 0; - SetupCityMarket(); - return; - } - - if(Globals->RANDOM_ECONOMY) { - int popch = 2000*Globals->POP_LEVEL; - if(Globals->LESS_ARCTIC_TOWNS) { - int dnorth = GetPoleDistance(D_NORTH); - int dsouth = GetPoleDistance(D_SOUTH); - int dist = dnorth; - // - // On small worlds or the underworld levels, a city could be - // within 9 of both poles.. chose the one it's closest to - if (dsouth < dist) dist = dsouth; - if (dist < 9) - popch = popch - (9 - dist) * ((9 - dist) + 10) * 15; - } - town->pop = 500*Globals->POP_LEVEL+getrandom(popch); - } else { - town->pop = 500*Globals->POP_LEVEL; - } - town->basepop = town->pop; - town->activity = 0; - SetupCityMarket(); -} - -void ARegion::UpdateEditRegion() -{ - // redo markets and entertainment/tax income for extra people. - - money = Population() * (Wages() - (Globals->MAINTENANCE_COST/2)) / (2*Globals->POP_LEVEL); //BS Edit - if (money < 0) money = 0; - // Setup working - Production *p = products.GetProd(I_SILVER, -1); - if(p) { - if (IsStartingCity()) { - // Higher wages in the entry cities. - p->amount = Wages() * Population(); - } else { - p->amount = (Wages() * Population()) / Globals->WORK_FRACTION; - } - p->productivity = Wages(); - } - // Entertainment. - p = products.GetProd(I_SILVER, S_ENTERTAINMENT); - if(p) { - p->baseamount = money / Globals->ENTERTAIN_FRACTION; - p->amount = p->baseamount; - } - markets.PostTurn(Population(), Wages(), race); - - //Replace man selling - forlist(&markets) { - Market *m = (Market *) elem; - if(ItemDefs[m->item].type & IT_MAN) { - markets.Remove(m); - delete m; - } - } - - float ratio = ItemDefs[race].baseprice / (float)Globals->BASE_MAN_COST; - int wage = Wages(); - if(wage < 10) wage = 10; - Market *m = new Market(M_BUY, race, (int)(wage*4*ratio), - Population()/(5*Globals->POP_LEVEL), 0, 10000, 0, 2000); - markets.Add(m); - - if(Globals->LEADERS_EXIST) { - ratio = ItemDefs[I_LEADERS].baseprice / (float)Globals->BASE_MAN_COST; - m = new Market(M_BUY, I_LEADERS, (int)(Wages()*4*ratio), - Population()/(25*Globals->POP_LEVEL), 0, 10000, 0, 400); - markets.Add(m); - } -} - -void ARegion::SetupEditRegion(int canmakecity) -{ -//Direct copy of SetupPop() except calls AddEditTown() instead of AddTown() - TerrainType *typer = &(TerrainDefs[type]); - habitat = typer->pop+1; - if (habitat < 100) habitat = 100; - habitat *= Globals->POP_LEVEL; - - int pop = typer->pop*Globals->POP_LEVEL; - int mw = typer->wages; - - // fix economy when MAINTENANCE_COST has been adjusted - mw += Globals->MAINTENANCE_COST - 10; - if (mw < 0) mw = 0; - - if (pop == 0) { - population = 0; - basepopulation = 0; - wages = 0; - maxwages = 0; - money = 0; - if(typer->similar_type == R_OCEAN) race = I_MERMEN; - - /* - if(Globals->PLAYER_ECONOMY) { - // All regions need silver production - // even if no income can be gained - Production *p = new Production; - p->itemtype = I_SILVER; - p->amount = 0; - p->skill = -1; - p->productivity = 0; - products.Add(p); - - p = new Production; - p->itemtype = I_SILVER; - p->amount = 0; - p->skill = S_ENTERTAINMENT; - p->productivity = Globals->ENTERTAIN_INCOME; - products.Add(p); - } - */ - - return; - } - - // Only select race here if it hasn't been set during Race Growth - // in the World Creation process. - if ((race == -1) || (!Globals->GROW_RACES)) { - int noncoastalraces = sizeof(typer->races)/sizeof(int); - int allraces = - noncoastalraces + sizeof(typer->coastal_races)/sizeof(int); - - race = -1; - while (race == -1 || (ItemDefs[race].flags & ItemType::DISABLED)) { - int n = getrandom(IsCoastal() ? allraces : noncoastalraces); - if(n > noncoastalraces-1) { - race = typer->coastal_races[n-noncoastalraces-1]; - } else - race = typer->races[n]; - } - } - - if(Globals->PLAYER_ECONOMY) { - if(Globals->RANDOM_ECONOMY) habitat = habitat * 2/3 + getrandom(habitat/3); - ManType *mt = FindRace(ItemDefs[race].abr); - if (mt->terrain == typer->similar_type) { - habitat = (habitat * 9)/8; - } - if (!IsNativeRace(race)) { - habitat = (habitat * 4)/5; - } - basepopulation = habitat; - // hmm... somewhere not too far off equilibrium pop - population = habitat * 66 / 100; - } else { - if(Globals->RANDOM_ECONOMY) { - population = (pop + getrandom(pop)) / 2; - } else { - population = pop; - } - basepopulation = population; - } - - // Setup wages - if(Globals->PLAYER_ECONOMY) { - int level = 1; - development = 1; - int prev = 0; - while (level < mw) { - development++; - prev++; - if(prev > level) { - level++; - prev = 0; - } - } - if(Globals->RANDOM_ECONOMY) { - development += getrandom(36); - } - } else { - if(Globals->RANDOM_ECONOMY) { - mw += getrandom(3); - } - wages = mw; - maxwages = mw; - } - - if(Globals->TOWNS_EXIST) { - int adjacent = 0; - int prob = Globals->TOWN_PROBABILITY; - if (prob < 1) prob = 100; - int townch = (int) 80000 / prob; - if (Globals->TOWNS_NOT_ADJACENT) { - for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = neighbors[d]; - if ((newregion) && (newregion->town)) adjacent++; - } - } - if(Globals->LESS_ARCTIC_TOWNS) { - int dnorth = GetPoleDistance(D_NORTH); - int dsouth = GetPoleDistance(D_SOUTH); - if (dnorth < 9) - townch = townch + 25 * (9 - dnorth) * - (9 - dnorth) * Globals->LESS_ARCTIC_TOWNS; - if (dsouth < 9) - townch = townch + 25 * (9 - dsouth) * - (9 - dsouth) * Globals->LESS_ARCTIC_TOWNS; - } - int spread = Globals->TOWN_SPREAD; - if(spread > 100) spread = 100; - int townprob = (TerrainDefs[type].economy * 4 * (100 - spread) + - 100 * spread) / 100; - if (adjacent > 0) townprob = townprob * (100 - Globals->TOWNS_NOT_ADJACENT) / 100; - if (getrandom(townch) < townprob) AddEditTown(); - } - - Production *p = new Production; - p->itemtype = I_SILVER; - money = Population() * (Wages() - (Globals->MAINTENANCE_COST/2)) / (2*Globals->POP_LEVEL); //BS Edit - - if(Globals->PLAYER_ECONOMY) { - WagesFromDevelopment(); - maxwages = wages; - money = Population() * (wages - 100) / 10; - } - - if (money < 0) money = 0; - p->amount = money / Globals->WORK_FRACTION; - p->skill = -1; - if (Globals->PLAYER_ECONOMY) p->productivity = wages; - else p->productivity = Wages(); - products.Add(p); - - // - // Setup entertainment - // - p = new Production; - p->itemtype = I_SILVER; - p->amount = money / Globals->ENTERTAIN_FRACTION; - p->skill = S_ENTERTAINMENT; - p->productivity = Globals->ENTERTAIN_INCOME; - products.Add(p); - - float ratio = ItemDefs[race].baseprice / (float)Globals->BASE_MAN_COST; - // Setup Recruiting - Market *m = new Market(M_BUY, race, (int)(Wages()*4*ratio), - Population()/(5*Globals->POP_LEVEL), 0, 10000, 0, 2000); - markets.Add(m); - - if(Globals->LEADERS_EXIST) { - ratio = ItemDefs[I_LEADERS].baseprice / (float)Globals->BASE_MAN_COST; - m = new Market(M_BUY, I_LEADERS, (int)(Wages()*4*ratio), - Population()/(25*Globals->POP_LEVEL), 0, 10000, 0, 400); - markets.Add(m); - } -} - - - - - - - -// Used at start to set initial town's -// development level -void ARegion::CheckTownIncrease() -{ - if(!town) return; - - //if(town) return; - - if(town->pop > 3000*Globals->POP_LEVEL) { - development = development + ((getrandom(Globals->TOWN_DEVELOPMENT) + Globals->TOWN_DEVELOPMENT) / 10); - return; - } - - if(getrandom(200) > Globals->TOWN_DEVELOPMENT) return; - - int a = 5; - if(Globals->TOWN_DEVELOPMENT < 10) a = Globals->TOWN_DEVELOPMENT / 2; - int b = 20; - if(Globals->TOWN_DEVELOPMENT < 60) b = Globals->TOWN_DEVELOPMENT / 3; - development = development + a + getrandom(b); - /* - Awrite(AString("> increased city in ") + TerrainDefs[type].name + " in " + - *name + " (" + xloc + ", " + yloc + ") to dev = " + development); - */ - TownHabitat(); - town->pop = town->basepop * 2 / 3; -} - -int ARegion::TownHabitat() -{ - // Effect of existing buildings - int farm = 0; - int inn = 0; - int bank = 0; - int temple = 0; - int caravan = 0; - int fort = 0; - forlist(&objects) { - Object *obj = (Object *) elem; - if(ObjectDefs[obj->type].protect > fort) fort = ObjectDefs[obj->type].protect; - if(ItemDefs[ObjectDefs[obj->type].productionAided].flags & IT_FOOD) farm++; - if(ObjectDefs[obj->type].productionAided == I_SILVER) inn++; - if(ObjectDefs[obj->type].productionAided == I_HERBS) temple++; - if(ObjectDefs[obj->type].name == "Bank") bank++; - if((ObjectDefs[obj->type].flags & ObjectType::TRANSPORT) - && (ItemDefs[ObjectDefs[obj->type].productionAided].flags & IT_MOUNT)) caravan++; - } - int hab = 2; - int step = 0; - for(int i=0; i<5; i++) { - if(fort > step) hab++; - step *= 5; - if(step == 0) step = 10; - } - int build = 0; - if(farm) build++; - if(inn) build++; - if(temple) build++; - if(bank) build++; - if(caravan) build++; - if(build > 2) build = 2; - - hab = (build++ * build + 1) * hab * hab + basepopulation / 4 + 50; - - // Lake Effect - if(LakeEffect()) hab += 100; - - // Effect of Development: - int totalhab = hab + TownDevelopment() / 100 * (basepopulation + 2800 + hab); - - return totalhab; -} - -// Use this to determine development including -// bonuses for roads -int ARegion::Development() -{ - int dv = development; - - // Road bonus - int roads = 0; - for(int i=0; i 0) { -#if 0 - Awrite("_____________________________________________________"); - Awrite("Checking Roads... for region:"); - Awrite(AString(" ") + *name + "(" + xloc + ", " + yloc + ")"); -#endif - dbonus = CountRoadConnectedTowns(8); - } - // Maximum bonus of 40 to development for roads - int bonus = 5; - int leveloff = 1; - int totalb = 0; - while((dbonus > 0) && (totalb < 41)) { - dbonus--; - if(leveloff > 4) if (bonus > 1) bonus--; - leveloff++; - totalb += bonus; - } - - return dv; -} - -// Measure of the economic development of a town -// on a scale of 0-100. Used for town growth/hab/limits -// and also for raising development through markets. -// Do NOT take roads into account as they are a bonus and -// considered outside of these limits. -int ARegion::TownDevelopment() -{ - int level = 1; - int basedev = 1; - int prev = 0; - while (level <= TerrainDefs[type].wages) { - prev++; - basedev++; - if(prev > level) { - level++; - prev = 0; - } - } - - int df = 100 * (development - basedev) / 90; - if(df < 0) df = 0; - if(df > 100) df = 100; - - return df; -} - -void ARegion::UpdateTown() -{ - if(!(Globals->VARIABLE_ECONOMY)) { - // - // Nothing to do here. - // - return; - } - - // - // Check if we were a starting city and got taken over - // - if(IsStartingCity() && !HasCityGuard() && !Globals->SAFE_START_CITIES) { - // Make sure we haven't already been modified. - int done = 1; - forlist(&markets) { - Market *m = (Market *)elem; - if(m->minamt == -1) { - done = 0; - break; - } - } - if(!done) { - markets.DeleteAll(); - SetupCityMarket(); - float ratio = ItemDefs[race].baseprice / - (float)Globals->BASE_MAN_COST; - // Setup Recruiting - Market *m = new Market(M_BUY, race, (int)(Wages()*4*ratio), - Population()/(5*Globals->POP_LEVEL), 0, 10000, 0, 2000); - markets.Add(m); - if(Globals->LEADERS_EXIST) { - ratio = ItemDefs[I_LEADERS].baseprice / - (float)Globals->BASE_MAN_COST; - m = new Market(M_BUY, I_LEADERS, (int)(Wages()*4*ratio), - Population()/(25*Globals->POP_LEVEL), 0, 10000, 0, 400); - markets.Add(m); - } - } - } - - if(Globals->PLAYER_ECONOMY) { - - town->basepop = TownHabitat(); - - // *Town Pop Growth* - int delay = Globals->DELAY_GROWTH; - if (delay < 2) delay = 2; - int lastgrowth = town->growth; - if (delay > 2) - for (int i=1; igrowth += lastgrowth; - // growth based on available space - int space = town->basepop - town->pop; - if(space < 0) space = 0; - int sgrow = 0; - if((3 * space/(town->basepop+1)) < 2) sgrow = space / 10; - else sgrow = (space / (town->basepop + 1) * 15) * space; - // growth based on population and wages - int curg = ((Globals->POP_GROWTH / 100) * (Wages()-5) * - (((town->basepop * (1+Wages()/8)) - 2 * town->pop) / (40 * delay))); - if (sgrow > 0) sgrow = 0; - if (curg > 0) curg = 0; - town->growth += sgrow + curg; - town->growth = town->growth / delay; - if (town->pop < 1) town->growth = 0; - - // *Town Pop Mortality* - delay = Globals->DELAY_MORTALITY; - if (delay < 2) delay = 2; - int lastmort = town->mortality; - int curm = 0; - int starve = 0; - if (delay > 2) - for (int i=1; ipop - 2 * town->basepop; - if ((3 * crowd / town->basepop) < 2) crowd = 0; - if (crowd > 0) { - float cfactor = 2 / (crowd + 1); - cfactor = cfactor * cfactor / 4; - crowd = (int) ((town->pop / 10) * (1 - cfactor)); - } - - if(crowd > 0) town->mortality += crowd; - if(starve > 0) town->mortality += starve; - town->mortality = town->mortality / delay; - if ((town->mortality < 0) || (town->pop < 1)) town->mortality = 0; - - town->pop += town->growth - town->mortality; - if(town->pop < 0) town->pop = 0; - /* - if(crowd > 0) migration += crowd / 36; - if(starve > 0) migration += starve / 36; - */ -#if 0 - if((development > 190) && (!IsStartingCity())) { - Awrite(AString("===== Town(") + town->TownType() + ") in " + *name - + " in (" + xloc + ", " + yloc + ") ====="); - Awrite(AString(" growth: ") + town->growth); - Awrite(AString(" mortality: ") + town->mortality); - Awrite(AString(" town pop: ") + town->pop); - Awrite(AString(" town hab: ") + town->basepop); - Awrite(AString(" development: ") + development); - int td = TownDevelopment(); - Awrite(AString(" towndevel.: ") + td); - Awrite(AString(" migration: ") + migration); - Awrite(""); - } -#endif - return; - } - - - // - // Don't do pop stuff for AC Exit. - // - //BS : This section modified from standard (for Arcadia) - if (!IsStartingCity()) { - // First, get the target population - int amt = 0; - int tot = 0; - forlist(&markets) { - Market *m = (Market *) elem; - if (Population() > m->minpop) { - if (ItemDefs[m->item].type & IT_TRADE) { - amt += 3 * m->activity; - tot += 3 * m->amount; //BS mod (i) all trade items, (ii) use amount not maxamt here & below - } else { - if (m->type == M_SELL) { - // Only food items except fish are mandatory - // for town growth - other items can - // be used in replacement - if (ItemDefs[m->item].type & IT_FOOD) { - amt += 2 * m->activity; - } else amt += m->activity; - if (ItemDefs[m->item].type & IT_FOOD) tot += 2 * m->amount; //so town growth is set by size of fish,livestock&grain markets (plus trade items) only ... fish added by BS. - } else { - //BS mod - buying town products should increase growth also - if (!(ItemDefs[m->item].type & IT_MAN)) { - amt += m->activity; - } - } - } - } - } - - if (amt > tot) amt = tot; - - int score; - if (tot) { - score = (1000 * amt) / tot; - } else { - score = 0; - } - - int maxgrowth = 150*Globals->POP_LEVEL + (town->pop * ((3*Globals->CITY_POP*Globals->POP_LEVEL)/2 - town->pop)) / (60000*Globals->POP_LEVEL*Globals->POP_LEVEL); - //equals 150 at pop=0, max 300 at pop = 3000, 233 at pop = 1000 or 5000. - //this growth cannot be exceeded, but it should be fairly easy to get half this growth for small towns. - - int basescore = town->pop/(6*Globals->POP_LEVEL) - 80; // 3 at pop = 500, 320=32% at pop = 2400. Equals trade required for steady pop - if(basescore < 1) basescore = 1; - - int change = 0; - if(score < basescore) { - change = ((score-basescore)*town->pop)/(basescore*20); //linear from -5% to 0 for basescore = 0 to score. - } else if (score > basescore) { //approximately exponential, requiring score = 2*basescore to get growth = 63% of maxgrowth. - float exponent = 1; - while( (score-- > basescore) && (exponent*maxgrowth > 1) ) { - exponent *= 1 - 1/((float) basescore); - } - change = maxgrowth - (int (maxgrowth*exponent)); - } - - town->pop += change; - - // Check base population - if (town->pop < town->basepop) { - town->pop = town->basepop; - } - if ((town->pop * 4) / 5 > town->basepop) { - town->basepop = (town->pop * 4) / 5; - } - } -} - -void ARegion::Migrate() -{ - for(int i=0; imigration > 0)) { - int cv = 100; - if(nbor->race != race) cv = 50; - // Roads? - if(HasExitRoad(i) && HasConnectingRoad(i)) { - cv += 25; - for(int d=0; dHasExitRoad(d))) continue; - ARegion *ntwo = nbor->neighbors[d]; - if((nbor) && (nbor->HasConnectingRoad(d))) { - int c2 = 100; - if(ntwo->race != race) c2 = 50; - population += ntwo->migration * c2 / 100; - } - } - } - population += nbor->migration * cv / 100; - } - } -} - -void ARegion::PostTurn(ARegionList *pRegs) -{ - // Rules for PLAYER-RUN ECONOMY - if (Globals->PLAYER_ECONOMY) { - - // Decay desolate areas - if (Population() < (habitat / 100)) - if (development > 0) development--; - // Check for Development increase - int fooddemand = 1; - int foodavailable = 1; - forlist(&markets) { - Market *m = (Market *) elem; - if (m->amount < 1) continue; - int npcprod = 0; - forlist(&products) { - Production *re = (Production *) elem; - if (re->itemtype == m->item) - npcprod = re->amount - re->activity; - } - if (ItemDefs[m->item].type & IT_MAN) { - // reduce population - population -= m->activity; - } else if (m->type == M_SELL) { - if (ItemDefs[m->item].type & IT_FOOD) { - fooddemand += m->amount; - foodavailable += m->activity + npcprod; - } - int supply = npcprod + m->activity; - if ((m->amount <= supply * 4) && - (getrandom(m->amount) < supply)) { - development++; - } - } else if (m->type == M_BUY) { - int supply = m->activity; - if ((m->amount <= supply * 3) && - (getrandom(3 * m->amount) < (supply * 2))) { - development++; - } - } - // TODO: a function to update markets (incl. npcprod) - } - - WagesFromDevelopment(); - - // *Population Growth* - int delay = Globals->DELAY_GROWTH; - if (delay < 2) delay = 2; - int lastgrowth = growth; - if (delay > 2) - for (int i=1; iPOP_GROWTH / 100) * (Wages()-5) * - (habitat - 2 * population) / 200); - if(curg < 0) curg = 0; - curg = curg * (2 * habitat - 3 * population) / (habitat + 1); - // growth based on existing population - int pgrow = population; - if(pgrow > habitat) pgrow = habitat; - pgrow *= Globals->POP_GROWTH / 20000; - if(sgrow < 0) sgrow = 0; - if(curg < 0) curg = 0; - if(population > 0) growth += curg + sgrow + pgrow; - growth = growth / delay; - - // *Mortality* - delay = Globals->DELAY_MORTALITY; - if (delay < 2) delay = 2; - int lastmort = mortality; - int curm = 0; - int starve = 0; - if (delay > 2) - for (int i=1; ibasepop; - /* - if ((habitat > 0) && (fooddemand > 0)) - starve = (population * population * - (fooddemand - foodavailable)) / - (fooddemand * habitat * 4); - */ - - // mortality based on crowding: - int crowd = 3 * population - 2 * habitat; - if ((3 * crowd / habitat) < 2) crowd = 0; - if (crowd > 0) { - float cfactor = 2 / (crowd + 1); - cfactor = cfactor * cfactor / 4; - crowd = (int) ((population / 10) * (1 - cfactor)); - } - if(population > 0) mortality += crowd + starve; - mortality = mortality / delay; - if(mortality < 0) mortality = 0; - migration = (crowd + starve) / 18; - - // Update population - AdjustPop(growth - mortality); - - // Update town - if(town) UpdateTown(); - - // Check decay - if(Globals->DECAY) { - DoDecayCheck(pRegs); - } - - // Set tax base - money = (wages - 100) * Population() / 10; - if (money < 0) money = 0; - - if (type != R_NEXUS) { - // Setup working - Production * p = products.GetProd(I_SILVER,-1); - int hack = 0; - if (IsStartingCity()) { - // Higher wages in the entry cities. - hack = wages * Population() / 10; - } else { - // (Globals->WORK_FRACTION); //This is PLAYER ECONOMY section - hack = (wages * Population()) / 50; - } - // TODO: Silver available for work and entertainment - // still causes a segmentation fault!!! - if (p) { - p->amount = hack; - p->productivity = wages; - } - - // Entertainment. - p = products.GetProd(I_SILVER,S_ENTERTAINMENT); - if (p) p->baseamount = money / Globals->ENTERTAIN_FRACTION; -#if 0 - //uncomment for economy info output used for debugging - Awrite(AString("===== ") + - TerrainDefs[type].name + " in " + *name - + " (" + xloc + ", " + yloc + ") ====="); - Awrite(AString("population: ") + population + " " + - ItemDefs[race].names); - Awrite(AString("wages: ") + - (wages/10) + " (tax base: "+ money + ")"); - Awrite(AString("development: ") + development); - Awrite(AString("habitat: ") + - (habitat - population) + " / " + habitat); - Awrite(AString("growth: ") + growth + - " (this month: " + curg + ")"); - Awrite(AString("mortality: ") + mortality + " (" + starve + - " starve, " + crowd + " die of crowding)"); - Awrite(AString("food: ") + (foodavailable-1) + " / " + - (fooddemand-1)); - Awrite(""); -#endif - - markets.PostTurn(Population(),Wages(), race); - } - return; - } - - // Standard economy - // - // First update population based on production - // - int activity = 0; - int amount = 0; - if (basepopulation || Population()) { - forlist(&products) { - Production *p = (Production *) elem; - if (ItemDefs[p->itemtype].type & IT_NORMAL && - p->itemtype != I_SILVER) { - activity += p->activity; - amount += p->amount; - } - } - int tarpop = basepopulation; - if (amount) tarpop += (basepopulation * activity) / (2 * amount); - int diff = tarpop - population; - - if(Globals->VARIABLE_ECONOMY) { - population = population + diff / 5; - } - - // - // Now, if there is a town, update its population. - // - if (town) { - UpdateTown(); - } - - // AS - if(Globals->DECAY) { - DoDecayCheck(pRegs); - } - - // - // Now, reset population based stuff. - // Recover Wages. - // - if (wages < maxwages) wages++; - - // - // Set money - // - money = Population() * (Wages() - (Globals->MAINTENANCE_COST/2)) / (2*Globals->POP_LEVEL); //BS Edit - if (money < 0) money = 0; - - // - // Setup working - // - - Production *p = products.GetProd(I_SILVER, -1); - if(p) { - if (IsStartingCity()) { - // - // Higher wages in the entry cities. - // - p->amount = Wages() * Population() / Globals->POP_LEVEL; - } else { - p->amount = (Wages() * Population()) / (Globals->WORK_FRACTION * Globals->POP_LEVEL); - } - p->productivity = Wages(); - } - - // - // Entertainment. - // - p = products.GetProd(I_SILVER, S_ENTERTAINMENT); - if(p) p->baseamount = money / Globals->ENTERTAIN_FRACTION; - - markets.PostTurn(Population(), Wages(), race); - } - - UpdateProducts(); - - // - // Set these guys to 0. - // - //BS: Why? There's no need anymore, and it makes report-writing harder. - /* - earthlore = 0; - clearskies = 0; -*/ - - forlist(&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - u->PostTurn(this); - } - } -} diff --git a/arcadia/edit.cpp b/arcadia/edit.cpp deleted file mode 100644 index 940b61bdb..000000000 --- a/arcadia/edit.cpp +++ /dev/null @@ -1,3145 +0,0 @@ -#ifdef WIN32 -#include // Needed for memcpy on windows -#endif - -#include - -#include "game.h" -#include "unit.h" -#include "fileio.h" -#include "astring.h" -#include "gamedata.h" - -int Game::EditGame(int *pSaveGame) -{ - *pSaveGame = 0; - - Awrite("Editing an Atlantis Game: "); - do { - int exit = 0; - - Awrite("Main Menu"); - Awrite(" 1) Find a region..."); - Awrite(" 2) Find a unit..."); - Awrite(" 3) Create a new unit..."); - Awrite(" 4) Global Effects..."); - Awrite(" qq) Quit without saving."); - Awrite(" x) Exit and save."); - Awrite("> "); - - AString *pStr = AGetString(); - Awrite(""); - - if(*pStr == "qq") { - exit = 1; - Awrite("Quiting without saving."); - } else if(*pStr == "x") { - exit = 1; - *pSaveGame = 1; - Awrite("Exit and save."); - } else if(*pStr == "1") { - ARegion *pReg = EditGameFindRegion(); - if(pReg) EditGameRegion(pReg); - } else if(*pStr == "2") { - EditGameFindUnit(); - } else if(*pStr == "3") { - EditGameCreateUnit(); - } else if(*pStr == "4") { - EditGameGlobalEffects(); - } else { - Awrite("Select from the menu."); - } - - delete pStr; - if(exit) { - break; - } - } while(1); - - return(1); -} - -ARegion *Game::EditGameFindRegion() -{ - ARegion *ret = 0; - int x, y, z; - AString *pStr = 0, *pToken = 0; - Awrite("Region coords (x y z):"); - do { - pStr = AGetString(); - - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("No such region."); - break; - } - x = pToken->value(); - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("No such region."); - break; - } - y = pToken->value(); - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if(pToken) { - z = pToken->value(); - SAFE_DELETE(pToken); - } else { - z = 0; - } - - ARegion *pReg = regions.GetRegion(x, y, z); - if(!pReg) { - Awrite("No such region."); - break; - } - - ret = pReg; - } while(0); - - if(pStr) delete pStr; - if(pToken) delete pToken; - - return(ret); -} - -void Game::EditGameFindUnit() -{ - AString *pStr; - Awrite("Which unit number?"); - pStr = AGetString(); - int num = pStr->value(); - delete pStr; - Unit *pUnit = GetUnit(num); - if(!pUnit) { - Awrite("No such unit!"); - return; - } - EditGameUnit(pUnit); -} - -void Game::EditGameRegion(ARegion *pReg) -//copied direct from AtlantisDev 030730 post -{ - do { - Awrite( AString( "Region: " ) + pReg->Print( ®ions ) ); - Awrite( AString ("Region number ") + pReg->num); - Awrite( " 1) Edit objects..." ); - Awrite( " 2) Edit terrain..." ); - Awrite( " 3) Edit exits..." ); - Awrite( " 4) Navigate regions..." ); - Awrite( " 4 [dirs]... Navigate specified regions"); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "1" ) { - EditGameRegionObjects( pReg ); - } - else if( *pStr == "2" ) { - EditGameRegionTerrain( pReg ); - } - else if( *pStr == "3" ) { - EditGameRegionExits( pReg ); - } - else if( *pStr == "4" ) { - pReg = EditGameRegionNavigate( pReg ); - } - else if( *pStr == "q" ) { - exit = 1; - } - else { - AString *pToken = 0; - pToken = pStr->gettoken(); - if(pToken && *pToken == "4") { - pReg = EditGameRegionNavigate( pReg, pStr ); - } else { - Awrite( "Select from the menu." ); - } - SAFE_DELETE(pToken); - } - delete pStr; - - if( exit ) { - break; - } - } - while( 1 ); -} - - -/* RegionEdit Patch 030829 BS */ -void Game::EditGameRegionObjects( ARegion *pReg ) -//template copied from AtlantisDev 030730 post. Modified option a, added option h, m. -{ - do { - Awrite( AString( "Region: " ) + pReg->Print( ®ions ) ); - Awrite( "" ); - int i = 0; - AString temp = AString(""); - forlist (&(pReg->objects)) { - Object * obj = (Object *)elem; - temp = AString ((AString(i) + ". " + *obj->name + " : " + ObjectDefs[obj->type].name)); - if (Globals->HEXSIDE_TERRAIN && obj->hexside>-1) temp += AString( AString(" (side:") + DirectionAbrs[obj->hexside] + ")."); - - if (obj->incomplete > 0) { - temp += AString(", needs ") + obj->incomplete; - } else if(Globals->DECAY && !(ObjectDefs[obj->type].flags & ObjectType::NEVERDECAY) && obj->incomplete < 1) { - if(obj->incomplete > (0 - ObjectDefs[obj->type].maxMonthlyDecay)) { - temp += ", about to decay"; - } else if(obj->incomplete > (0 - ObjectDefs[obj->type].maxMaintenance/2)) { - temp += ", needs maintenance"; - } - } - if (obj->inner != -1) { - temp += AString(", contains an inner location to ") + (regions.GetRegion(obj->inner))->ShortPrint(®ions); - } - - if(obj->describe) temp += AString(". ") + *(obj->describe); - - Awrite(temp); - i++; - } - Awrite( "" ); - if(pReg->flagpole) { - Awrite(AString("This region is flagpoled ") + pReg->flagpole); - Awrite(""); - } - - Awrite( " [a] [object type] [dir] to add object" ); - Awrite( " [d] [index] to delete object" ); - if (Globals->HEXSIDE_TERRAIN) Awrite( " [h] [index] [dir] to change the hexside of an object" ); - Awrite( " [n] [index] [name] to rename object" ); - Awrite( " [s] [index] [description] to describe an object" ); - Awrite( " [i] [index] to remove an inner connection" ); - Awrite( " [i] [index] [xloc] [yloc] [zloc] to add an inner connection to an object" ); - Awrite( " [f] [num] to flagpole the region with value num." ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - // add object - if (*pToken == "a") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int objType = ParseObject(pToken); - if( (objType == -1) || (ObjectDefs[objType].flags & ObjectType::DISABLED) ) { - Awrite( "No such object." ); - break; - } - SAFE_DELETE( pToken ); - int dir=-1; - if(ObjectDefs[objType].hexside && Globals->HEXSIDE_TERRAIN ) { - if(!ObjectIsShip(objType) || !(TerrainDefs[pReg->type].similar_type == R_OCEAN) ) { - pToken = pStr->gettoken(); - if(!pToken) { - Awrite( "Specify direction" ); - break; - } - dir = ParseHexsideDir(pToken); - if(dir<0) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - } - } - - Object *o = new Object(pReg); - o->type = objType; - o->incomplete = 0; - o->inner = -1; - o->hexside = dir; - if (o->IsBoat()) { - o->num = shipseq++; - o->name = new AString(AString("Ship") + " [" + o->num + "]"); - } - else { - o->num = pReg->buildingseq++; - o->name = new AString(AString("Building") + " [" + o->num + "]"); - } - pReg->objects.Add(o); - } - // delete object - else if (*pToken == "d") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - int i = 0; - AListElem *tmp = pReg->objects.First(); - for (i = 0; i < index; i++) tmp = pReg->objects.Next(tmp); - pReg->objects.Remove(tmp); - } - else if (*pToken == "i") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if( (index < 0) || (index >= pReg->objects.Num()) ) { //modified minimum to <0 to allow deleting object 0. 030824 BS - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - - pToken = pStr->gettoken(); - if( !pToken ) { - tmp->inner = -1; - break; - } - int xloc = pToken->value(); - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - AString ("Specify y coordinate"); - break; - } - int yloc = pToken->value(); - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - AString ("Specify z coordinate"); - break; - } - int zloc = pToken->value(); - SAFE_DELETE( pToken ); - - ARegion *target = regions.GetRegion(xloc,yloc,zloc); - tmp->inner = target->num; - } - //hexside change - else if (*pToken == "h") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - - if(!(ObjectDefs[tmp->type].hexside)) { - Awrite("Not a hexside object."); - break; - } - - if(!Globals->HEXSIDE_TERRAIN) { - Awrite("Hexside terrain disabled under game rules."); - break; - } - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Specify Direction." ); - break; - } - - int dir=-1; - dir = ParseHexsideDir(pToken); - if(dir==-1) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - - SAFE_DELETE(pToken); - tmp->hexside = dir; - } - // rename object - else if (*pToken == "n") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "No name given." ); - break; - } - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - - AString * newname = pToken->getlegal(); - SAFE_DELETE(pToken); - if (newname) { - delete tmp->name; - *newname += AString(" [") + tmp->num + "]"; - tmp->name = newname; - } - } - else if (*pToken == "s") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int index = pToken->value(); - if( (index < 1) || (index >= pReg->objects.Num()) ) { - Awrite( "Incorrect index." ); - break; - } - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "No description given." ); - break; - } - - int i = 0; - Object *tmp = (Object *)pReg->objects.First(); - for (i = 0; i < index; i++) tmp = (Object *)pReg->objects.Next(tmp); - - if(tmp->describe) delete tmp->describe; - - AString * newdesc = pToken->getlegal(); - SAFE_DELETE(pToken); - tmp->describe = newdesc; - } - else if (*pToken == "f") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int flag = pToken->value(); - pReg->flagpole = flag; - SAFE_DELETE( pToken ); - } - - } while( 0 ); - if(pToken) delete pToken; - } - if(pStr) delete pStr; - - if( exit ) { - break; - } - } - while( 1 ); -} - -void Game::EditGameRegionTerrain( ARegion *pReg ) -{ - do { - Awrite(""); - Awrite( AString( "Region: " ) + pReg->Print( ®ions ) ); - Awrite( "Hexsides:" ); - - for(int i=0; i<6; i++) { - Hexside *h = pReg->hexside[i]; - if(h->type || h->road != 0 || h->bridge != 0) { - AString temp = AString(DirectionStrs[i]) + " : "; - if(h->type) temp += AString(HexsideDefs[h->type].name) + ". "; - if(h->road != 0) { - temp += HexsideDefs[H_ROAD].name; - if(h->road > 0) temp += AString(" (needs ") + h->road + ")"; - temp += ". "; - } - if(h->bridge != 0) { - temp += HexsideDefs[H_BRIDGE].name; - if(h->bridge > 0) temp += AString(" (needs ") + h->bridge + ")"; - temp += ". "; - } - Awrite(temp); - } - } -// write pop stuff - Awrite( AString("") + pReg->population + " " + ItemDefs[pReg->race].names + " basepop"); - if(pReg->town) Awrite( AString("") + pReg->town->pop + " " + ItemDefs[pReg->race].names + " townpop"); - Awrite( AString("") + pReg->Population() + " " + ItemDefs[pReg->race].names + " totalpop"); - -// write wages - Awrite(AString("Wages: ") + pReg->WagesForReport() + "."); - Awrite(AString("Maxwages: ") + pReg->maxwages + "."); - Awrite(AString("Taxes: ") + pReg->money + "."); - -// write products - AString temp = "Products: "; - int has = 0; - forlist((&pReg->products)) { - Production * p = ((Production *) elem); - if (ItemDefs[p->itemtype].type & IT_ADVANCED) { - if (has) { - temp += AString(", ") + p->WriteReport(); - } else { - has = 1; - temp += p->WriteReport(); - } - } else { - if (p->itemtype == I_SILVER) { - if (p->skill == S_ENTERTAINMENT) { - Awrite (AString("Entertainment available: $") + - p->amount + "."); - } - } else { - if (has) { - temp += AString(", ") + p->WriteReport(); - } else { - has = 1; - temp += p->WriteReport(); - } - } - } - } - if (has==0) temp += "none"; - temp += "."; - Awrite(temp); - Awrite( "" ); - - if(Globals->GATES_EXIST && pReg->gate && pReg->gate != -1) { - Awrite(AString("There is a Gate here (Gate ") + pReg->gate + - " of " + (regions.numberofgates) + ")."); - if(Globals->GATES_NOT_PERENNIAL) Awrite(AString("This gate opens " - "in month ") + pReg->gatemonth); - Awrite(""); - } - if(Globals->ARCADIA_MAGIC && pReg->willsink) { - Awrite(AString("This region will sink in ") + pReg->willsink + " months."); - } - - - Awrite( " [t] [terrain type] to modify terrain type" ); - Awrite( " [r] [race] to modify local race" ); - Awrite( " [w] [maxwages] to modify local wages" ); - Awrite( " [p] to regenerate products according to terrain type" ); - Awrite( " [g] to regenerate all according to terrain type" ); - if(pReg->gate > 0) Awrite( " [dg] to delete the gate in this region" ); - else Awrite( " [ag] to add a gate to this region" ); - Awrite( " [n] [name] to modify region name" ); - Awrite( " [ncopy] to copy this region's name to all similar nearby regions" ); - if(Globals->HEXSIDE_TERRAIN) { - Awrite( " [h] [dir] [type] to add/modify a hexside type "); - Awrite( " [dh] [dir] to clear a hexside "); - } - if(Globals->ARCADIA_MAGIC) Awrite( " [sink] [num] to set sink status"); - Awrite( " [pop] to set population level"); - if(pReg->town) { - Awrite( " [townpop] to set town population level"); - Awrite( " [town] to regenerate a town" ); - Awrite( " [deltown] to remove a town" ); - Awrite( " [tn] [name] to rename a town" ); - Awrite( " [v] to view/modify town markets" ); - } else Awrite( " [town] to add a town" ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - // modify terrain - if (*pToken == "t") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int terType = ParseTerrain(pToken); - if(terType == -1) { - Awrite( "No such terrain." ); - break; - } - SAFE_DELETE( pToken ); - int wasocean = 0; - int toocean = 0; - if(TerrainDefs[pReg->type].similar_type == R_OCEAN) wasocean = 1; - if(TerrainDefs[terType].similar_type == R_OCEAN) toocean = 1; - - if(wasocean && !toocean) pReg->OceanToLand(); - if(toocean && !wasocean) pReg->SinkRegion(®ions); - else pReg->type = terType; - - } - else if (*pToken == "r") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - int prace = ParseAllItems(pToken); - if(!(ItemDefs[prace].type & IT_MAN) || (ItemDefs[prace].flags & ItemType::DISABLED) ) { - Awrite( "No such race." ); - break; - } - if(prace>0) pReg->race = prace; - pReg->UpdateEditRegion(); - SAFE_DELETE( pToken ); - } - else if (*pToken == "h") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Specify a direction." ); - break; - } - int dir=-1; - dir = ParseHexsideDir(pToken); - SAFE_DELETE( pToken ); - if(dir < 0 || dir > 5) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - Hexside *h = pReg->hexside[dir]; - if(!h) { - Awrite("Hexside not present, gamefile corrupted."); - break; - } - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try Again!"); - break; - } - int type = ParseHexside(pToken); - SAFE_DELETE( pToken ); - if(type < 0) { - Awrite("Try Again!"); - break; - } - pToken = pStr->gettoken(); - if(type == H_BRIDGE) { - if(pToken) { - h->bridge = pToken->value(); - } else { - if(h->bridge) h->bridge = 0; - else h->bridge = -1; - } - } else if (type == H_ROAD) { - if(pToken) { - h->road = pToken->value(); - } else { - if(h->road) h->road = 0; - else h->road = -1; - } - } else { - h->type = type; - } - } - else if (*pToken == "dh") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Specify a direction." ); - break; - } - int dir=-1; - dir = ParseHexsideDir(pToken); - SAFE_DELETE( pToken ); - if(dir < 0 || dir > 5) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - Hexside *h = pReg->hexside[dir]; - if(!h) { - Awrite("Hexside not present, gamefile corrupted."); - break; - } - h->bridge = 0; - h->road = 0; - h->type = 0; - } - else if (*pToken == "sink") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - int months = 0; - if(pToken) months = pToken->value(); - pReg->willsink = months; - } - else if (*pToken == "dg") { - SAFE_DELETE( pToken ); - if(pReg->gate > 0) { - int numgates = regions.numberofgates; - int found = 0; - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if (reg->gate == numgates) { - reg->gate = pReg->gate; - pReg->gate = 0; - regions.numberofgates--; - found = 1; - break; - } - } - if(!found) Awrite("Error: Could not find last gate"); - } - } - else if (*pToken == "ag") { - SAFE_DELETE( pToken ); - if(pReg->gate > 0) break; - regions.numberofgates++; - int gatenum = getrandom(regions.numberofgates) + 1; - if(gatenum != regions.numberofgates) { - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if(reg->gate == gatenum) reg->gate = regions.numberofgates; - } - } - pReg->gate = gatenum; - pReg->gatemonth = getrandom(12); - } - else if (*pToken == "w") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int val = pToken->value(); - SAFE_DELETE( pToken ); - if(val) { - int change = val - pReg->maxwages; - pReg->maxwages = val; - pReg->wages += change; - } - pReg->UpdateEditRegion(); - } - else if (*pToken == "p") { - SAFE_DELETE(pToken); - forlist((&pReg->products)) { - Production * p = ((Production *) elem); - if(p->itemtype!=I_SILVER) { - pReg->products.Remove(p); - delete p; - } - } - pReg->SetupProds(); - } - else if (*pToken == "g") { - SAFE_DELETE(pToken); - - if(pReg->town) delete pReg->town; - pReg->town = NULL; - - pReg->products.DeleteAll(); - pReg->SetupProds(); - - pReg->markets.DeleteAll(); - - pReg->SetupEditRegion(); - pReg->UpdateEditRegion(); - } - else if (*pToken == "n") { - SAFE_DELETE(pToken); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - *pReg->name = *pToken; - SAFE_DELETE(pToken); - } - else if (*pToken == "ncopy") { - SAFE_DELETE(pToken); - AString text = *pReg->name; - *pReg->name = AString(""); - pReg->EditAdjustAreaName(text); - } - else if (*pToken == "pop") { - SAFE_DELETE(pToken); - pToken = pStr->gettoken(); - int pop = 0; - if(pToken) { - pop = pToken->value(); - SAFE_DELETE(pToken); - } - if(!pop) { - Awrite( "Try again." ); - break; - } - pReg->population = pop; - pReg->UpdateEditRegion(); // financial stuff! Does markets - } - else if (*pToken == "townpop") { - SAFE_DELETE(pToken); - pToken = pStr->gettoken(); - int pop = 0; - if(pToken) { - pop = pToken->value(); - SAFE_DELETE(pToken); - } - if(!pop || !pReg->town) { - Awrite( "Try again." ); - break; - } - pReg->town->pop = pop; - pReg->town->basepop = pop; - pReg->UpdateEditRegion(); // financial stuff! Does markets - } - else if (*pToken == "tn") { - SAFE_DELETE(pToken); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - if(pReg->town) *pReg->town->name = *pToken; - SAFE_DELETE(pToken); - } - else if (*pToken == "town") { - SAFE_DELETE(pToken); - - if(pReg->race<0) pReg->race = I_NOMAD; - - AString *townname = new AString("name"); - if(pReg->town) { - *townname = *pReg->town->name; - delete pReg->town; - pReg->town = 0; - pReg->markets.DeleteAll(); - } - pReg->AddEditTown(townname); - pReg->UpdateEditRegion(); // financial stuff! Does markets - } - else if (*pToken == "deltown") { - SAFE_DELETE(pToken); - if(pReg->town) { - delete pReg->town; - pReg->town = NULL; - pReg->markets.DeleteAll(); - pReg->UpdateEditRegion(); - } - } - else if (*pToken == "v") { - if(pReg->town) EditGameRegionMarkets(pReg); - } - } while( 0 ); - if(pToken) delete pToken; - } - if(pStr) delete pStr; - - if( exit ) { - break; - } -} -while( 1 ); -} - -void Game::EditGameRegionMarkets( ARegion *pReg ) -{ -/* This only gets called if pReg->town exists! */ - do { - Awrite(""); - Awrite( AString( "Region: " ) + pReg->Print( ®ions ) ); - Awrite( "" ); -// write pop stuff - Awrite( AString("") + pReg->town->pop + " " + ItemDefs[pReg->race].names + " townpop"); - -//write markets - Awrite(AString("Market Format: ... price(base). minpop/maxpop. minamt/maxamt.")); - - Awrite("Wanted: "); - forlist(&pReg->markets) { - Market *m = (Market *) elem; - if (m->type == M_SELL) { - AString temp = ItemString(m->item, m->amount) + " at $" + m->price + "(" + m->baseprice + ")."; - temp += AString(" Pop: ") + m->minpop + "/" + m->maxpop + "."; - temp += AString(" Amount: ") + m->minamt + "/" + m->maxamt + "."; - Awrite(temp); - } - } - Awrite("For Sale: "); - forlist_reuse(&pReg->markets) { - Market *m = (Market *) elem; - if (m->type == M_BUY) { - AString temp = ItemString(m->item, m->amount) + " at $" + m->price + "(" + m->baseprice + ")."; - temp += AString(" Pop: ") + m->minpop + "/" + m->maxpop + "."; - temp += AString(" Amount: ") + m->minamt + "/" + m->maxamt + "."; - Awrite(temp); - } - } - - - Awrite( "" ); - - Awrite( " [g] to regenerate all markets" ); - Awrite( " [p] [item] [minpop] [maxpop] to add/modify market population" ); - Awrite( " [a] [item] [minamt] [maxamt] to add/modify market amounts" ); - Awrite( " [c] [item] [price] [baseprice] to add/modify item prices" ); - Awrite( " [s] [item] to swop an item between wanted and sold" ); - Awrite( " [d] [item] to delete an item from the market" ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - // regenerate markets - if (*pToken == "g") { - SAFE_DELETE(pToken); - - pReg->markets.DeleteAll(); - pReg->SetupCityMarket(); - pReg->UpdateEditRegion(); - } - else if (*pToken == "p") { - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int mitem = ParseEnabledItem(pToken); - if(mitem<0) { - Awrite("No such item"); - break; - } - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - int minimum = pToken->value(); - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - int maximum = pToken->value(); - SAFE_DELETE( pToken ); - - int done = 0; - - if(minimum + 1 > maximum) { - Awrite("Maximum must be more than minimum"); - break; - } - - int population = pReg->Population(); - - forlist(&pReg->markets) { - Market *m = (Market *) elem; - if(m->item == mitem) { - m->minpop = minimum; - m->maxpop = maximum; - - if (population <= m->minpop) - m->amount = m->minamt; - else { - if (population >= m->maxpop) - m->amount = m->maxamt; - else { - m->amount = m->minamt + ((m->maxamt - m->minamt) * - (population - m->minpop)) / - (m->maxpop - m->minpop); - } - } - done = 1; - } - } - - if(!done) { - int price = (ItemDefs[mitem].baseprice * (100 + getrandom(50))) / - 100; - Market *m = new Market(M_SELL, mitem, price, 0, minimum, maximum, 0, 0); - // m->PostTurn(pReg->Population(),pReg->Wages()); // updates amounts - pReg->markets.Add(m); - } - - } - else if (*pToken == "a") { - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int mitem = ParseEnabledItem(pToken); - if(mitem<0) { - Awrite("No such item"); - break; - } - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - int minimum = pToken->value(); - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - int maximum = pToken->value(); - SAFE_DELETE( pToken ); - - int done = 0; - - if(minimum + 1 > maximum) { - Awrite("Maximum must be more than minimum"); - break; - } - - int population = pReg->Population(); - - forlist(&pReg->markets) { - Market *m = (Market *) elem; - if(m->item == mitem) { - m->minamt = minimum; - m->maxamt = maximum; - - if (population <= m->minpop) - m->amount = m->minamt; - else { - if (population >= m->maxpop) - m->amount = m->maxamt; - else { - m->amount = m->minamt + ((m->maxamt - m->minamt) * - (population - m->minpop)) / - (m->maxpop - m->minpop); - } - } - done = 1; - } - } - - if(!done) { - int price = (ItemDefs[mitem].baseprice * (100 + getrandom(50))) / - 100; - int mamount = minimum + ( maximum * population / 5000 ); - Market *m = new Market(M_SELL, mitem, price, mamount, 0, 5000, minimum, maximum); - pReg->markets.Add(m); - } - - } - else if (*pToken == "c") { - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int mitem = ParseEnabledItem(pToken); - if(mitem<0) { - Awrite("No such item"); - break; - } - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - int price = pToken->value(); - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - int baseprice = pToken->value(); - SAFE_DELETE( pToken ); - - if(price<1 || baseprice<1) { - Awrite("Price must be more than zero"); - break; - } - - int done = 0; - - - forlist(&pReg->markets) { - Market *m = (Market *) elem; - if(m->item == mitem) { - m->price = price; - m->baseprice = baseprice; - done = 1; - } - } - - if(!done) { - Market *m = new Market(M_SELL, mitem, price, 0, 0, 5000, 0, 0); - m->baseprice = baseprice; - pReg->markets.Add(m); - } - - } - else if (*pToken == "s") { - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int mitem = ParseEnabledItem(pToken); - if(mitem<0) { - Awrite("No such item"); - break; - } - SAFE_DELETE( pToken ); - - int done = 0; - forlist(&pReg->markets) { - Market *m = (Market *) elem; - if(m->item == mitem) { - if(!done) { - if(m->type == M_SELL) m->type = M_BUY; - else m->type = M_SELL; - done = 1; - } else { - pReg->markets.Remove(m); - delete m; - } - } - } - if(!done) Awrite("No such market"); - } - else if (*pToken == "d") { - SAFE_DELETE(pToken); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int mitem = ParseEnabledItem(pToken); - if(mitem<0) { - Awrite("No such item"); - break; - } - SAFE_DELETE( pToken ); - - int done = 0; - forlist(&pReg->markets) { - Market *m = (Market *) elem; - if(m->item == mitem) { - pReg->markets.Remove(m); - delete m; - done = 1; - } - } - if(!done) Awrite("No such market"); - } - } while( 0 ); - if(pToken) delete pToken; - } - if(pStr) delete pStr; - - if( exit ) { - break; - } - } while( 1 ); -} - - -void Game::EditGameRegionExits(ARegion *pReg) -{ - do { - Awrite(""); - Awrite( AString( "Region: " ) + pReg->Print( ®ions ) ); - Awrite(""); - Awrite("Exits:"); - - int y=0; - for (int i=0; ineighbors[i]; - if (r) { - AString temp = AString(DirectionStrs[i]) + ": " + r->Print(®ions); - - Hexside *h = pReg->hexside[i]; - if(h && h->type) temp += AString(", ") + HexsideDefs[h->type].name; - if(h && h->road != 0) { - temp += AString(", ") + HexsideDefs[H_ROAD].name; - if(h->road > 0) temp += AString(" (needs ") + h->road + ")"; - } - if(h && h->bridge != 0) { - temp += AString(", ") + HexsideDefs[H_BRIDGE].name; - if(h->bridge > 0) temp += AString(" (needs ") + h->bridge + ")"; - } - temp += "."; - - int compdir = (i+3)%6; - if(r->neighbors[compdir] && r->neighbors[compdir] == pReg) temp += " (two-way)."; - else temp += " (one-way)."; - - Awrite(temp); - y = 1; - } - else { - if(pReg->hexside[i]->type) { - Hexside *h = pReg->hexside[i]; - AString temp = AString(DirectionStrs[i]) + " : "; - if(h && h->type) temp += HexsideDefs[h->type].name; - - temp += "."; - - Awrite(temp); - y = 1; - } - } - } - if (!y) Awrite("none"); - - Awrite( "" ); - Awrite( " [d] [dir] to remove that connection." ); - Awrite( " [a] [dir] to add a default (two-way) connection." ); - Awrite( " [s] [dir] [x] [y] [z] to add a specific (one-way) connection to region x,y,z." ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - - // add object - if (*pToken == "d") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int dir = ParseHexsideDir(pToken); - if(dir<0) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - SAFE_DELETE( pToken ); - - ARegion *regiontwo = pReg->neighbors[dir]; - if(!regiontwo) { - Awrite("There is no connection in that direction."); - break; - } - //Have to remove the link, and create a new hexside. - int compdir = pReg->GetRealDirComp(dir); - if(regiontwo->neighbors[compdir] == pReg) { - regiontwo->neighbors[compdir] = 0; - regiontwo->hexside[compdir]->type = H_DUMMY; - regiontwo->hexside[compdir]->bridge = 0; - regiontwo->hexside[compdir]->road = 0; - Hexside *temp = new Hexside; - pReg->hexside[dir] = temp; - } - pReg->neighbors[dir] = 0; - - - } - // add connection - else if (*pToken == "a") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int dir = ParseHexsideDir(pToken); - if(dir<0) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - SAFE_DELETE( pToken ); - - if(pReg->neighbors[dir]) { - Awrite("There is already a connection in that direction."); - break; - } - - ARegion *regiontwo = 0; - ARegionArray *ar = regions.GetRegionArray(pReg->zloc); - //Have to add a link, and delete one of the hexsides. - switch(dir) { - case D_NORTH: - if(pReg->yloc >=2 ) regiontwo = ar->GetRegion(pReg->xloc, pReg->yloc - 2); - break; - case D_NORTHEAST: - if(pReg->yloc >=1 ) regiontwo = ar->GetRegion(pReg->xloc + 1, pReg->yloc - 1); - break; - case D_NORTHWEST: - if(pReg->yloc >=1 ) regiontwo = ar->GetRegion(pReg->xloc - 1, pReg->yloc - 1); - break; - case D_SOUTHEAST: - if(pReg->yloc < ar->y - 1 ) regiontwo = ar->GetRegion(pReg->xloc + 1, pReg->yloc + 1); - break; - case D_SOUTHWEST: - if(pReg->yloc < ar->y - 1 ) regiontwo = ar->GetRegion(pReg->xloc - 1, pReg->yloc + 1); - break; - case D_SOUTH: - if(pReg->yloc < ar->y - 2 ) regiontwo = ar->GetRegion(pReg->xloc, pReg->yloc + 2); - break; - default: - Awrite("Unrecognised direction."); - break; - } - if(!regiontwo) { - Awrite("No default connection can be found."); - break; - } - int compdir = (dir+3)%6; - if(regiontwo->neighbors[compdir]) { - Awrite("Default neighbour is already connected."); - break; - } - //setup neighbours - regiontwo->neighbors[compdir] = pReg; - pReg->neighbors[dir] = regiontwo; - //combine hexsides - delete regiontwo->hexside[compdir]; // since this was not connected, no other region should point to this - regiontwo->hexside[compdir] = pReg->hexside[dir]; - } - else if (*pToken == "s") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int dir = ParseHexsideDir(pToken); - if(dir<0) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - SAFE_DELETE( pToken ); - if(pReg->neighbors[dir]) { - Awrite("There is already a connection in that direction."); - break; - } - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int x = pToken->value(); - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int y = pToken->value(); - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int z = pToken->value(); - SAFE_DELETE( pToken ); - - ARegion *regiontwo = regions.GetRegion(x,y,z); - if(!regiontwo) { - Awrite( "Cannot find that region." ); - break; - } - - pReg->neighbors[dir] = regiontwo; - int compdir = pReg->GetRealDirComp(dir); - if(regiontwo->neighbors[compdir] == pReg) { - //this linkage is two-way. Combine hexsides if they are different. - if(pReg->hexside[dir] != regiontwo->hexside[compdir]) { - delete regiontwo->hexside[compdir]; - regiontwo->hexside[compdir] = pReg->hexside[dir]; - } - } - } - } while( 0 ); - if(pToken) delete pToken; - } - - if(pStr) delete pStr; - if( exit ) break; - } while(1); -} - -ARegion * Game::EditGameRegionNavigate(ARegion *pReg) -{ - do { - Awrite(""); - Awrite( AString( "Region: " ) + pReg->Print( ®ions ) ); - Awrite(""); - Awrite("Exits:"); - - int y=0; - for (int i=0; ineighbors[i]; - if (r) { - AString temp = AString(DirectionStrs[i]) + " : " + r->Print(®ions); - - Hexside *h = pReg->hexside[i]; - if(h && h->type) temp += AString(", ") + HexsideDefs[h->type].name; - if(h && h->road != 0) { - temp += AString(", ") + HexsideDefs[H_ROAD].name; - if(h->road > 0) temp += AString(" (needs ") + h->road + ")"; - } - if(h && h->bridge != 0) { - temp += AString(", ") + HexsideDefs[H_BRIDGE].name; - if(h->bridge > 0) temp += AString(" (needs ") + h->bridge + ")"; - } - temp += "."; - - Awrite(temp); - y = 1; - } - else { - if(pReg->hexside[i]->type) { - Hexside *h = pReg->hexside[i]; - AString temp = AString(DirectionStrs[i]) + " : "; - if(h && h->type) temp += HexsideDefs[h->type].name; - - temp += "."; - - Awrite(temp); - y = 1; - } - } - } - if (!y) Awrite("none"); - - Awrite( "" ); - Awrite( " [dirs] to move to the region in that direction(s)." ); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "q" ) { - exit = 1; - } else { - pReg = EditGameRegionNavigate(pReg, pStr); - } - - if(pStr) delete pStr; - if( exit ) break; - } while(1); - return pReg; -} - -ARegion * Game::EditGameRegionNavigate(ARegion *pReg, AString *pStr) -{ - AString *pToken = 0; - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - return pReg; - } - - do { - int dir = ParseHexsideDir(pToken); - if(dir<0) { - Awrite("Incorrect direction. Use N,NE,SE,S,SW,NW"); - break; - } - SAFE_DELETE( pToken ); - - ARegion *regiontwo = pReg->neighbors[dir]; - if(!regiontwo) { - Awrite("There is no connection in that direction."); - break; - } - pReg = regiontwo; - pToken = pStr->gettoken(); - } while( pToken ); - - if(pToken) delete pToken; - //pStr deleted in calling function - return pReg; -} - - - -void Game::EditGameUnit(Unit *pUnit) -{ - do { - Awrite(AString("Unit: ") + *(pUnit->name)); - Awrite(AString("Faction: ") + pUnit->faction->num); - Awrite(AString(" in ") + - pUnit->object->region->ShortPrint(®ions)); - Awrite(" 1) Edit items..."); - Awrite(" 2) Edit skills..."); - Awrite(" 3) Move unit..."); - Awrite(" 4) Edit details..."); - - Awrite(" q) Stop editing this unit."); - - int exit = 0; - AString *pStr = AGetString(); - if(*pStr == "1") { - EditGameUnitItems(pUnit); - } else if(*pStr == "2") { - EditGameUnitSkills(pUnit); - } else if(*pStr == "3") { - EditGameUnitMove(pUnit); - } else if(*pStr == "4") { - EditGameUnitDetails(pUnit); - } else if(*pStr == "q") { - exit = 1; - } else { - Awrite("Select from the menu."); - } - delete pStr; - - if(exit) { - break; - } - } while(1); -} - -void Game::EditGameUnitItems(Unit *pUnit) -{ - do { - int exit = 0; - Awrite(AString("Unit items: ") + pUnit->items.Report(2, 1, 1)); - Awrite(" [item] [number] to update an item."); - Awrite(" q) Stop editing the items."); - AString *pStr = AGetString(); - if(*pStr == "q") { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again."); - break; - } - - int itemNum = ParseAllItems(pToken); - if(itemNum == -1) { - Awrite("No such item."); - break; - } - if(ItemDefs[itemNum].flags & ItemType::DISABLED) { - Awrite("No such item."); - break; - } - SAFE_DELETE(pToken); - - int num; - pToken = pStr->gettoken(); - if(!pToken) { - num = 0; - } else { - num = pToken->value(); - } - - pUnit->items.SetNum(itemNum, num); - /* Mark it as known about for 'shows' */ - pUnit->faction->items.SetNum(itemNum, 1); - } while(0); - if(pToken) delete pToken; - } - if(pStr) delete pStr; - - if(exit) { - break; - } - } while(1); -} - -void Game::EditGameUnitSkills(Unit *pUnit) -{ - do { - int exit = 0; - Awrite(AString("Unit skills: ") + - pUnit->skills.Report(pUnit->GetMen())); - Awrite(" [skill] [days] to update a skill."); - Awrite(" q) Stop editing the skills."); - AString *pStr = AGetString(); - if(*pStr == "q") { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again."); - break; - } - - int skillNum = ParseSkill(pToken); - if(skillNum == -1) { - Awrite("No such skill."); - break; - } - if(SkillDefs[skillNum].flags & SkillType::DISABLED) { - Awrite("No such skill."); - break; - } - SAFE_DELETE(pToken); - - int days; - pToken = pStr->gettoken(); - if(!pToken) { - days = 0; - } else { - days = pToken->value(); - } - SAFE_DELETE(pToken); - - int exper; - pToken = pStr->gettoken(); - if(!pToken || !Globals->REAL_EXPERIENCE) { - exper = 0; - } else { - exper = pToken->value(); - } - - if((SkillDefs[skillNum].flags & SkillType::MAGIC) && - (pUnit->type != U_MAGE)) { - } - if((SkillDefs[skillNum].flags & SkillType::APPRENTICE) && - (pUnit->type == U_NORMAL)) { - pUnit->type = U_APPRENTICE; - } - pUnit->skills.SetDays(skillNum, days * pUnit->GetMen(), exper * pUnit->GetMen()); - int lvl = pUnit->GetRealSkill(skillNum); - if(lvl > pUnit->faction->skills.GetDays(skillNum)) { - pUnit->faction->skills.SetDays(skillNum, lvl); - } - } while(0); - delete pToken; - } - delete pStr; - - if(exit) { - break; - } - } while(1); -} - -void Game::EditGameUnitMove(Unit *pUnit) -{ - ARegion *pReg = EditGameFindRegion(); - if(!pReg) return; - - pUnit->MoveUnit(pReg->GetDummy()); -} - -void Game::EditGameUnitDetails(Unit *pUnit) -{ - do { - int exit = 0; - Awrite(AString("Unit: ") + *(pUnit->name)); - if(pUnit->describe) Awrite(AString("Description: ") + *(pUnit->describe)); - Awrite(AString("Unit faction: ") + - *(pUnit->faction->name)); - AString temp; - switch(pUnit->type) { - case U_NORMAL: - temp = AString(" (normal)"); - break; - case U_SPECIALIST: - temp = AString(" (specialist)"); - break; - case U_LEADER: - temp = AString(" (leader)"); - break; - case U_MAGE: - temp = AString(" (mage)"); - break; - case U_GUARD: - temp = AString(" (guard)"); - break; - case U_WMON: - temp = AString(" (monster)"); - break; - case U_GUARDMAGE: - temp = AString(" (guardmage)"); - break; - case U_APPRENTICE: - temp = AString(" (apprentice)"); - break; - } - Awrite(AString("Unit type: ") + pUnit->type + temp); - if(pUnit->type == U_MAGE && Globals->ARCADIA_MAGIC) { - temp = AString("Unit mortality: "); - if(pUnit->dead) temp += "dead"; - else temp += "alive"; - Awrite(temp); - Awrite(AString("Unit energy: ") + pUnit->energy + "/" + pUnit->MaxEnergy()); - if(pUnit->resurrects) Awrite(AString("This unit has been resurrected ") + pUnit->resurrects + " times."); - AString temp = "none"; - } - Awrite(AString("Unit is in object ") + *pUnit->object->name + " : " + ObjectDefs[pUnit->object->type].name); - - Awrite(""); - Awrite(" [f] [num] to change the unit's faction."); - Awrite(" [t] [num] to change the unit's type."); - Awrite(" [n] [name] to change the unit's name."); - Awrite(" [c] [description] to change the unit's description."); - Awrite(" [enter] [num] to enter an object."); - if(pUnit->type == U_MAGE) { - Awrite(" [d] to change the unit's death status."); - Awrite(" [e] [num] to change the unit's energy."); - } - Awrite(" [q] Go back one screen."); - - AString *pStr = AGetString(); - if(*pStr == "q") { - exit = 1; - } - else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again."); - break; - } - // change faction - if (*pToken == "f") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int fnum = pToken->value(); - SAFE_DELETE( pToken ); - if(fnum<1) { - Awrite("Invalid Faction Number"); - break; - } - Awrite("fetching faction"); - Faction *fac = GetFaction(&factions, fnum); - Awrite("back"); - if(fac) pUnit->faction = fac; - else Awrite("Cannot Find Faction"); - Awrite("done"); - } - else if (*pToken == "d") { - SAFE_DELETE( pToken ); - if(pUnit->type != U_MAGE) { - Awrite("Warning: This only has an effect on mage units."); - } - if(!pUnit->dead) { - pUnit->dead = 1; /* If the unit is not a mage, this will not get saved in the game.out file - and will thus be reset to zero when the game is loaded */ - Faction *fac = GetFaction(&factions, ghostfaction); - if(fac) pUnit->faction = fac; - else Awrite("Warning: Cannot Find Ghost Faction"); - } else { - pUnit->dead = 0; - Faction *fac = GetFaction(&factions, guardfaction); - if(fac) pUnit->faction = fac; - else Awrite("Warning: Cannot Find Guard Faction"); - } - - } - else if (*pToken == "e") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int newenergy = pToken->value(); - if(newenergy > pUnit->MaxEnergy()) newenergy = pUnit->MaxEnergy(); - - if(pUnit->type == U_MAGE) { - pUnit->energy = newenergy; - } - } - else if (*pToken == "t") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int newtype = pToken->value(); - SAFE_DELETE( pToken ); - if(newtype<0 || newtype>NUNITTYPES-1) { - Awrite("Invalid Type"); - break; - } - pUnit->type = newtype; - } - else if (*pToken == "n") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - AString *name = new AString(*pToken); - SAFE_DELETE( pToken ); - pUnit->SetName(name); - } - else if (*pToken == "c") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - AString *desc = new AString(*pToken); - SAFE_DELETE( pToken ); - pUnit->SetDescribe(desc); - } - else if (*pToken == "enter") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int objnum = pToken->value(); - SAFE_DELETE( pToken ); - Object *to = pUnit->object->region->GetObject(objnum); - if(!to) { - Awrite("No such object"); - break; - } - pUnit->MoveUnit(to); - } - } while(0); - delete pToken; - } - delete pStr; - - if(exit) { - break; - } - } while(1); -} - -void Game::EditGameCreateUnit() -{ - Faction *fac = GetFaction(&factions, 1); - Unit *newunit = GetNewUnit(fac); - if(!(ItemDefs[I_LEADERS].flags & ItemType::DISABLED)) newunit->SetMen(I_LEADERS, 1); - newunit->reveal = REVEAL_FACTION; - newunit->MoveUnit(((ARegion *) regions.First())->GetDummy()); - - EditGameUnit(newunit); -} - -void Game::EditGameGlobalEffects() -{ - do { - Awrite(""); - - - if(Globals->ARCADIA_MAGIC) Awrite( " [sink] [num] to set all land regions to sink" ); - if(Globals->HEXSIDE_TERRAIN) Awrite( " [remove] [feature] to remove rivers, bridges or roads "); - Awrite( " [ocean] [level] to convert the specified level to ocean. "); - Awrite( " [clearbarriers] [level] to reset all neighbours in the specified level. "); - Awrite( " [renumber] to renumber all buildings (do after extensive map design). "); - Awrite( " [buildingseq] to set all buildingseqs to minimum allowed value without changing building numbers" ); - Awrite( " [markets] [cycles] to regenerate all markets in the world. Use cycles for advanced balancing." ); - Awrite( " [addpop] [num] to change all town populations by [num] "); - Awrite( " [regenproducts] [level] to regenerate all products on the specified level. "); - Awrite( " [trade] to provide a trade summary "); - Awrite( " [products] to provide a production summary "); - Awrite( " [buildings] to provide a buildings summary "); - Awrite( " [rename] [terrain] [level] [name] to rename all of a terrain type on a level. "); - Awrite( " [importmap] [level] [filename] to set the terrain/cities of a level according to a text file."); - Awrite( " [importeth] [level] [filename] to set the ethnicities/flagpoles of a level according to a text file."); - Awrite( " [importriv] [level] [filename] to set the rivers/bridges of a level according to a text file."); - Awrite( " [resetgates] [level] [frequency] to reset gates on specified level."); - Awrite( " [makexan] to make Xanaxor."); - Awrite( " [genguards] to regenerate all guard units."); - Awrite( " q) Return to previous menu." ); - - int exit = 0; - AString *pStr = AGetString(); - if( *pStr == "q" ) { - exit = 1; - } else { - AString *pToken = 0; - do { - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - if (*pToken == "sink") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int months = pToken->value(); - SAFE_DELETE( pToken ); - if(months < 1) { - Awrite("Try again!"); - break; - } - forlist(®ions) { - ARegion *pReg = (ARegion *) elem; - if(TerrainDefs[pReg->type].similar_type != R_OCEAN && pReg->zloc == 1) - pReg->willsink = months; - } - } - else if (*pToken == "remove") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(*pToken == "rivers") { - forlist(®ions) { - ARegion *pReg = (ARegion *) elem; - for(int i=0; i<6; i++) { - if(pReg->hexside[i]->type == H_RIVER) pReg->hexside[i]->type = H_DUMMY; - } - } - } else if(*pToken == "bridges") { - forlist(®ions) { - ARegion *pReg = (ARegion *) elem; - for(int i=0; i<6; i++) pReg->hexside[i]->bridge = 0; - } - } else if(*pToken == "roads") { - forlist(®ions) { - ARegion *pReg = (ARegion *) elem; - for(int i=0; i<6; i++) pReg->hexside[i]->road = 0; - } - } - } else if (*pToken == "ocean") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again!"); - break; - } - int level = pToken->value(); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(r->zloc == level) { - r->SinkRegion(®ions); - r->type = R_OCEAN; //prevents lakes appearing in UW levels where there are barriers - } - } - } else if (*pToken == "markets") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - int reduce = 0; - if(pToken) { - reduce = pToken->value(); - SAFE_DELETE( pToken ); - } - forlist(®ions) { - ARegion *r = (ARegion *) elem; - r->markets.DeleteAll(); - if(r->town) r->SetupCityMarket(); - r->UpdateEditRegion(); - } - int score = GetMarketTradeVariance(); - int tries = 0; - while(reduce && tries++ < 500) { - forlist(®ions) { - ARegion *r = (ARegion *) elem; - r->markets.DeleteAll(); - if(r->town) r->SetupCityMarket(); - r->UpdateEditRegion(); - } - int temp = GetMarketTradeVariance(); - if(temp < score) { - score = temp; - reduce--; - } - } - } else if (*pToken == "regenproducts") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again!"); - break; - } - int level = pToken->value(); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(r->zloc == level) { - forlist((&r->products)) { - Production * p = ((Production *) elem); - if(p->itemtype != I_SILVER) { - r->products.Remove(p); - delete p; - } - } - r->SetupProds(); - } - } - } else if (*pToken == "clearbarriers") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again!"); - break; - } - int level = pToken->value(); - - ARegionArray *ar = regions.GetRegionArray(level); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(r->zloc == level) regions.EditNeighSetup(r,ar); - } - } else if (*pToken == "addpop") { - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again!"); - break; - } - int amount = pToken->value(); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(r->town) r->town->pop += amount; - } - } else if (*pToken == "renumber") { - SAFE_DELETE( pToken ); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - int buildingnum = 1; - forlist(&r->objects) { - Object *o = (Object *) elem; - if(o->type == O_DUMMY) o->num = 0; - else { - o->num = buildingnum++; - - AString *newname = o->name->getlegal(); - AString *temp = newname->Trunc(newname->Len()-3); //temp gets deleted with newname. - if(!newname) { - newname = new AString("Building"); - } - delete o->name; - - AString *newname2 = new AString(newname->Str()); - *newname2 += AString(" [") + o->num + "]"; - delete newname; - o->name = newname2; - if(temp) delete temp; - } - } - r->buildingseq = buildingnum; - } - } else if (*pToken == "rename") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int terType = ParseTerrain(pToken); - if(terType == -1) { - Awrite( "No such terrain." ); - break; - } - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again!"); - break; - } - int level = pToken->value(); - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "No name given." ); - break; - } - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(r->zloc == level && r->type == terType) { - *r->name = *pToken; - } - } - SAFE_DELETE(pToken); - } else if (*pToken == "importmap") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int level = pToken->value(); - if(level == -1) { - Awrite( "Invalid level." ); - break; - } - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(pToken) ImportMapFile(pToken, level); - SAFE_DELETE( pToken ); - } else if (*pToken == "importeth") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int level = pToken->value(); - if(level == -1) { - Awrite( "Invalid level." ); - break; - } - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(pToken) ImportEthFile(pToken, level); - SAFE_DELETE( pToken ); - } else if (*pToken == "importriv") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int level = pToken->value(); - if(level == -1) { - Awrite( "Invalid level." ); - break; - } - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if(pToken) ImportRivFile(pToken, level); - SAFE_DELETE( pToken ); - } else if (*pToken == "genguards") { - Awrite("Clearing City Guards"); - forlist(®ions) { - ARegion *reg = (ARegion *)elem; -// if(!reg->town) continue; // temp fix to stop clearing regional guards - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - if(u->type == U_GUARD || u->type == U_GUARDMAGE) reg->Kill(u); - } - if (ObjectDefs[obj->type].protect > 0) CreateFortMon(reg,obj); - } - } - Awrite("Making City Guards"); - CreateCityMons(); - } else if (*pToken == "makexan") { - SAFE_DELETE( pToken ); - - //clearing all units - forlist(®ions) { - ARegion *reg = (ARegion *)elem; - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - reg->Kill(u); - } - } - } - - ImportMapFile(new AString("xanaxor.txt"), 1); - ImportEthFile(new AString("xanaxoreth.txt"), 1); - ImportRivFile(new AString("xanaxorriv.txt"), 1); - ImportFortFile(new AString("xanaxorfort.txt"), 1); - - int frequency = 10; - - forlist_reuse(®ions) { - ARegion *r = (ARegion *) elem; - //reset building sequence - int maxnum = 0; - forlist(&r->objects) { - Object *o = (Object *) elem; - if(o->num > maxnum) maxnum = o->num; - } - r->buildingseq = maxnum + 1; - - //delete or make gates as necessary - int needsgate = 0; - if(TerrainDefs[r->type].similar_type != R_OCEAN) needsgate = !getrandom(frequency); - if(r->gate > 0 && !needsgate) { - //remove gate - int numgates = regions.numberofgates; - int found = 0; - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if (reg->gate == numgates) { - reg->gate = r->gate; - r->gate = 0; - regions.numberofgates--; - found = 1; - break; - } - } - if(!found) Awrite("Error: Could not find last gate"); - } else if(r->gate == 0 && needsgate) { - //add gate - regions.numberofgates++; - int gatenum = getrandom(regions.numberofgates) + 1; - if(gatenum != regions.numberofgates) { - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if(reg->gate == gatenum) reg->gate = regions.numberofgates; - } - } - r->gate = gatenum; - r->gatemonth = getrandom(12); - } - } - } else if (*pToken == "resetgates") { - SAFE_DELETE( pToken ); - - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Try again." ); - break; - } - int level = pToken->value(); - if(level == -1) { - Awrite( "Invalid level." ); - break; - } - SAFE_DELETE( pToken ); - pToken = pStr->gettoken(); - if( !pToken ) { - Awrite( "Invalid frequency." ); - break; - } - int frequency = pToken->value(); - SAFE_DELETE( pToken ); - if( frequency < 1 ) { - Awrite( "Invalid frequency." ); - break; - } - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - int needsgate = 0; - if(TerrainDefs[r->type].similar_type != R_OCEAN) needsgate = !getrandom(frequency); - if(r->gate > 0 && !needsgate) { - //remove gate - int numgates = regions.numberofgates; - int found = 0; - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if (reg->gate == numgates) { - reg->gate = r->gate; - r->gate = 0; - regions.numberofgates--; - found = 1; - break; - } - } - if(!found) Awrite("Error: Could not find last gate"); - } else if(r->gate == 0 && needsgate) { - //add gate - regions.numberofgates++; - int gatenum = getrandom(regions.numberofgates) + 1; - if(gatenum != regions.numberofgates) { - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if(reg->gate == gatenum) reg->gate = regions.numberofgates; - } - } - r->gate = gatenum; - r->gatemonth = getrandom(12); - } - } - } else if (*pToken == "buildingseq") { - SAFE_DELETE( pToken ); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - int maxnum = 0; - forlist(&r->objects) { - Object *o = (Object *) elem; - if(o->num > maxnum) maxnum = o->num; - } - r->buildingseq = maxnum + 1; - } - } else if (*pToken == "trade") { - SAFE_DELETE( pToken ); - EditGameTradeSummary(); - } else if (*pToken == "products") { - SAFE_DELETE( pToken ); - EditGameProductsSummary(); - } else if (*pToken == "buildings") { - SAFE_DELETE( pToken ); - EditGameBuildingsSummary(); - } - } while( 0 ); - if(pToken) delete pToken; - } - if(pStr) delete pStr; - - if( exit ) { - break; - } - } - while( 1 ); -} - -void Game::ImportFortFile(AString *filename, int level) -{ - Ainfile f; - if(f.OpenByName(*filename) == -1) { - Awrite("Could not open file."); - return; - } - - int yy = 0; - AString *line = f.GetStr(); - - int maxx = regions.GetRegionArray(level)->x; - int maxy = regions.GetRegionArray(level)->y; - - while(line && yy <= maxy) { - AString *type = line->gettoken(); - int xx = yy%2; - - while(type && xx <= maxx) { - ARegion *pReg = regions.GetRegion(xx,yy,level); - if(pReg) { - forlist(&pReg->objects) { - Object *o = (Object *) elem; - if(o->type == O_DUMMY) continue; - - forlist(&o->units) { - Unit *u = (Unit *) elem; - pReg->Kill(u); - } - pReg->objects.Remove(o); - } - - int forttype = -1; - if (*type == "t") forttype = O_TOWER; - else if (*type == "f") forttype = O_FORT; - else if (*type == "c") forttype = O_CASTLE; - else if (*type == "i") forttype = O_CITADEL; - else if (*type == "m") forttype = O_MFORTRESS; - else if (*type == "1") forttype = TerrainDefs[pReg->type].lairs[0]; - else if (*type == "2") forttype = TerrainDefs[pReg->type].lairs[1]; - else if (*type == "3") forttype = TerrainDefs[pReg->type].lairs[2]; - else if (*type == "4") forttype = TerrainDefs[pReg->type].lairs[3]; - else if (*type == "5") forttype = TerrainDefs[pReg->type].lairs[4]; - else if (*type == "6") forttype = TerrainDefs[pReg->type].lairs[5]; - if(forttype > -1) { - ARegion *pReg = regions.GetRegion(xx,yy,level); - pReg->MakeLair(forttype); - forlist(&pReg->objects) { - Object *o = (Object *) elem; - if (o->units.Num()) continue; - if (ObjectDefs[o->type].monster != -1) MakeLMon(o); - if (ObjectDefs[o->type].protect > 0) CreateFortMon(pReg,o); - } - } - } - xx += 2; - delete type; - type = line->gettoken(); - } - yy += 1; - if(line) delete line; - line = f.GetStr(); - } -} - -void Game::ImportRivFile(AString *filename, int level) -{ - Ainfile f; - if(f.OpenByName(*filename) == -1) { - Awrite("Could not open file."); - return; - } - - int yy = 0; - AString *line = f.GetStr(); - - int maxx = regions.GetRegionArray(level)->x; - int maxy = regions.GetRegionArray(level)->y; - - while(line && yy <= maxy) { - AString *type = line->gettoken(); - int xx = yy%2; - - while(type && xx <= maxx) { - int rivers = type->value()%10; -// int bridges = (type->value()/10)%10; //not implemented below yet - - ARegion *pReg = regions.GetRegion(xx,yy,level); - //prevent stupid input making rivers in oceans - if(TerrainDefs[pReg->type].similar_type == R_OCEAN) rivers = 0; - if(pReg) { - Hexside *h1 = pReg->hexside[0]; - Hexside *h2 = pReg->hexside[1]; - Hexside *h4 = pReg->hexside[2]; - if(rivers%2 && (!pReg->neighbors[0] || TerrainDefs[pReg->neighbors[0]->type].similar_type != R_OCEAN)) h1->type = H_RIVER; - else if(h1->type == H_RIVER) h1->type = H_DUMMY; - if((rivers%4 > 1) && (!pReg->neighbors[1] || TerrainDefs[pReg->neighbors[1]->type].similar_type != R_OCEAN)) h2->type = H_RIVER; - else if(h2->type == H_RIVER) h2->type = H_DUMMY; - if((rivers%8 > 3) && (!pReg->neighbors[2] || TerrainDefs[pReg->neighbors[2]->type].similar_type != R_OCEAN)) h4->type = H_RIVER; - else if(h4->type == H_RIVER) h4->type = H_DUMMY; - } - xx += 2; - delete type; - type = line->gettoken(); - } - yy += 1; - if(line) delete line; - line = f.GetStr(); - } - Awrite("Done Rivers."); -} - -void Game::ImportEthFile(AString *filename, int level) -{ - Ainfile f; - if(f.OpenByName(*filename) == -1) { - Awrite("Could not open file."); - return; - } - - int yy = 0; - AString *line = f.GetStr(); - - int maxx = regions.GetRegionArray(level)->x; - int maxy = regions.GetRegionArray(level)->y; - - while(line && yy <= maxy) { - AString *type = line->gettoken(); - int xx = yy%2; - - while(type && xx <= maxx) { - int ethnicity = -1; - - if (*type == "d") ethnicity = RA_DWARF; - else if (*type == "e") ethnicity = RA_ELF; - else if (*type == "h") ethnicity = RA_HUMAN; - else if (*type == "o") ethnicity = RA_OTHER; - else if (*type == "r") ethnicity = getrandom(RA_NA); - - ARegion *pReg = regions.GetRegion(xx,yy,level); - if(pReg) { - if(ethnicity != -1) pReg->SetEthnicity(ethnicity, ®ions); - //extra feature flagpoling: - char *str = type->Str(); - if(*str >= 'A' && *str <= 'Z') { - pReg->flagpole = FL_UNUSED_START_LOC; - - //startup cities get named "Starter" - if(Globals->TESTGAME_ENABLED && pReg->town) { - AString *newname = new AString(EthnicityString(ethnicity) + " Start"); - delete pReg->town->name; - pReg->town->name = newname; - } - - } else pReg->flagpole = FL_NULL; - } - xx += 2; - delete type; - type = line->gettoken(); - } - yy += 1; - if(line) delete line; - line = f.GetStr(); - } - - Awrite("Clearing City Guards"); - forlist(®ions) { - ARegion *reg = (ARegion *)elem; - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - if(u->type == U_GUARD || u->type == U_GUARDMAGE) reg->Kill(u); - } - } - } - Awrite("Making City Guards"); - CreateCityMons(); - Awrite("Done Ethnicities."); -} - -void Game::ImportMapFile(AString *filename, int level) -{ - Ainfile f; - if(f.OpenByName(*filename) == -1) { - Awrite("Could not open file."); - return; - } - - int yy = 0; - AString *line = f.GetStr(); - - int maxx = regions.GetRegionArray(level)->x; - int maxy = regions.GetRegionArray(level)->y; - - while(line && yy <= maxy) { - AString *type = line->gettoken(); - int xx = yy%2; - - while(type && xx <= maxx) { - int regiontype = -1; - int iscity = 0; //0 means no city, 1 means city, -1 means random - - if (*type == "d") regiontype = R_DESERT; - else if (*type == "f") regiontype = R_FOREST; - else if (*type == "j") regiontype = R_JUNGLE; - else if (*type == "l") regiontype = R_LAKE; - else if (*type == "m") regiontype = R_MOUNTAIN; - else if (*type == "o") regiontype = R_OCEAN; - else if (*type == "p") regiontype = R_PLAIN; - else if (*type == "s") regiontype = R_SWAMP; - else if (*type == "t") regiontype = R_TUNDRA; - else if (*type == "a") regiontype = R_PARADISE; - - char *str = type->Str(); - if(*str >= 'A' && *str <= 'Z') iscity = 1; - - if(regiontype > -1) { - ARegion *pReg = regions.GetRegion(xx,yy,level); - if(pReg) pReg->RedoAs(regiontype, iscity, ®ions); - } - xx += 2; - delete type; - type = line->gettoken(); - } - yy += 1; - if(line) delete line; - line = f.GetStr(); - } - -#define NUMREGIONNAMES 1000 - - Awrite("Clearing City Guards / Setting Region Names"); - forlist(®ions) { - ARegion *reg = (ARegion *)elem; - AString *name = 0; - if(TerrainDefs[reg->type].similar_type == R_OCEAN) { - name = new AString(Globals->WORLD_NAME); - *name += " Ocean"; - } else { - for(int i=0; i 1 && i < 5) continue; - if(reg->neighbors[i] && reg->neighbors[i]->type == reg->type) name = new AString(*(reg->neighbors[i]->name)); - } - if(!name) name = new AString(AGetNameString(NUMREGIONNAMES + getrandom(NUMREGIONNAMES))); - } - reg->SetName((*name).Str()); - delete name; - - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - if(u->type == U_GUARD || u->type == U_GUARDMAGE) reg->Kill(u); - } - } - } - Awrite("Making City Guards"); - CreateCityMons(); - Awrite("Done."); -} - - -void ARegion::SetEthnicity(int ethnicity, ARegionList *pRegs) -{ -Awrite(EthnicityString(ethnicity)); - int chance = getrandom(100); - - switch(type) { - case R_OCEAN: - race = I_MERMEN; - break; - case R_LAKE: - race = I_MERMEN; - break; - //raiders = I_VIKING - //ancient elves = I_DARKMAN - //plain dwarves = I_PLAINSMAN - case R_MOUNTAIN: - if(ethnicity == RA_HUMAN) { - if(chance < 80) race = I_BARBARIAN; - else race = I_VIKING; - if(IsCoastal() && !getrandom(10)) race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - if(chance < 85) race = I_HILLDWARF; - else race = I_UNDERDWARF; - if(IsCoastal() && !getrandom(10)) race = I_ICEDWARF; - - } else if(ethnicity == RA_ELF) { - if(chance < 70) race = I_HIGHELF; - else if(chance < 90) race = I_DARKMAN; - else race = I_TRIBALELF; - if(IsCoastal() && !getrandom(2)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_FOREST: - if(ethnicity == RA_HUMAN) { - if(chance < 60) race = I_TRIBESMAN; - else race = I_ESKIMO; - if(IsCoastal() && !getrandom(4)) race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - if(chance < 60) race = I_UNDERDWARF; - else if(chance < 90) race = I_ICEDWARF; - else race = I_PLAINSMAN; - - } else if(ethnicity == RA_ELF) { - if(chance < 50) race = I_WOODELF; - else if(chance < 90) race = I_DARKMAN; - else race = I_TRIBALELF; - if(IsCoastal() && !getrandom(6)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_PLAIN: - if(ethnicity == RA_HUMAN) { - if(chance < 75) race = I_NOMAD; - else race = I_VIKING; - if(IsCoastal() && !getrandom(3)) race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - if(chance < 75) race = I_PLAINSMAN; - else race = I_DESERTDWARF; - - } else if(ethnicity == RA_ELF) { - if(chance < 80) race = I_HIGHELF; - else race = I_DARKMAN; - if(IsCoastal() && !getrandom(4)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_DESERT: - if(ethnicity == RA_HUMAN) { - if(chance < 50) race = I_NOMAD; - else race = I_BARBARIAN; - if(IsCoastal() && !getrandom(6)) race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - if(chance < 80) race = I_DESERTDWARF; - else race = I_PLAINSMAN; - - } else if(ethnicity == RA_ELF) { - if(chance < 70) race = I_DARKMAN; - else if(chance < 85) race = I_TRIBALELF; - else race = I_HIGHELF; - if(IsCoastal() && !getrandom(2)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_JUNGLE: - if(ethnicity == RA_HUMAN) { - if(chance < 90) race = I_TRIBESMAN; - else race = I_NOMAD; - if(IsCoastal() && !getrandom(5)) race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - race = I_UNDERDWARF; - - } else if(ethnicity == RA_ELF) { - if(chance < 70) race = I_TRIBALELF; - else race = I_WOODELF; - if(IsCoastal() && !getrandom(10)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_SWAMP: - if(ethnicity == RA_HUMAN) { - if(chance < 50) race = I_TRIBESMAN; - else if(chance < 75) race = I_BARBARIAN; - else race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - race = I_UNDERDWARF; - - } else if(ethnicity == RA_ELF) { - if(chance < 90) race = I_TRIBALELF; - else race = I_SEAELF; - if(IsCoastal() && !getrandom(5)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_TUNDRA: - if(ethnicity == RA_HUMAN) { - if(chance < 90) race = I_ESKIMO; - else race = I_TRIBESMAN; - } else if(ethnicity == RA_DWARF) { - if(chance < 90) race = I_ICEDWARF; - else race = I_UNDERDWARF; - } else if(ethnicity == RA_ELF) { - if(chance < 60) race = I_TRIBALELF; - else if(chance < 80) race = I_HIGHELF; - else race = I_SEAELF; - if(IsCoastal() && !getrandom(2)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - case R_PARADISE: - if(ethnicity == RA_HUMAN) { - if(chance < 60) race = I_TRIBESMAN; - else race = I_ESKIMO; - if(IsCoastal() && !getrandom(4)) race = I_VIKING; - - } else if(ethnicity == RA_DWARF) { - if(chance < 60) race = I_UNDERDWARF; - else if(chance < 90) race = I_ICEDWARF; - else race = I_PLAINSMAN; - - } else if(ethnicity == RA_ELF) { - if(chance < 50) race = I_WOODELF; - else if(chance < 90) race = I_DARKMAN; - else race = I_TRIBALELF; - if(IsCoastal() && !getrandom(6)) race = I_SEAELF; - - } else { - race = I_ORC; - } - break; - default: - break; - } - - UpdateEditRegion(); -} - -void ARegion::RedoAs(int tertype, int hastown, ARegionList *pRegs) -{ -Awrite(TerrainDefs[tertype].name); - //reset terrain - int wasocean = 0; - int toocean = 0; - if(TerrainDefs[type].similar_type == R_OCEAN) wasocean = 1; - if(TerrainDefs[tertype].similar_type == R_OCEAN) toocean = 1; - - if(wasocean && !toocean) OceanToLand(); - - if(toocean && !wasocean) SinkRegion(pRegs); - else type = tertype; - - if(town) delete town; - town = NULL; - - products.DeleteAll(); - SetupProds(); - - markets.DeleteAll(); - - SetupEditRegion(); - UpdateEditRegion(); - - if(hastown < 0) return; - else if(hastown == 0 && town) { - //remove town - for some reason this code doesn't seem to be 100% working?! - delete town; - town = NULL; - markets.DeleteAll(); - UpdateEditRegion(); - } else if(hastown == 1 && !town) { - AddEditTown(); - UpdateEditRegion(); - } -} - -int Game::GetMarketTradeVariance() -{ - int sales[NITEMS]; - int buys[NITEMS]; - int numtrade = 0; - - for(int i=0; itown) continue; - forlist(&r->markets) { - Market *m = (Market *) elem; - if(!(ItemDefs[m->item].type & IT_TRADE)) continue; - if(m->type == M_SELL) sales[m->item]++; - else buys[m->item]++; - total++; - } - } - - float average = (float) total; - average /= (float) 2*numtrade; - - float variance = 0; - - for(int i=0; iobjects) { - Object *o = (Object *) elem; - buildings[o->type]++; - if(o->type == O_SHAFT) { - if(o->inner == -1) unconnectedshafts++; - } - } - } - - for(int i=0; itown) continue; - - int ethnicity = r->GetEthnicity(); - - forlist(&r->products) { - Production *p = (Production *) elem; - switch(ethnicity) { - case RA_HUMAN: - humanproducts[p->itemtype] += p->baseamount; - break; - case RA_ELF: - elfproducts[p->itemtype] += p->baseamount; - break; - case RA_DWARF: - dwarfproducts[p->itemtype] += p->baseamount; - break; - case RA_OTHER: - case RA_NA: - otherproducts[p->itemtype] += p->baseamount; - break; - default: - break; - } - } - } - - cout << " \t" << " H " << " E " << " D " << " O " << endl; - for(int i=0; itown) continue; - int ethnicity = r->GetEthnicity(); - - forlist(&r->markets) { - Market *m = (Market *) elem; - switch(ethnicity) { - case RA_HUMAN: - if(m->type == M_BUY) humanbuyers[m->item]++; - else humansellers[m->item]++; - break; - case RA_ELF: - if(m->type == M_BUY) elfbuyers[m->item]++; - else elfsellers[m->item]++; - break; - case RA_DWARF: - if(m->type == M_BUY) dwarfbuyers[m->item]++; - else dwarfsellers[m->item]++; - break; - case RA_OTHER: - case RA_NA: - if(m->type == M_BUY) otherbuyers[m->item]++; - else othersellers[m->item]++; - break; - default: - break; - } - } - } - //we have a big trade table. What to do with it? - int exit = 0; - do { - Awrite(""); - Awrite(" [trade] to display trade items."); - Awrite(" [normal] to display normal items."); - Awrite(" [men] to display men."); - Awrite(" [q] Go back one screen."); - - AString *pStr = AGetString(); - if(*pStr == "q") exit = 1; - else { - AString *pToken = 0; - - pToken = pStr->gettoken(); - if(!pToken) { - Awrite("Try again."); - break; - } - if (*pToken == "trade") { - cout << " \t" << " Suppliers \t" << " Demands" << endl; - cout << " \t" << " H " << " E " << " D " << " O" << "\t\t" << " H " << " E " << " D " << " O " << endl; - for(int i=0; itype].similar_type != TerrainDefs[type].similar_type) continue; - neighbors[j]->EditAdjustAreaName(text); - } -} diff --git a/arcadia/extra.cpp b/arcadia/extra.cpp deleted file mode 100644 index 64443d1d5..000000000 --- a/arcadia/extra.cpp +++ /dev/null @@ -1,1093 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// -// This file contains extra game-specific functions -// -#include "game.h" -#include "gamedata.h" - -int Game::SetupFaction( Faction *pFac ) -{ - pFac->unclaimed = Globals->START_MONEY + TurnNumber() * 100; - - if(pFac->noStartLeader) - return 1; - - // - // Set up first unit. - // - int race = -1; - Unit *temp2 = GetNewUnit( pFac ); - if(pFac->pStartLoc) pFac->ethnicity = pFac->pStartLoc->GetEthnicity(); - else pFac->ethnicity = getrandom(RA_OTHER); - switch(pFac->ethnicity) { - case RA_HUMAN: - race = I_BARBARIAN; - break; - case RA_ELF: - race = I_DARKMAN; - break; - default: - race = I_HILLDWARF; - break; - } - temp2->SetMen( race, 1 ); - pFac->DiscoverItem(race, 0, 1); - temp2->items.SetNum( I_STAFFOFY, 1 ); - pFac->DiscoverItem(I_STAFFOFY, 0, 1); - temp2->reveal = REVEAL_FACTION; - temp2->SetFlag(FLAG_COMMANDER,1); - temp2->type = U_MAGE; - - FindOrder *ord = new FindOrder; - ord->find = 0; - ord->quiet = 0; - temp2->findorders.Add(ord); - - //Xanaxor mod: see neighbours first turn! - if(pFac->pStartLoc) { - for(int i=0; i<6; i++) { - if(!pFac->pStartLoc->neighbors[i]) continue; - Farsight *f = new Farsight; - f->faction = pFac; - f->level = 1; - pFac->pStartLoc->neighbors[i]->farsees.Add(f); - } - } - - - ARegion *reg = NULL; - if(pFac->pStartLoc) { - reg = pFac->pStartLoc; - } else if(!Globals->MULTI_HEX_NEXUS) { - reg = (ARegion *)(regions.First()); - } else { - ARegionArray *pArr = regions.GetRegionArray(ARegionArray::LEVEL_NEXUS); - while(!reg) { - reg = pArr->GetRegion(pFac->num%4, getrandom(pArr->y)); - } - } - temp2->MoveUnit( reg->GetDummy() ); - reg->race = race; -/* - AString message = "Welcome to Xanaxor, the fourth game in the Arcadia series. This game is based on " - "Atlantis 5.0, and the source code is available from the Atlantis CVS repository " - "or by request from the GMs."; - AString message2 = "Up to 12 factions may be present in Xanaxor simultaneously. " - "4 factions will begin aligned with each of " - "three major ethnicities - dwarf, human and elf. None begin representing the " - "fourth alignment of orcs and merfolk. You may freely change your alignment " - "through the game, and may work with or against other factions regardless of their " - "alignment. However, the game will end when there are no surviving player factions aligned " - "with three of the major ethnicities (the fourth ethnicity will be declared victorious " - "across Xanaxor), or earlier by agreement of the surviving players."; - AString message3 = "Your hero has begun their reign in their home village. As a bonus to help you " - "along you have recieved details of all regions adjacent to your hero's " - "home village. This bonus will not be repeated in future turns. Good Luck!"; - - pFac->Message(""); - pFac->Message(message); - pFac->Message(""); - pFac->Message(message2); - pFac->Message(""); - pFac->Message(message3); -*/ - AString message1 = "Welcome to Xanaxor, the fourth game in the Arcadia series based on the Xanaxor code. This game is based on " - "Atlantis 5.0, and the source code is available from the Atlantis CVS repository " - "or by request from the GM. Many changes have been made both from Atlantis 5.0, and " - "Arcadia 3 (Nylandor). If you are not aware of the changes, you should read about them " - "as soon as possible."; - AString message2 = "Up to 12 player factions may be present in the world of Xanaxor, as well as " - "the seven non-player factions. " - "4 player factions begin aligned with each of the three major ethnicities across the land - " - "humans, dwarves and elves. Yet there is nothing to prevent leaders changing their allegiances " - "between these three races, or even for some to lead the outcasts of Xanaxor, the orcs and merfolk. " - "And nor is there anything preventing one race co-operating with another, if only for a short while. "; - AString message3 = "Xanaxor will end when there are no surviving player factions supporting three of the " - "four possible alignments - that is, all factions belong either to a particular alignment, or are " - "in chaos following the death of their commanding hero. Xanaxor may also finish earlier " - "by agreement of the surviving players."; - AString message4 = "Your hero has begun their reign in their home village. As a bonus to help you " - "along you have recieved details of all regions adjacent to your hero's " - "home village. This bonus will not be repeated in future turns. Good Luck!"; - - pFac->Message(""); - pFac->Message(message1); - pFac->Message(""); - pFac->Message(message2); - pFac->Message(""); - pFac->Message(message3); - pFac->Message(""); - pFac->Message(message4); - - return( 1 ); -} - -Faction *Game::CheckVictory(AString *victoryline) -{ - int faction_present[RA_NA]; - for(int i=0; iIsNPC()) continue; - if(f->ethnicity < RA_NA) faction_present[f->ethnicity]++; - } - - int race_present = -1; - for(int i=0; iIsNPC()) continue; - *victoryline += EthnicityString(f->ethnicity) + " factions have taken over Xanaxor!"; - return f; //we have one, let's return it. - } - - //huh? Oh well ... - return NULL; - - - /* - int cities = 0; - forlist(®ions) { - ARegion *r = (ARegion *)elem; - if(r->town && r->town->TownType() == TOWN_CITY) cities++; - } - numcities = cities; - cities = (cities*3+4)/5; // 3/5 of all cities, rounded up. - - Faction *winner = NULL; - CountGuardedCities(); - forlist_reuse(&factions) { - Faction *f = (Faction *) elem; - if(f->IsNPC()) continue; //don't want the Guardsmen winning on day 1. - - if(f->guardedcities.Value() >= cities) { - if(!winner) winner = f; - else if(f->guardedcities.Value() >= winner->guardedcities.Value()) winner = f; - } - } - if(winner && cities >= 1) { - *victoryline += *(winner->name) + " has won the game by guarding " + winner->guardedcities.Value() + " cities!"; - return winner; - } - //warning message when faction gets close to victory. - cities = (numcities*2+4)/5; // 2/5 of all cities, rounded up. - forlist_reuse(&factions) { - Faction *f = (Faction *) elem; - if(f->IsNPC()) continue; - if(f->guardedcities.Value() >= cities) { - AString message = AString(*f->name) + " nears victory, guarding " + f->guardedcities.Value() + " out of " + numcities + " cities."; - forlist(&factions) { - Faction *rfac = (Faction *) elem; - rfac->Message(message); - } - } - } - - return winner; - */ -} - -void Game::ModifyTablesPerRuleset(void) -{ - if(Globals->APPRENTICES_EXIST) - EnableSkill(S_MANIPULATE); - - if(!Globals->GATES_EXIST) - DisableSkill(S_GATE_LORE); - - if (Globals->FULL_TRUESEEING_BONUS) { - ModifyAttribMod("observation", 1, AttribModItem::SKILL, - "TRUE", AttribModItem::UNIT_LEVEL, 1); - } - if (Globals->IMPROVED_AMTS) { - ModifyAttribMod("observation", 2, AttribModItem::ITEM, - "AMTS", AttribModItem::CONSTANT, 3); - } - if (Globals->FULL_INVIS_ON_SELF) { - ModifyAttribMod("stealth", 4, AttribModItem::SKILL, - "INVI", AttribModItem::UNIT_LEVEL, 1); - } - - if(Globals->NEXUS_IS_CITY && Globals->TOWNS_EXIST) { - ClearTerrainRaces(R_NEXUS); - ModifyTerrainRace(R_NEXUS, 0, I_HIGHELF); - ModifyTerrainRace(R_NEXUS, 1, I_VIKING); - ModifyTerrainRace(R_NEXUS, 2, I_PLAINSMAN); - ClearTerrainItems(R_NEXUS); - ModifyTerrainItems(R_NEXUS, 0, I_IRON, 100, 10); - ModifyTerrainItems(R_NEXUS, 1, I_WOOD, 100, 10); - ModifyTerrainItems(R_NEXUS, 2, I_STONE, 100, 10); - ModifyTerrainEconomy(R_NEXUS, 1000, 15, 50, 2); - } - - if(Globals->ARCADIA_MAGIC) { - ModifyAttribMod("stealth", 5, AttribModItem::SKILL,"INVI", AttribModItem::UNIT_LEVEL_HALF, 1); //make sure 6 slots available - default version has only 5. - ModifyAttribMod("stealth", 2, AttribModItem::FLAGGED,"invis", AttribModItem::CONSTANT, 2); //2 down from 3 - ModifyAttribMod("entertainment", 0, AttribModItem::SKILL,"GLAD", AttribModItem::UNIT_LEVEL, 10); - - - //Fundamental Skills - EnableSkill(S_BASE_WINDKEY); - EnableSkill(S_BASE_SUMMONING); - EnableSkill(S_BASE_PATTERNING); - EnableSkill(S_BASE_MYSTICISM); - EnableSkill(S_BASE_BATTLETRAINING); - EnableSkill(S_BASE_CHARISMA); - EnableSkill(S_BASE_ARTIFACTLORE); - - //Other Skills - EnableSkill(S_BLIZZARD); - EnableSkill(S_FOG); - EnableSkill(S_CONCEALMENT); -// EnableSkill(S_ILLUSORY_CREATURES); -// EnableSkill(S_ILLUSORY_WOUNDS); - EnableSkill(S_INSTILL_COURAGE); - EnableSkill(S_SUMMON_MEN); - EnableSkill(S_RESURRECTION); - EnableSkill(S_SPIRIT_OF_DEAD); - EnableSkill(S_INNER_STRENGTH); - EnableSkill(S_TRANSMUTATION); -// EnableSkill(S_TRANSFIGURATION); - EnableSkill(S_MODIFICATION); -// EnableSkill(S_REJUVENATION); -// EnableSkill(S_SEAWARD); - EnableSkill(S_DIVERSION); - EnableSkill(S_GRYFFIN_LORE); - EnableSkill(S_HYPNOSIS); - EnableSkill(S_BINDING); - EnableSkill(S_CREATE_PORTAL); - EnableSkill(S_LIGHT); - EnableSkill(S_DARKNESS); - EnableSkill(S_DRAGON_TALK); - EnableSkill(S_TOUGHNESS); - EnableSkill(S_UNITY); - EnableSkill(S_FRENZY); - EnableSkill(S_SECSIGHT); - EnableSkill(S_SWIFTNESS); - EnableSkill(S_TRADING); - EnableSkill(S_MERCHANTRY); - EnableSkill(S_ARCADIA_QUARTERMASTERY); - - - DisableSkill(S_FORCE); - DisableSkill(S_PATTERN); - DisableSkill(S_SPIRIT); - DisableSkill(S_PORTAL_LORE); - DisableSkill(S_WEATHER_LORE); - DisableSkill(S_SUMMON_SKELETONS); - DisableSkill(S_DEMON_LORE); - DisableSkill(S_ILLUSION); - DisableSkill(S_CREATE_PHANTASMAL_BEASTS); - DisableSkill(S_CREATE_PHANTASMAL_UNDEAD); - DisableSkill(S_CREATE_PHANTASMAL_DEMONS); - DisableSkill(S_DISPEL_ILLUSIONS); - DisableSkill(S_CREATE_AMULET_OF_PROTECTION); - DisableSkill(S_CREATE_SHIELDSTONE); - DisableSkill(S_CONSTRUCT_PORTAL); - DisableSkill(S_DRAGON_LORE); - DisableSkill(S_ARTIFACT_LORE); - DisableSkill(S_EARTHQUAKE); - DisableSkill(S_TACTICS); - DisableSkill(S_MIND_READING); - DisableSkill(S_SUMMON_BLACK_WIND); - - - - //Skilltree stuff - ModifySkillName(S_FIRE,"fireball","FIRE"); - ModifySkillDependancy(S_FIRE, 0, "WKEY", 1); - ModifySkillDependancy(S_FORCE_SHIELD, 0, "FIRE", 4); - ModifySkillDependancy(S_FARSIGHT, 0, "WKEY", 1); - ModifySkillDependancy(S_FARSIGHT, 1, NULL, 0); - ModifySkillDependancy(S_SUMMON_WIND, 0, "WKEY", 1); - ModifySkillDependancy(S_SUMMON_STORM, 0, "SWIN", 1); - ModifySkillDependancy(S_SUMMON_TORNADO, 0, "SWIN", 4); - ModifySkillDependancy(S_CALL_LIGHTNING, 0, "SWIN", 6); - ModifySkillDependancy(S_CLEAR_SKIES, 0, "WKEY", 1); - ModifySkillRange(S_CLEAR_SKIES, "rng_linear"); -// ModifySkillDependancy(S_BLIZZARD, 0, "WKEY", 4); - ModifySkillDependancy(S_FOG, 0, "WKEY", 3); - ModifySkillDependancy(S_FOG, 1, NULL, 0); - ModifySkillFlags(S_FOG, SkillType::MAGIC | SkillType::COMBAT | SkillType::CAST | SkillType::MAGEOTHER); - ModifyBaseSkills(S_BASE_WINDKEY, S_FIRE, S_FORCE_SHIELD, S_FARSIGHT,S_BLIZZARD, S_CLEAR_SKIES); - ModifyBaseSkills(S_BASE_WINDKEY, S_SUMMON_WIND, S_SUMMON_STORM, S_SUMMON_TORNADO,S_CALL_LIGHTNING, S_FOG); - - ModifySkillDependancy(S_GATE_LORE, 0, "PTTN", 1); - ModifySkillDependancy(S_GATE_LORE, 1, NULL, 0); - ModifySkillDependancy(S_TELEPORTATION, 0, "GATE", 3); - ModifySkillDependancy(S_TELEPORTATION, 1, NULL, 0); - ModifySkillDependancy(S_CONSTRUCT_GATE, 0, "GATE", 4); - ModifySkillDependancy(S_CONSTRUCT_GATE, 1, NULL, 0); - ModifySkillDependancy(S_CREATE_PORTAL, 0, "TELE", 3); - ModifySkillDependancy(S_EARTH_LORE, 0, "PTTN", 1); - ModifySkillDependancy(S_MAGICAL_HEALING, 0, "PTTN", 1); - ModifySkillDependancy(S_RESURRECTION, 0, "NECR", 3); - ModifySkillDependancy(S_ENERGY_SHIELD, 0, "PTTN", 1); -// ModifySkillDependancy(S_RESURRECTION, 1, "MHEA", 3); -// ModifySkillDependancy(S_SPIRIT_OF_DEAD, 0, "RESU", 3); -// ModifySkillDependancy(S_MODIFICATION, 0, "EART", 4); -// ModifySkillDependancy(S_DIVERSION, 0, "EART", 4); - ModifyBaseSkills(S_BASE_PATTERNING, S_GATE_LORE, S_TELEPORTATION, S_CONSTRUCT_GATE, S_CREATE_PORTAL); - ModifyBaseSkills(S_BASE_PATTERNING, S_EARTH_LORE, S_DIVERSION, S_MODIFICATION, S_ENERGY_SHIELD); - ModifyBaseSkills(S_BASE_PATTERNING, S_MAGICAL_HEALING, S_RESURRECTION, S_SPIRIT_OF_DEAD); - - ModifySkillDependancy(S_CONCEALMENT, 0, "MYST", 2); - ModifySkillDependancy(S_INVISIBILITY, 0, "CONC", 5); - ModifySkillDependancy(S_TRUE_SEEING, 0, "CONC", 4); - ModifySkillDependancy(S_TRANSMUTATION, 0, "MYST", 1); - ModifySkillDependancy(S_ENCHANT_SWORDS, 0, "TRAM", 2); - ModifySkillDependancy(S_ENCHANT_ARMOR, 0, "TRAM", 2); - ModifySkillDependancy(S_HYPNOSIS, 0, "MYST", 1); - ModifySkillDependancy(S_BINDING, 0, "HYPN", 3); - ModifySkillDependancy(S_DRAGON_TALK, 0, "BIND", 3); - ModifyBaseSkills(S_BASE_MYSTICISM, S_CONCEALMENT, S_INVISIBILITY, S_TRUE_SEEING); - ModifyBaseSkills(S_BASE_MYSTICISM, S_TRANSMUTATION, S_ENCHANT_SWORDS, S_ENCHANT_ARMOR); - ModifyBaseSkills(S_BASE_MYSTICISM, S_HYPNOSIS, S_BINDING, S_DRAGON_TALK); - - ModifySkillDependancy(S_SPIRIT_SHIELD, 0, "SUMM", 1); - ModifySkillDependancy(S_SPIRIT_SHIELD, 1, NULL, 0); - ModifySkillDependancy(S_NECROMANCY, 0, "SUMM", 2); - ModifySkillDependancy(S_NECROMANCY, 1, NULL, 0); - ModifySkillDependancy(S_RAISE_UNDEAD, 0, "NECR", 3); - ModifySkillDependancy(S_SUMMON_LICH, 0, "RAIS", 4); - ModifySkillDependancy(S_BANISH_UNDEAD, 0, "NECR", 1); - ModifySkillDependancy(S_LIGHT, 0, "SUMM", 1); - ModifySkillDependancy(S_DARKNESS, 0, "LIGT", 4); - ModifySkillDependancy(S_SUMMON_MEN, 0, "SUMM", 1); - ModifySkillName(S_DEMON_LORE,"blankb","ZZZB"); - ModifySkillName(S_SUMMON_IMPS,"demon lore","DEMO"); - ModifyItemMagicSkill(I_IMP, "DEMO", 1); - ModifyItemEscapeSkill(I_IMP, "DEMO", 320); - ModifySkillDependancy(S_SUMMON_IMPS, 0, "SUMM", 1); - ModifySkillFlags(S_SUMMON_IMPS, SkillType::MAGIC | SkillType::NOTIFY | SkillType::CAST | SkillType::COSTVARIES); - ModifySkillDependancy(S_SUMMON_DEMON, 0, "DEMO", 3); - ModifySkillDependancy(S_SUMMON_BALROG, 0, "SUDE", 4); - ModifySkillDependancy(S_BANISH_DEMONS, 0, "DEMO", 1); - ModifyBaseSkills(S_BASE_SUMMONING, S_SPIRIT_SHIELD, S_LIGHT, S_DARKNESS, S_SUMMON_MEN); - ModifyBaseSkills(S_BASE_SUMMONING, S_NECROMANCY, S_RAISE_UNDEAD, S_SUMMON_LICH, S_BANISH_UNDEAD); - ModifyBaseSkills(S_BASE_SUMMONING, S_SUMMON_IMPS, S_SUMMON_DEMON, S_SUMMON_BALROG, S_BANISH_DEMONS); - - ModifySkillFlags(S_BASE_ARTIFACTLORE, SkillType::MAGIC | SkillType::NOTIFY | SkillType::CAST | SkillType::FOUNDATION); - ModifyItemMagicSkill(I_SHIELDSTONE, "ARTL", 3); - ModifyItemMagicSkill(I_AMULETOFP, "ARTL", 1); - ModifySkillName(S_ARTIFACT_LORE,"blankc","ZZZC"); - ModifySkillDependancy(S_CREATE_RING_OF_INVISIBILITY, 0, "INVI", 4); - ModifySkillDependancy(S_CREATE_RING_OF_INVISIBILITY, 1, "ARTL", 4); - ModifySkillDependancy(S_CREATE_AMULET_OF_TRUE_SEEING, 0, "TRUE", 4); - ModifySkillDependancy(S_CREATE_AMULET_OF_TRUE_SEEING, 1, "ARTL", 4); - ModifySkillDependancy(S_CREATE_CLOAK_OF_INVULNERABILITY, 0, "FSHI", 4); - ModifySkillDependancy(S_CREATE_CLOAK_OF_INVULNERABILITY, 1, "ARTL", 4); - ModifySkillDependancy(S_CREATE_CLOAK_OF_INVULNERABILITY, 2, NULL, 0); - ModifySkillDependancy(S_CREATE_STAFF_OF_FIRE, 0, "FIRE", 3); - ModifySkillDependancy(S_CREATE_STAFF_OF_FIRE, 1, "ARTL", 1); - ModifySkillDependancy(S_CREATE_STAFF_OF_LIGHTNING, 0, "CALL", 3); - ModifySkillDependancy(S_CREATE_STAFF_OF_LIGHTNING, 1, "ARTL", 5); - ModifySkillDependancy(S_CREATE_RUNESWORD, 0, "FEAR", 2); - ModifySkillDependancy(S_CREATE_RUNESWORD, 1, "ARTL", 4); - ModifySkillDependancy(S_CREATE_MAGIC_CARPET, 0, "ARTL", 1); - ModifySkillDependancy(S_CREATE_MAGIC_CARPET, 1, "SWIN", 3); - ModifySkillDependancy(S_ENGRAVE_RUNES_OF_WARDING, 0, "ARTL", 1); - ModifySkillDependancy(S_ENGRAVE_RUNES_OF_WARDING, 1, "ESHI", 1); - ModifySkillDependancy(S_ENGRAVE_RUNES_OF_WARDING, 2, NULL, 0); - ModifyBaseSkills(S_BASE_ARTIFACTLORE, S_CREATE_RING_OF_INVISIBILITY, S_CREATE_AMULET_OF_TRUE_SEEING, S_CREATE_CLOAK_OF_INVULNERABILITY); - ModifyBaseSkills(S_BASE_ARTIFACTLORE, S_CREATE_STAFF_OF_FIRE, S_CREATE_STAFF_OF_LIGHTNING, S_CREATE_RUNESWORD); - ModifyBaseSkills(S_BASE_ARTIFACTLORE, S_CREATE_MAGIC_CARPET, S_ENGRAVE_RUNES_OF_WARDING); - - ModifySkillDependancy(S_INNER_STRENGTH, 0, "BATT", 3); - ModifySkillDependancy(S_PHANTASMAL_ENTERTAINMENT, 0, "BATT", 1); - ModifySkillName(S_PHANTASMAL_ENTERTAINMENT,"gladiator","GLAD"); - ModifySkillDependancy(S_CREATE_AURA_OF_FEAR, 0, "FREN", 1); - ModifySkillDependancy(S_INSTILL_COURAGE, 0, "FREN", 5); - //swiftness (2) - //toughness (3) - //unity (2,1) - //frenzy (1) - ModifyBaseSkills(S_BASE_BATTLETRAINING, S_INNER_STRENGTH, S_PHANTASMAL_ENTERTAINMENT, S_CREATE_AURA_OF_FEAR, S_INSTILL_COURAGE); - ModifyBaseSkills(S_BASE_BATTLETRAINING, S_SWIFTNESS, S_TOUGHNESS, S_UNITY, S_FRENZY); - - ModifySkillDependancy(S_SECSIGHT, 0, "BATT", 1); - - - ModifySkillDependancy(S_WOLF_LORE, 0, "CHAR", 1); - ModifySkillDependancy(S_BIRD_LORE, 0, "CHAR", 1); - //gryffin lore (4,4) - //unity (1,2) - //trading (1) - //merchantry (3) - //quartermastery (4) - ModifyBaseSkills(S_BASE_CHARISMA, S_WOLF_LORE, S_BIRD_LORE, S_GRYFFIN_LORE, S_UNITY); - ModifyBaseSkills(S_BASE_CHARISMA, S_TRADING, S_MERCHANTRY, S_ARCADIA_QUARTERMASTERY); - - - ModifyItemMagicInput(I_AMULETOFTS, 0, I_IRON, 8); - ModifyItemMagicInput(I_RINGOFI, 0, I_MITHRIL, 4); - ModifyItemMagicInput(I_CLOAKOFI, 0, I_FUR, 8); - ModifyItemMagicInput(I_CLOAKOFI, 1, I_PEARL, 4); - ModifyItemMagicInput(I_STAFFOFF, 0, I_WOOD, 8); - ModifyItemMagicInput(I_STAFFOFL, 0, I_WOOD, 8); - ModifyItemMagicInput(I_STAFFOFL, 0, I_GEMS, 8); - ModifyItemMagicInput(I_AMULETOFP, 0, I_IRON, 1); - ModifyItemMagicInput(I_SHIELDSTONE, 0, I_IRON, 1); - ModifyItemMagicInput(I_RUNESWORD, 0, I_MSWORD, 1); - ModifyItemMagicInput(I_MCARPET, 0, I_HERBS, 1); - - EnableItem(I_STAFFOFY); - - //Illusory Creatures Stuff - EnableItem(I_IGRYFFIN); - DisableItem(I_IWOLF); - DisableItem(I_IIMP); - DisableItem(I_ISKELETON); - DisableItem(I_IEAGLE); - DisableItem(I_IDEMON); - DisableItem(I_IUNDEAD); - DisableItem(I_ILICH); - DisableItem(I_IBALROG); - DisableItem(I_IDRAGON); -/* ModifyItemMagicSkill(I_IWOLF, "ILCR", 1); - ModifyItemMagicSkill(I_IIMP, "ILCR", 1); - ModifyItemMagicSkill(I_ISKELETON, "ILCR", 1); - ModifyItemMagicSkill(I_IEAGLE, "ILCR", 2); - ModifyItemMagicSkill(I_IDEMON, "ILCR", 2); - ModifyItemMagicSkill(I_IUNDEAD, "ILCR", 2); - ModifyItemMagicSkill(I_ILICH, "ILCR", 3); - ModifyItemMagicSkill(I_IBALROG, "ILCR", 3); - ModifyItemMagicSkill(I_IDRAGON, "ILCR", 4);*/ - - //new Create Portal stuff - ModifyRangeClass("rng_teleport", RangeType::RNG_LEVEL); - ModifyRangeFlags("rng_teleport", RangeType::RNG_SURFACE_ONLY); //to prevent teleportation in the labryinth - ModifyRangeMultiplier("rng_teleport", 4); - EnableObject(O_ESEAPORTAL); - - //Monster stuff - //dragon cannot be summoned, only captured - ModifyMonsterAttacksAndHits("DRAG", 150, 150, 0); - ModifySpecialDamage("firebreath", 0, ATTACK_ENERGY,2,40, WeaponType::RANGED,MAGIC_ENERGY,0); - ModifyItemCapacities(I_DRAGON, 900, 900, 900, 900); - ModifyItemWeight(I_DRAGON, 800); - ModifyMonsterSkills("DRAG", 6, 0, 6); //tact, stea, obse - ModifyMonsterAttackLevel("DRAG", 7); - ModifyMonsterDefense("DRAG", ATTACK_COMBAT, 7); - ModifyMonsterDefense("DRAG", ATTACK_ENERGY, 5); - ModifyMonsterDefense("DRAG", ATTACK_SPIRIT, 5); - ModifyMonsterDefense("DRAG", ATTACK_WEATHER, 5); - ModifyMonsterDefense("DRAG", ATTACK_RIDING, 6); - ModifyMonsterDefense("DRAG", ATTACK_RANGED, 1); - - EnableItem(I_BABYDRAGON); - - //balrog 40 energy to summon, 4 to maintain, ~2.5% escape chance (average 5 to maintain). - ModifyMonsterAttacksAndHits("BALR", 50, 50, 0); - ModifySpecialDamage("hellfire", 0, ATTACK_ENERGY,2,20, WeaponType::RANGED,MAGIC_ENERGY,0); - ModifyMonsterSpecial("BALR", "hellfire", 3); - ModifyItemCapacities(I_BALROG, 300, 300, 0, 0); - ModifyItemWeight(I_BALROG, 250); - ModifyItemFlags(I_BALROG, ItemType::CANTGIVE | ItemType::NOTRANSPORT); - ModifyMonsterSkills("BALR", 4, 4, 5); - ModifyMonsterDefense("BALR", ATTACK_ENERGY, 3); - ModifyMonsterDefense("BALR", ATTACK_SPIRIT, 3); - ModifyMonsterDefense("BALR", ATTACK_WEATHER, 3); - ModifyMonsterThreat("BALR", 2, 75); - //escape changed in gamedata to: escape_lev_square, suba, 10, ((n^2 / 10s^2) chance of escape, ie 1 in 40 turns typical). - //max_inventory changed in gamedata to 0. - - ModifyItemFlags(I_DEMON, ItemType::CANTGIVE | ItemType::NOTRANSPORT); - ModifyMonsterDefense("DEMO", ATTACK_ENERGY, 2); - ModifyMonsterDefense("DEMO", ATTACK_SPIRIT, 3); - ModifyMonsterDefense("DEMO", ATTACK_WEATHER, 2); - //escape changed in gamedata to: escape_lev_quad, sude, 20, (n^2 / 20s^4) chance, ie 1 in 20 typical if n=s^2. - - ModifyItemFlags(I_IMP, ItemType::CANTGIVE | ItemType::NOTRANSPORT); - ModifyMonsterDefense("IMP", ATTACK_ENERGY, 2); - ModifyMonsterDefense("IMP", ATTACK_SPIRIT, 2); - ModifyMonsterDefense("IMP", ATTACK_WEATHER, 1); - //escape changed in gamedata to: escape_lev_quad, suim, 320, (n^2 / 320s^4) chance, ie 1 in 20 typical if n=4s^2. - - //lich 30 energy to summon, 0 to maintain, 10% decay chance (average 3 to maintain if count recast cost). - ModifyMonsterAttacksAndHits("LICH", 40, 40, 0); - ModifySpecialDamage("fear", 0, ATTACK_SPIRIT,2,60, WeaponType::RANGED,MAGIC_SPIRIT, "fear"); - ModifyMonsterSpecial("LICH", "fear", 4); - ModifyItemCapacities(I_LICH, 150, 0, 0, 0); - ModifyItemWeight(I_LICH, 100); - ModifyMonsterSkills("LICH", 4, 4, 5); - ModifyMonsterAttackLevel("LICH", 5); - ModifyMonsterDefense("LICH", ATTACK_COMBAT, 5); - ModifyMonsterDefense("LICH", ATTACK_ENERGY, 4); - ModifyMonsterDefense("LICH", ATTACK_SPIRIT, 5); - ModifyMonsterDefense("LICH", ATTACK_WEATHER, 3); - ModifyMonsterDefense("LICH", ATTACK_RIDING, 5); - ModifyMonsterThreat("LICH", 3, 50); - - //gryffin free to summon, free to maintain - EnableItem(I_GRYFFIN); - ModifyMonsterAttacksAndHits("GRYF", 33, 33, 0); - ModifyMonsterSkills("GRYF", 4, 2, 5); - ModifyMonsterAttackLevel("GRYF", 7); - ModifyMonsterDefense("GRYF", ATTACK_COMBAT, 7); - ModifyMonsterDefense("GRYF", ATTACK_ENERGY, 5); - ModifyMonsterDefense("GRYF", ATTACK_SPIRIT, 5); - ModifyMonsterDefense("GRYF", ATTACK_WEATHER, 7); - ModifyMonsterDefense("GRYF", ATTACK_RIDING, 6); - ModifyMonsterThreat("GRYF", 2, 25); - - ModifyItemCapacities(I_EAGLE, 30, 30, 30, 0); - ModifyItemWeight(I_EAGLE, 20); - ModifyMonsterAttacksAndHits("EAGL", 3, 3, 0); - ModifyMonsterSkills("EAGL", 2, 3, 4); - ModifyMonsterAttackLevel("EAGL", 3); - ModifyMonsterDefense("EAGL", ATTACK_COMBAT, 3); - ModifyMonsterThreat("EAGL", 12, 10); - - ModifyMonsterDefense("WOLF", ATTACK_WEATHER, 2); - - //kraken slightly less scary - EnableItem(I_KRAKEN); - ModifyMonsterAttacksAndHits("KRAK", 40, 40, 0); - ModifyMonsterSpecial("KRAK", "fear", 3); - ModifyMonsterDefense("KRAK", ATTACK_ENERGY, 3); - ModifyMonsterDefense("KRAK", ATTACK_SPIRIT, 4); - ModifyMonsterDefense("KRAK", ATTACK_WEATHER, 4); - ModifyItemCapacities(I_KRAKEN, 0, 0, 0, 250); - ModifyItemWeight(I_KRAKEN, 200); - - //multi-headed hydra - EnableItem(I_HYDRA); - ModifyMonsterAttacksAndHits("HYDR", 60, 30, 5); - ModifyMonsterDefense("HYDR", ATTACK_SPIRIT, 1); - ModifyMonsterDefense("HYDR", ATTACK_WEATHER, 2); - ModifyMonsterSpecial("HYDR", "firebreath", 1); - ModifyMonsterThreat("HYDR", 2, 50); - - ModifySpecialDamage("fireball", 0, ATTACK_ENERGY,2,10, WeaponType::RANGED,MAGIC_ENERGY,0); - ModifySpecialDamage("lightning", 0, ATTACK_WEATHER,2,50, WeaponType::RANGED,MAGIC_WEATHER,0); - ModifySpecialDamage("lightning", 1, ATTACK_ENERGY,2,50, WeaponType::RANGED,MAGIC_ENERGY,0); - ModifySpecialDamage("mindblast", 0, ATTACK_SPIRIT,2,125, WeaponType::RANGED,MAGIC_SPIRIT,0); - ModifySpecialDamage("earthquake", 0, ATTACK_COMBAT,2,50, WeaponType::RANGED,ARMORPIERCING,0); // should this be num_attack_types? - ModifySpecialDamage("dispel_illusion", 0, NUM_ATTACK_TYPES,2,50, WeaponType::RANGED,MAGIC_ENERGY,0); - ModifySpecialDamage("storm", 0, ATTACK_WEATHER,2,300, WeaponType::RANGED,MAGIC_WEATHER,"storm"); - ModifyEffectFlags("storm", EffectType::EFF_ONESHOT); - ModifySpecialDamage("tornado", 0, ATTACK_WEATHER,2,50, WeaponType::RANGED,MAGIC_WEATHER, 0); - ModifySpecialDamage("black_wind", 0, ATTACK_SPIRIT,2,150, WeaponType::RANGED,MAGIC_SPIRIT,0); - ModifySpecialDamage("banish_undead", 0, NUM_ATTACK_TYPES,2,60, WeaponType::RANGED|WeaponType::RESTINPEACE,MAGIC_ENERGY,0); - ModifySpecialDamage("banish_demon", 0, NUM_ATTACK_TYPES,2,60, WeaponType::RANGED,MAGIC_SPIRIT,0); - ModifySpecialDamage("icebreath", 0, ATTACK_WEATHER,2,5, WeaponType::RANGED,MAGIC_WEATHER,0); - ModifySpecialDamage("light", 0, ATTACK_ENERGY,2,10, WeaponType::RANGED,MAGIC_ENERGY,0); - ModifySpecialDamage("wounds", 0, ATTACK_SPIRIT,2,40, WeaponType::RANGED,MAGIC_SPIRIT, "wounds"); - ModifySpecialDamage("courage", 0, NUM_ATTACK_TYPES,2,100, WeaponType::RANGED,NUM_WEAPON_CLASSES, "courage"); - - //Get rid of dragons from the terrain table. Also, level 3 is Arcadia specific. - ModifyTerrainWMons(R_CAVERN, 4, I_RAT, I_HYDRA, I_GOBLIN); - ModifyTerrainWMons(R_UFOREST, 3, I_SPIDER, I_GRYFFIN, I_TROLL); - ModifyTerrainWMons(R_TUNNELS, 4, I_LIZARD, I_HYDRA, I_ETTIN); - ModifyTerrainWMons(R_GROTTO, 1, I_RAT, I_IWURM, I_GOBLIN); - ModifyTerrainWMons(R_DFOREST, 1, I_DEMON, I_GRYFFIN, I_TROLL); - ModifyTerrainWMons(R_CHASM, 2, I_RAT, I_BALROG, I_ETTIN); - - - //Races for new advancement style - DisableItem(I_LEADERS); - ModifyItemName(I_VIKING,"raider","raiders","RAID"); - ModifyItemName(I_PLAINSMAN,"plains dwarf","plains dwarves","PDWA"); - ModifyItemName(I_DARKMAN,"ancient elf","ancient elves","AELF"); - EnableItem(I_MERMEN); - - ModifyRaceSkills("BARB", "COMB","MINI","WEAP","OBSE"); - ModifyRaceSkills("ESKI", "HEAL","BUIL","FISH","HERB"); - ModifyRaceSkills("NOMA", "RIDI","RANC","HORS","BUIL"); - ModifyRaceSkills("TMAN", "LUMB","CONS","FARM","OBSE"); - - ModifyRaceSkills("WELF", "LUMB","LBOW","FARM","ENTE","BUIL"); - ModifyRaceSkills("SELF", "FISH","SAIL","CONS","RANC"); - ModifyRaceSkills("HELF", "HORS","ENTE","RIDI","HEAL"); - ModifyRaceSkills("TELF", "HERB","HEAL","STEA","LBOW","HUNT"); - - ModifyRaceSkills("IDWA", "COMB","BUIL","HERB","FISH"); - ModifyRaceSkills("HDWA", "COMB","MINI","WEAP","ARMO"); - ModifyRaceSkills("UDWA", "XBOW","MINI","QUAR","STEA"); - ModifyRaceSkills("DDWA", "XBOW","QUAR","ARMO","RANC"); - - ModifyRaceSkills("MERM", "STEA","FISH","ARMO","DOLP"); - ModifyRaceSkills("ORC", "COMB"); - } - - if(Globals->REAL_EXPERIENCE) { -// ModifyRaceSkillLevels("LEAD",3,3); - ModifyRaceSkillLevels("RAID",2,1); - ModifyRaceSkillLevels("BARB",2,1); - ModifyRaceSkillLevels("ESKI",2,1); - ModifyRaceSkillLevels("NOMA",2,1); - ModifyRaceSkillLevels("TMAN",2,1); - ModifyRaceSkillLevels("AELF",2,1); - ModifyRaceSkillLevels("WELF",2,1); - ModifyRaceSkillLevels("SELF",2,1); - ModifyRaceSkillLevels("HELF",2,1); - ModifyRaceSkillLevels("TELF",2,1); - ModifyRaceSkillLevels("PDWA",2,1); - ModifyRaceSkillLevels("IDWA",2,1); - ModifyRaceSkillLevels("HDWA",2,1); - ModifyRaceSkillLevels("UDWA",2,1); - ModifyRaceSkillLevels("DDWA",2,1); - ModifyRaceSkillLevels("ORC",3,0); - ModifyRaceSkillLevels("MERM",2,1); -/* ModifyRaceSkillLevels("MAN",3,3); - ModifyRaceSkillLevels("FAIR",3,1); - ModifyRaceSkillLevels("LIZA",2,1); - ModifyRaceSkillLevels("URUK",3,1); - ModifyRaceSkillLevels("GBLN",2,1); - ModifyRaceSkillLevels("HOBB",2,1); - ModifyRaceSkillLevels("GNOL",2,1); - ModifyRaceSkillLevels("DRLF",2,1); - ModifyRaceSkillLevels("MERC",1,1); - ModifyRaceSkillLevels("TITA",2,1); - ModifyRaceSkillLevels("AMAZ",2,1); - ModifyRaceSkillLevels("AMAZ",2,1); - ModifyRaceSkillLevels("OGER",3,1); - ModifyRaceSkillLevels("GNOM",2,1); - ModifyRaceSkillLevels("HILA",2,1); - ModifyRaceSkillLevels("MINO",3,1); - ModifyRaceSkillLevels("GELF",2,1); -*/ - - ModifyItemProductionSkill(I_YEW, "LUMB", 6); - ModifyItemProductionSkill(I_IRONWOOD, "LUMB", 4); - ModifyItemProductionSkill(I_DOUBLEBOW, "WEAP", 6); - ModifyItemProductionSkill(I_MITHRIL, "MINI", 4); - ModifyItemProductionSkill(I_MSWORD, "WEAP", 4); - ModifyItemProductionSkill(I_MPLATE, "ARMO", 6); - - ModifyItemProductionSkill(I_FLOATER, "FLOA", 4); - ModifyItemProductionSkill(I_ROOTSTONE, "QUAR", 3); - ModifyItemProductionSkill(I_PPLATE, "ARMO", 4); - ModifyItemProductionSkill(I_WHORSE, "HORS", 6); - ModifyItemProductionSkill(I_MUSHROOM, "HERB", 4); - ModifyItemProductionSkill(I_HEALPOTION, "HEAL", 4); - ModifyMountBonuses("WING", 4, 8, 3); - ModifyItemType(I_MCARPET, IT_MAGIC|IT_MOUNT); - - // Leave temples, stables, road etc. as they are. - } - - - -/* Standard Arcadia Changes. */ -/* All primary items $30, all secondary items $60 - Introduction of pearls & PPAR - Armour table changes - */ -/* - ModifyMonsterAttackLevel("iWOLF", -10); - ModifyMonsterDefense("iWOLF", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iWOLF", ATTACK_RIDING, -10); - ModifyMonsterDefense("iWOLF", ATTACK_RANGED, -10); - ModifyMonsterSkills("iWOLF", 0, 10, 0); - ModifyMonsterAttackLevel("iIMP", -10); - ModifyMonsterDefense("iIMP", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iIMP", ATTACK_RIDING, -10); - ModifyMonsterDefense("iIMP", ATTACK_RANGED, -10); - ModifyMonsterSkills("iIMP", 0, 10, 0); - ModifyMonsterAttackLevel("iSKEL", -10); - ModifyMonsterDefense("iSKEL", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iSKEL", ATTACK_RIDING, -10); - ModifyMonsterDefense("iSKEL", ATTACK_RANGED, -10); - ModifyMonsterSkills("iSKEL", 0, 10, 0); - ModifyMonsterAttackLevel("iEAGL", -10); - ModifyMonsterDefense("iEAGL", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iEAGL", ATTACK_RIDING, -10); - ModifyMonsterDefense("iEAGL", ATTACK_RANGED, -10); - ModifyMonsterSkills("iEAGL", 0, 10, 0); - ModifyMonsterAttackLevel("iDEMO", -10); - ModifyMonsterDefense("iDEMO", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iDEMO", ATTACK_RIDING, -10); - ModifyMonsterDefense("iDEMO", ATTACK_RANGED, -10); - ModifyMonsterSkills("iDEMO", 0, 10, 0); - ModifyMonsterAttackLevel("iUNDE", -10); - ModifyMonsterDefense("iUNDE", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iUNDE", ATTACK_RIDING, -10); - ModifyMonsterDefense("iUNDE", ATTACK_RANGED, -10); - ModifyMonsterSkills("iUNDE", 0, 10, 0); - ModifyMonsterAttackLevel("iGRYF", -10); - ModifyMonsterDefense("iGRYF", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iGRYF", ATTACK_RIDING, -10); - ModifyMonsterDefense("iGRYF", ATTACK_RANGED, -10); - ModifyMonsterSkills("iGRYF", 0, 10, 0); - ModifyMonsterAttackLevel("iDRAG", -10); - ModifyMonsterDefense("iDRAG", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iDRAG", ATTACK_RIDING, -10); - ModifyMonsterDefense("iDRAG", ATTACK_RANGED, -10); - ModifyMonsterSkills("iDRAG", 0, 10, 0); - ModifyMonsterAttackLevel("iBALR", -10); - ModifyMonsterDefense("iBALR", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iBALR", ATTACK_RIDING, -10); - ModifyMonsterDefense("iBALR", ATTACK_RANGED, -10); - ModifyMonsterSkills("iBALR", 0, 10, 0); - ModifyMonsterAttackLevel("iLICH", -10); - ModifyMonsterDefense("iLICH", ATTACK_COMBAT, -10); - ModifyMonsterDefense("iLICH", ATTACK_RIDING, -10); - ModifyMonsterDefense("iLICH", ATTACK_RANGED, -10); - ModifyMonsterSkills("iLICH", 0, 10, 0); - */ - - - ModifyMonsterAttacksAndHits("TROL", 4, 4, 2); - - ModifyMonsterThreat("ANAC", 8, 10); - ModifyMonsterThreat("SCOR", 6, 10); - ModifyMonsterThreat("POLA", 2, 10); - ModifyMonsterThreat("GRAT", 60, 10); - ModifyMonsterThreat("ROC", 3, 25); - ModifyMonsterThreat("ICEW", 12, 25); - ModifyMonsterSpecial("ICEW", "icebreath", 2); - ModifyMonsterThreat("LMAN", 16, 10); - ModifyMonsterThreat("WMAN", 20, 10); - ModifyMonsterThreat("SAND", 16, 10); - ModifyMonsterThreat("PIRA", 30, 70); - ModifyMonsterThreat("MERF", 80, 10); - ModifyMonsterThreat("UNDE", 16, 25); - ModifyMonsterThreat("iWOLF", 2000, 10); - ModifyMonsterThreat("iEAGL", 400, 10); - ModifyMonsterThreat("iGRYF", 100, 10); - ModifyMonsterSpoils("LION", 250, -1); - ModifyMonsterSpoils("WOLF", 150, -1); - ModifyMonsterSpoils("GRIZ", 500, -1); - ModifyMonsterSpoils("CROC", 180, -1); - ModifyMonsterSpoils("ANAC", 180, -1); - ModifyMonsterSpoils("SCOR", 250, -1); - ModifyMonsterSpoils("POLA", 600, -1); - ModifyMonsterSpoils("GRAT", 29, IT_NORMAL); - ModifyMonsterSpoils("GSPI", 350, -1); - ModifyMonsterSpoils("GLIZ", 700, -1); - ModifyMonsterSpoils("TREN", 400, IT_ADVANCED); - ModifyMonsterSpoils("ROC", 1100, IT_ADVANCED); - ModifyMonsterSpoils("BOGT", 1000, IT_ADVANCED); - ModifyMonsterSpoils("KONG", 1200, IT_ADVANCED); - ModifyMonsterSpoils("SPHI", 3000, IT_ADVANCED); - ModifyMonsterSpoils("ICEW", 600, IT_ADVANCED); - ModifyMonsterSpoils("BDRG", 2000, IT_MAGIC); - ModifyMonsterSpoils("DRAG", 15000, IT_MAGIC); - ModifyMonsterSpoils("GRYF", 4000, IT_ADVANCED); - ModifyMonsterSpoils("OGRE", 400, IT_NORMAL); - ModifyMonsterSpoils("ETTI", 1000, IT_NORMAL); - ModifyMonsterSpoils("UNDE", 300, IT_ADVANCED); - ModifyMonsterSpoils("LICH", 3300, IT_ADVANCED); - ModifyMonsterSpoils("DEMO", 700, IT_ADVANCED); - ModifyMonsterSpoils("BALR", 5000, IT_ADVANCED); - ModifyMonsterSpoils("EAGL", 200, IT_ADVANCED); - ModifyMonsterSpoils("PIRA", 60, IT_NORMAL); - ModifyMonsterSpoils("KRAK", 3000, IT_ADVANCED); - ModifyMonsterSpoils("MERF", 150, -1); - ModifyMonsterSpoils("HYDR", 1600, IT_ADVANCED); - - EnableObject(O_ISLE); - EnableObject(O_DERELICT); - EnableObject(O_OCAVE); - EnableItem(I_PIRATES); - EnableItem(I_KRAKEN); - EnableItem(I_MERFOLK); - ModifyItemCapacities(I_PIRATES, 0, 0, 0, 15); - ModifyObjectMonster(O_ISLE, I_TRENT); - ModifyObjectMonster(O_OCAVE, I_CENTAUR); - ModifyObjectMonster(O_DERELICT, I_CENTAUR); - - EnableObject(O_STABLE); - EnableObject(O_FISHTRAP); - EnableObject(O_TEMPLE); - EnableItem(I_LEATHERARMOR); - DisableItem(I_WAGON); - - EnableItem(I_PPLATE); - ModifyItemType(I_PEARL, IT_ADVANCED); - ModifyItemProductionSkill(I_PEARL, "FISH", 4); - ModifyItemProductionOutput(I_PEARL, 1, 1); - - EnableItem(I_MUSHROOM); - EnableItem(I_HEALPOTION); - //no rough gems, gems, or gemcutting - - DisableItem(I_TAROTCARDS); - DisableItem(I_VELVET); - DisableItem(I_VODKA); - DisableItem(I_IVORY); - DisableItem(I_MINK); - DisableItem(I_SPICES); - DisableItem(I_COTTON); // total of 18 trade items - ModifyItemWeight(I_CASHMERE,2); - //changed roses to orchids - //changed velvet to goatcheese - //changed order of items for island placement - ModifyItemBasePrice(I_MCARPET,100); - - -// ModifyItemBasePrice(I_WAGON,60); - ModifyItemBasePrice(I_PLATEARMOR,200); - ModifyItemBasePrice(I_DOUBLEBOW,320); - ModifyItemBasePrice(I_MPLATE,320); - ModifyItemBasePrice(I_PPLATE,320); - ModifyItemBasePrice(I_MSWORD,320); - ModifyItemBasePrice(I_YEW,200); - ModifyItemBasePrice(I_MITHRIL,200); - ModifyItemBasePrice(I_PEARL, 200); - ModifyItemBasePrice(I_WHORSE,200); - ModifyItemBasePrice(I_HEALPOTION,200); -// ModifyItemBasePrice(I_ROUGHGEM,100); -// ModifyItemType(I_ROUGHGEM, IT_ADVANCED); - ModifyItemBasePrice(I_LEATHERARMOR,60); - ModifyItemBasePrice(I_LIVESTOCK,20); - ModifyItemBasePrice(I_GRAIN,20); - ModifyItemBasePrice(I_FISH,20); - - ModifyItemBasePrice(I_MCARPET,600); - ModifyItemBasePrice(I_SHIELDSTONE,1500); - ModifyItemBasePrice(I_AMULETOFTS,8000); - ModifyItemBasePrice(I_RUNESWORD,12000); - ModifyItemBasePrice(I_RINGOFI,12000); - ModifyItemBasePrice(I_CLOAKOFI,16000); - ModifyItemBasePrice(I_STAFFOFL,32000); - ModifyItemCapacities(I_MCARPET,30,30,30,0); - - EnableSkill(S_CONSTRUCTION); - DisableSkill(S_CARPENTER); - DisableSkill(S_SHIPBUILDING); - - EnableObject(O_CORACLE); - ModifyObjectManpower(O_TRIREME,0,2200,100,1); - ModifyObjectManpower(O_ATRIREME,220,2200,120,1); - ModifyObjectManpower(O_MERCHANT,0,1800,15,0); - ModifyObjectManpower(O_CORACLE,0,20,1,0); - ModifyObjectManpower(O_BARGE,0,6000,40,0); - ModifyObjectManpower(O_JUNK,0,1200,20,0); - ModifyObjectManpower(O_LONGBOAT,0,300,10,0); - ModifyObjectManpower(O_BALLOON,0,800,10,0); - ModifyObjectManpower(O_TREASUREARK,0,10000,10,0); - - ModifyObjectConstruction(O_CORACLE, I_FUR, 2, "CONS", 1); - ModifyObjectConstruction(O_LONGBOAT, I_WOOD, 20, "CONS", 1); - ModifyObjectConstruction(O_MERCHANT, I_WOOD, 100, "CONS", 4); - ModifyObjectConstruction(O_TRIREME, I_WOOD, 200, "CONS", 3); - ModifyObjectConstruction(O_ATRIREME, I_IRONWOOD, 200, "CONS", 4); - ModifyObjectConstruction(O_BARGE, I_WOOD, 100, "CONS", 2); - ModifyObjectConstruction(O_JUNK, I_WOOD, 40, "CONS", 2); - ModifyObjectConstruction(O_BALLOON, I_FLOATER, 50, "CONS", 5); - ModifyObjectConstruction(O_TREASUREARK, I_WOOD, 150, "CONS", 3); -// ModifyItemProductionSkill(I_WAGON, "CONS", 1); - - ModifyObjectDefence(O_TOWER, 2, 2, 2, 2, 2, 2); - ModifyObjectDefence(O_FORT, 2, 3, 3, 3, 2, 3); - ModifyObjectDefence(O_CASTLE, 3, 3, 3, 3, 3, 3); - ModifyObjectDefence(O_CITADEL, 3, 4, 4, 4, 3, 4); - ModifyObjectDefence(O_MFORTRESS, 4, 4, 4, 4, 3, 4); - ModifyObjectDefence(O_ATRIREME, 2, 2, 2, 2, 2, 2); - - EnableObject(O_MESSAGESTONE); - -// Weapon and Armour tables - - ModifyWeaponAttack("DBOW", PIERCING, ATTACK_RANGED, WeaponType::NUM_ATTACKS_SKILL); - ModifyWeaponAttack("MSWO", ARMORPIERCING, ATTACK_COMBAT, 1); - ModifyWeaponAttack("RUNE", ARMORPIERCING, ATTACK_COMBAT, 1); - ModifyWeaponBonuses("XBOW", 2, 0, 0); - ModifyWeaponBonuses("DBOW", 2, 0, 0); - ModifyWeaponBonuses("RUNE", 5, 5, 0); - - ModifyArmorFlags("LARM", ArmorType::DEFINASSASSINATE); - ModifyArmorSaveAll("LARM", 6, 2, 0, 3); - ModifyArmorSaveAll("CARM", 2, 1, 0, 0); - ModifyArmorSaveAll("PARM", 8, 6, 2, 2); - ModifyArmorSaveAll("PPAR", 8, 6, 2, 7); - ModifyArmorSaveAll("MARM", 8, 7, 4, 5); - ModifyArmorSaveAll("CLOA", 80, 79, 79, 79); - - - ClearTerrainItems(R_FOREST); - ModifyTerrainItems(R_FOREST, 0, I_WOOD, 100, 20); - ModifyTerrainItems(R_FOREST, 1, I_FUR, 100, 10); - ModifyTerrainItems(R_FOREST, 2, I_IRONWOOD, 25, 5); - ModifyTerrainItems(R_FOREST, 3, I_YEW, 25, 5); - ModifyTerrainEconomy(R_FOREST, 500, 13, 20, 2); - - ClearTerrainItems(R_JUNGLE); - ModifyTerrainItems(R_JUNGLE, 0, I_WOOD, 100, 20); - ModifyTerrainItems(R_JUNGLE, 1, I_HERBS, 100, 10); - ModifyTerrainItems(R_JUNGLE, 2, I_FUR, 100, 10); - ModifyTerrainItems(R_JUNGLE, 3, I_YEW, 25, 5); - ModifyTerrainItems(R_JUNGLE, 4, I_MUSHROOM, 10, 5); - ModifyTerrainEconomy(R_JUNGLE, 300, 11, 20, 2); - - ClearTerrainItems(R_SWAMP); - ModifyTerrainItems(R_SWAMP, 0, I_WOOD, 100, 10); - ModifyTerrainItems(R_SWAMP, 1, I_HERBS, 100, 10); - ModifyTerrainItems(R_SWAMP, 2, I_IRON, 100, 10); - ModifyTerrainItems(R_SWAMP, 3, I_IRONWOOD, 25, 5); - ModifyTerrainItems(R_SWAMP, 4, I_FLOATER, 33, 10); - ModifyTerrainItems(R_SWAMP, 5, I_MUSHROOM, 25, 5); - ModifyTerrainEconomy(R_SWAMP, 400, 12, 20, 2); - - ClearTerrainItems(R_DESERT); - ModifyTerrainItems(R_DESERT, 0, I_STONE, 100, 30); - ModifyTerrainItems(R_DESERT, 1, I_IRON, 100, 10); - ModifyTerrainItems(R_DESERT, 2, I_HORSE, 100, 10); - ModifyTerrainItems(R_DESERT, 3, I_ROOTSTONE, 25, 10); - ModifyTerrainItems(R_DESERT, 4, I_MITHRIL, 25, 5); - ModifyTerrainEconomy(R_DESERT, 200, 13, 10, 1); - - ClearTerrainItems(R_TUNDRA); - ModifyTerrainItems(R_TUNDRA, 0, I_HERBS, 100, 20); - ModifyTerrainItems(R_TUNDRA, 1, I_FUR, 100, 20); - ModifyTerrainItems(R_TUNDRA, 2, I_WOOD, 80, 5); - ModifyTerrainItems(R_TUNDRA, 3, I_IRON, 80, 5); - ModifyTerrainItems(R_TUNDRA, 4, I_WHORSE, 25, 5); - ModifyTerrainEconomy(R_TUNDRA, 400, 11, 10, 2); - - ClearTerrainItems(R_MOUNTAIN); - ModifyTerrainItems(R_MOUNTAIN, 0, I_IRON, 100, 20); - ModifyTerrainItems(R_MOUNTAIN, 1, I_STONE, 100, 10); - ModifyTerrainItems(R_MOUNTAIN, 2, I_MITHRIL, 25, 5); - ModifyTerrainItems(R_MOUNTAIN, 3, I_ROOTSTONE, 25, 5); - ModifyTerrainEconomy(R_MOUNTAIN, 600, 13, 10, 2); - - ClearTerrainItems(R_PLAIN); - ModifyTerrainItems(R_PLAIN, 0, I_HORSE, 100, 20); - ModifyTerrainItems(R_PLAIN, 1, I_WHORSE, 25, 5); - ModifyTerrainEconomy(R_PLAIN, 800, 14, 40, 1); - ModifyTerrainWMons(R_PLAIN, 2, I_LION, I_EAGLE, I_CENTAUR); - - ClearTerrainItems(R_PARADISE); - ModifyTerrainItems(R_PARADISE, 0, I_WOOD, 100, 20); - ModifyTerrainItems(R_PARADISE, 1, I_IRON, 100, 20); - ModifyTerrainItems(R_PARADISE, 2, I_HERBS, 100, 15); - ModifyTerrainItems(R_PARADISE, 3, I_FUR, 100, 15); - ModifyTerrainItems(R_PARADISE, 4, I_STONE, 100, 20); - ModifyTerrainItems(R_PARADISE, 5, I_IRONWOOD, 100, 10); - ModifyTerrainItems(R_PARADISE, 6, I_FLOATER, 100, 20); - ModifyTerrainEconomy(R_PARADISE, 1000, 18, 40, 1); -/* - ClearTerrainItems(R_CAVERN); - ModifyTerrainItems(R_CAVERN, 0, I_IRON, 100, 20); - ModifyTerrainItems(R_CAVERN, 1, I_STONE, 100, 20); - ModifyTerrainItems(R_CAVERN, 2, I_MITHRIL, 25, 5); - ModifyTerrainItems(R_CAVERN, 3, I_ROOTSTONE, 25, 5); - ModifyTerrainEconomy(R_CAVERN, 100, 10, 10, 1); - - ClearTerrainItems(R_TUNNELS); - ModifyTerrainItems(R_TUNNELS, 0, I_IRON, 100, 20); - ModifyTerrainItems(R_TUNNELS, 1, I_STONE, 100, 20); - ModifyTerrainItems(R_TUNNELS, 2, I_MITHRIL, 25, 5); - ModifyTerrainItems(R_TUNNELS, 3, I_ROOTSTONE, 25, 5); - ModifyTerrainItems(R_TUNNELS, 4, I_MUSHROOM, 10, 5); - ModifyTerrainEconomy(R_TUNNELS, 0, 0, 0, 1); - - ClearTerrainItems(R_UFOREST); - //map generated without mushrooms and 30% IRWD chance - ModifyTerrainItems(R_UFOREST, 0, I_WOOD, 100, 10); - ModifyTerrainItems(R_UFOREST, 1, I_STONE, 100, 20); - ModifyTerrainItems(R_UFOREST, 2, I_IRON, 100, 10); - ModifyTerrainItems(R_UFOREST, 3, I_MUSHROOM, 25, 5); - ModifyTerrainItems(R_UFOREST, 4, I_IRONWOOD, 25, 7); - ModifyTerrainItems(R_UFOREST, 5, I_YEW, 10, 5); - ModifyTerrainEconomy(R_UFOREST, 100, 10, 10, 2); - - ClearTerrainItems(R_GROTTO); - ModifyTerrainItems(R_GROTTO, 0, I_STONE, 100, 10); - ModifyTerrainItems(R_GROTTO, 1, I_ROOTSTONE, 25, 10); - ModifyTerrainItems(R_GROTTO, 2, I_MITHRIL, 30, 6); - ModifyTerrainItems(R_GROTTO, 3, I_ROUGHGEM, 35, 10); - ModifyTerrainItems(R_GROTTO, 4, I_MUSHROOM, 15, 8); - ModifyTerrainEconomy(R_GROTTO, 0, 11, 0, 1); //0 economy for Nylandor only - - ClearTerrainItems(R_CHASM); - ModifyTerrainItems(R_CHASM, 0, I_STONE, 100, 20); - ModifyTerrainItems(R_CHASM, 1, I_ROOTSTONE, 25, 5); - ModifyTerrainItems(R_CHASM, 2, I_MITHRIL, 30, 6); - ModifyTerrainItems(R_CHASM, 3, I_ROUGHGEM, 25, 10); - ModifyTerrainItems(R_CHASM, 4, I_MUSHROOM, 20, 5); - ModifyTerrainEconomy(R_CHASM, 0, 0, 0, 2); - - ClearTerrainItems(R_DFOREST); - //map generated with rough gems instead of ironwood - ModifyTerrainItems(R_DFOREST, 0, I_WOOD, 100, 10); - ModifyTerrainItems(R_DFOREST, 1, I_STONE, 100, 10); - ModifyTerrainItems(R_DFOREST, 2, I_IRON, 100, 10); - ModifyTerrainItems(R_DFOREST, 3, I_MUSHROOM, 40, 8); - ModifyTerrainItems(R_DFOREST, 4, I_IRONWOOD, 30, 7); - ModifyTerrainEconomy(R_DFOREST, 0, 11, 2, 3); //0 economy for Nylandor only - */ - ClearTerrainItems(R_OCEAN); - ModifyTerrainItems(R_OCEAN, 0, I_FISH, 100, 40); - ModifyTerrainItems(R_OCEAN, 1, I_DOLPHIN, 50, 10); - ModifyTerrainItems(R_OCEAN, 2, I_PEARL, 15, 8); - ModifyTerrainItems(R_OCEAN, 3, I_FDOLPHIN, 10, 5); - - ClearTerrainItems(R_LAKE); - ModifyTerrainItems(R_LAKE, 0, I_FISH, 100, 60); - ModifyTerrainItems(R_LAKE, 1, I_PEARL, 35, 10); - - - /* End Standard Arcadia Changes */ - - if(Globals->HEXSIDE_TERRAIN) { - EnableHexside(H_ROAD); - EnableHexside(H_BRIDGE); - EnableHexside(H_BEACH); - EnableHexside(H_HARBOUR); - EnableHexside(H_ROCKS); - EnableHexside(H_RIVER); - EnableHexside(H_RAVINE); - EnableHexside(H_CLIFF); - } - - if((Globals->UNDERDEEP_LEVELS > 0) || (Globals->UNDERWORLD_LEVELS > 1)) { - EnableItem(I_MUSHROOM); - EnableItem(I_HEALPOTION); - EnableItem(I_ROUGHGEM); - EnableItem(I_GEMS); - EnableSkill(S_GEMCUTTING); - } - - // Modify the various spells which are allowed to cross levels - if(Globals->EASIER_UNDERWORLD) { -// ModifyRangeFlags("rng_teleport", RangeType::RNG_CROSS_LEVELS); //Not for Arcadia Labryinth - ModifyRangeFlags("rng_portal", RangeType::RNG_CROSS_LEVELS); - ModifyRangeFlags("rng_farsight", RangeType::RNG_CROSS_LEVELS); - ModifyRangeFlags("rng_clearsky", RangeType::RNG_CROSS_LEVELS); - ModifyRangeFlags("rng_weather", RangeType::RNG_CROSS_LEVELS); - ModifyRangeFlags("rng_square", RangeType::RNG_CROSS_LEVELS); - } - - if (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - EnableSkill(S_QUARTERMASTER); - EnableObject(O_CARAVANSERAI); - } - - return; -} diff --git a/arcadia/faction.cpp b/arcadia/faction.cpp deleted file mode 100644 index f08a62c62..000000000 --- a/arcadia/faction.cpp +++ /dev/null @@ -1,1017 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "gamedata.h" -#include "game.h" - -char *as[] = { - "Hostile", - "Unfriendly", - "Neutral", - "Friendly", - "Ally" -}; - -char **AttitudeStrs = as; - -char *fs[] = { - "War", - "Trade", - "Heroes" -}; - -char **FactionStrs = fs; - -// LLS - fix up the template strings -char *tp[] = { - "off", - "short", - "long", - "map" -}; - -char **TemplateStrs = tp; - -int ParseTemplate(AString *token) -{ - for (int i = 0; i < NTEMPLATES; i++) - if (*token == TemplateStrs[i]) return i; - return -1; -} - -int ParseAttitude(AString *token) -{ - for (int i=0; iPutInt(factionnum); - f->PutInt(attitude); -} - -void Attitude::Readin(Ainfile *f, ATL_VER v) -{ - factionnum = f->GetInt(); - attitude = f->GetInt(); -} - -void FormTemplate::Writeout(Aoutfile *f) -{ - f->PutStr(*name); - f->PutInt(orders.Num()); - forlist(&orders) f->PutStr(*((AString *) elem)); -} - -void FormTemplate::Readin(Ainfile *f) -{ - name = f->GetStr(); - int n = f->GetInt(); - for(int i=0; iGetStr()); -} - -Statistic::Statistic() -{ - value = 0; - rank = 1; - maxvalue = 0; -} - -Statistic::~Statistic() -{ -} - - -FormTemplate::FormTemplate() -{ - name = 0; -} - -FormTemplate::~FormTemplate() -{ - if(name) delete name; -} - -AString *FormTemplate::GetLine(int linenum) -{ - if(linenum < 0 || linenum >= orders.Num()) return 0; - AString *line = (AString *) orders.First(); //return this for linenum = 0 - while(linenum--) line = (AString *) orders.Next(line); - return (new AString(*line)); -} - -Faction::Faction() -{ - exists = 1; - name = 0; - for (int i=0; iPutInt(num); - - for (int i=0; iPutInt(type[i]); - - f->PutInt(lastchange); - f->PutInt(lastorders); - f->PutInt(unclaimed); - f->PutInt(bankaccount); - f->PutStr(*name); - f->PutStr(*address); - f->PutStr(*password); - f->PutInt(times); - f->PutInt(showunitattitudes); - f->PutInt(temformat); - f->PutInt(labryinth); //Arcadia only - f->PutInt(ethnicity); - f->PutInt(start); - - skills.Writeout(f); - items.Writeout(f); - f->PutInt(defaultattitude); - f->PutInt(attitudes.Num()); - forlist((&attitudes)) ((Attitude *) elem)->Writeout(f); - f->PutInt(formtemplates.Num()); - forlist_reuse(&formtemplates) ((FormTemplate *) elem)->Writeout(f); -} - -void Faction::Readin(Ainfile *f, ATL_VER v) -{ - num = f->GetInt(); - int i; - - for (i=0; iGetInt(); - - lastchange = f->GetInt(); - lastorders = f->GetInt(); - unclaimed = f->GetInt(); - bankaccount = f->GetInt(); - - name = f->GetStr(); - address = f->GetStr(); - password = f->GetStr(); - times = f->GetInt(); - showunitattitudes = f->GetInt(); - temformat = f->GetInt(); - labryinth = f->GetInt(); - ethnicity = f->GetInt(); - start = f->GetInt(); - - skills.Readin(f); - items.Readin(f); - - defaultattitude = f->GetInt(); - int n = f->GetInt(); - for (i=0; iReadin(f, v); - if (a->factionnum == num) delete a; - else attitudes.Add(a); - } - n = f->GetInt(); - for (i=0; iReadin(f); - formtemplates.Add(ftem); - } -} - -void Faction::View() -{ - AString temp; - temp = AString("Faction ") + num + AString(" : ") + *name; - Awrite(temp); -} - -void Faction::SetName(AString* s) -{ - if (s) { - AString* newname = s->getlegal(); - delete s; - if (!newname) return; - delete name; - *newname += AString(" (") + num + ")"; - name = newname; - } -} - -void Faction::SetNameNoChange(AString *s) -{ - if(s) { - delete name; - name = new AString(*s); - } -} - -void Faction::SetAddress(AString &strNewAddress) -{ - delete address; - address = new AString(strNewAddress); -} - -AString Faction::FactionTypeStr() -{ - AString temp; - if (IsNPC()) return AString("NPC"); - - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_UNLIMITED) { - return (AString("Unlimited")); - } else if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) { - return(AString("Normal")); - } else if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - int comma = 0; - for (int i=0; iGM_REPORT || (pGame->month == 0 && pGame->year == 1)) { - f->PutStr("Atlantis Report For:"); - if((Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) || - (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_UNLIMITED)) { - f->PutStr(*name); - } else if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - f->PutStr(*name + " (" + FactionTypeStr() + ")"); - } - f->PutStr(AString(MonthNames[ pGame->month ]) + ", Year " + pGame->year); - - int i, j; - // Put all skills, items and objects in the GM report - shows.DeleteAll(); - for(i = 0; i < NSKILLS; i++) { - for(j = 1; j < 7; j++) { - shows.Add(new ShowSkill(i, j)); - } - } - if(shows.Num()) { - f->PutStr("Skill reports:"); - forlist(&shows) { - AString *string = ((ShowSkill *)elem)->Report(this); - if(string) { - f->PutStr(""); - f->PutStr(*string); - delete string; - } - } - shows.DeleteAll(); - f->EndLine(); - } - itemshows.DeleteAll(); - for(i = 0; i < NITEMS; i++) { - AString *show = ItemDescription(i, 1); - if(show) { - itemshows.Add(show); - } - } - if(itemshows.Num()) { - f->PutStr("Item reports:"); - forlist(&itemshows) { - f->PutStr(""); - f->PutStr(*((AString *)elem)); - } - itemshows.DeleteAll(); - f->EndLine(); - } - objectshows.DeleteAll(); - for(i = 1; i < NOBJECTS; i++) { - AString *show = ObjectDescription(i); - if(show) { - objectshows.Add(show); - } - } - if(objectshows.Num()) { - f->PutStr("Object reports:"); - forlist(&objectshows) { - f->PutStr(""); - f->PutStr(*((AString *)elem)); - } - objectshows.DeleteAll(); - f->EndLine(); - } - - terrainshows.DeleteAll(); - for(i = 0; i < R_NUM; i++) { - AString *show = TerrainDescription(i); - if(show) { - terrainshows.Add(show); - } - } - for(i = 1; i < NHEXSIDES; i++) { - AString *show = HexsideDescription(i); - if(show) { - terrainshows.Add(show); - } - } - if(terrainshows.Num()) { - f->PutStr("Terrain reports:"); - forlist(&terrainshows) { - f->PutStr(""); - f->PutStr(*((AString *)elem)); - } - terrainshows.DeleteAll(); - f->EndLine(); - } - - present_regions.DeleteAll(); - forlist(&(pGame->regions)) { - ARegion *reg = (ARegion *)elem; - ARegionPtr *ptr = new ARegionPtr; - ptr->ptr = reg; - present_regions.Add(ptr); - } - { - forlist(&present_regions) { - ((ARegionPtr*)elem)->ptr->WriteReport(f, this, - pGame->month, - &(pGame->regions)); - } - } - present_regions.DeleteAll(); - } - errors.DeleteAll(); - events.DeleteAll(); - battles.DeleteAll(); - return; - } - - f->PutStr("Atlantis Report For:"); - if((Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) || - (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_UNLIMITED)) { - f->PutStr(*name); - } else if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - f->PutStr(*name + " (" + FactionTypeStr() + ")"); - } - f->PutStr(AString(MonthNames[ pGame->month ]) + ", Year " + pGame->year); - f->PutStr(AString("Alignment: ") + EthnicityString(ethnicity)); - f->EndLine(); - - f->PutStr(AString("Atlantis Engine Version: ") + - ATL_VER_STRING(CURRENT_ATL_VER)); - f->PutStr(AString(Globals->RULESET_NAME) + ", Version: " + - ATL_VER_STRING(Globals->RULESET_VERSION)); - f->EndLine(); - - if (!times) { - f->PutStr("Note: The Times is not being sent to you."); - f->EndLine(); - } - - if(*password == "none") { - f->PutStr("REMINDER: You have not set a password for your faction!"); - f->EndLine(); - } - - if(Globals->MAX_INACTIVE_TURNS != -1) { - int cturn = pGame->TurnNumber() - lastorders; - if((cturn >= (Globals->MAX_INACTIVE_TURNS - 3)) && !IsNPC()) { - cturn = Globals->MAX_INACTIVE_TURNS - cturn; - f->PutStr(AString("WARNING: You have ") + cturn + - AString(" turns until your faction is automatically ")+ - AString("removed due to inactivity!")); - f->EndLine(); - } - } - - if (!exists) { - if (quit == QUIT_AND_RESTART) { - f->PutStr("You restarted your faction this turn. This faction " - "has been removed, and a new faction has been started " - "for you. (Your new faction report will come in a " - "separate message.)"); - } else if(quit == QUIT_GAME_OVER) { - f->PutStr("I'm sorry, the game has ended. Better luck in " - "the next game you play!"); - } else if(quit == QUIT_WON_GAME) { - f->PutStr("Congratulations, you have won the game!"); - } else { - f->PutStr("I'm sorry, your faction has been eliminated."); - // LLS - f->PutStr("If you wish to restart, please let the " - "Gamemaster know, and you will be restarted for " - "the next available turn."); - } - f->PutStr(""); - } - - f->PutStr("Faction Status:"); - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) { - f->PutStr(AString("Mages: ") + nummages + " (" + - pGame->AllowedMages(this) + ")"); - if(Globals->APPRENTICES_EXIST) { - f->PutStr(AString("Apprentices: ") + numapprentices + " (" + - pGame->AllowedApprentices(this)+ ")"); - } - } else if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - f->PutStr(AString("Tax Regions: ") + war_regions.Num() + " (" + - pGame->AllowedTaxes(this) + ")"); - f->PutStr(AString("Trade Regions: ") + trade_regions.Num() + " (" + - pGame->AllowedTrades(this) + ")"); - if (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - f->PutStr(AString("Quartermasters: ") + numqms + " (" + - pGame->AllowedQuarterMasters(this) + ")"); - } - if (Globals->TACTICS_NEEDS_WAR) { - f->PutStr(AString("Tacticians: ") + numtacts + " (" + - pGame->AllowedTacticians(this) + ")"); - } - f->PutStr(AString("Heros: ") + nummages + " (" + - pGame->AllowedMages(this) + ")"); - if(Globals->APPRENTICES_EXIST) { - f->PutStr(AString("Apprentices: ") + numapprentices + " (" + - pGame->AllowedApprentices(this)+ ")"); - } - } - f->PutStr(""); - f->PutStr( AString("Empire Size: ") + nummen.Value() + " men"); - if(pGame->month == 5 || pGame->month == 11) f->PutStr( AString(" Rank: ") + nummen.rank + ". Max Value: " + nummen.maxvalue + "."); - f->PutStr( AString("Empire Money: ") + totalsilver.Value() + " silver (" + ((100*totalsilver.Value()+totalnetworth.Value()/2)/totalnetworth.Value()) + "% of total)"); - if(pGame->month == 5 || pGame->month == 11) f->PutStr( AString(" Rank: ") + totalsilver.rank + ". Max Value: " + totalsilver.maxvalue + "."); - f->PutStr( AString("Item Value: ") + itemnetworth.Value() + " silver (" + ((100*itemnetworth.Value()+totalnetworth.Value()/2)/totalnetworth.Value()) + "% of total)"); - if(pGame->month == 5 || pGame->month == 11) f->PutStr( AString(" Rank: ") + itemnetworth.rank + ". Max Value: " + itemnetworth.maxvalue + "."); - f->PutStr( AString("Skill Value: ") + skillnetworth.Value() + " silver (" + ((100*skillnetworth.Value()+totalnetworth.Value()/2)/totalnetworth.Value()) + "% of total)"); - if(pGame->month == 5 || pGame->month == 11) f->PutStr( AString(" Rank: ") + skillnetworth.rank + ". Max Value: " + skillnetworth.maxvalue + "."); - f->PutStr( AString("Total Value: ") + totalnetworth.Value() + " silver"); - if(pGame->month == 5 || pGame->month == 11) f->PutStr( AString(" Rank: ") + totalnetworth.rank + ". Max Value: " + totalnetworth.maxvalue + "."); - f->PutStr( AString("Hero Score: ") + magepower.Value()); - if(pGame->month == 5 || pGame->month == 11) f->PutStr( AString(" Rank: ") + magepower.rank + ". Max Value: " + magepower.maxvalue + "."); - f->PutStr(""); - - f->PutStr(""); - - if (messages.Num()) { - f->PutStr("Important Messages:"); - forlist((&messages)) { - f->PutStr(*((AString *) elem)); - } - messages.DeleteAll(); - f->EndLine(); - } - - if (errors.Num()) { - f->PutStr("Errors during turn:"); - forlist((&errors)) { - f->PutStr(*((AString *) elem)); - } - errors.DeleteAll(); - f->EndLine(); - } - - if (battles.Num()) { - f->PutStr("Battles during turn:"); - forlist(&battles) { - ((BattlePtr *) elem)->ptr->Report(f, this); - } - battles.DeleteAll(); - } - - if (events.Num()) { - f->PutStr("Events during turn:"); - forlist((&events)) { - f->PutStr(*((AString *) elem)); - } - events.DeleteAll(); - f->EndLine(); - } - - if (shows.Num()) { - f->PutStr("Skill reports:"); - forlist(&shows) { - AString* string = ((ShowSkill *) elem)->Report(this); - if (string) { - f->PutStr(""); - f->PutStr(*string); - } - delete string; - } - shows.DeleteAll(); - f->EndLine(); - } - - if (itemshows.Num()) { - f->PutStr("Item reports:"); - forlist(&itemshows) { - f->PutStr(""); - f->PutStr(*((AString *) elem)); - } - itemshows.DeleteAll(); - f->EndLine(); - } - - if(objectshows.Num()) { - f->PutStr("Object reports:"); - forlist(&objectshows) { - f->PutStr(""); - f->PutStr(*((AString *)elem)); - } - objectshows.DeleteAll(); - f->EndLine(); - } - - /* Attitudes */ - AString temp = AString("Declared Attitudes (default ") + - AttitudeStrs[defaultattitude] + "):"; - f->PutStr(temp); - for (int i=0; iattitude == i) { - if (j) temp += ", "; - temp += *(GetFaction(&(pGame->factions), - a->factionnum)->name); - j = 1; - } - } - if (!j) temp += "none"; - temp += "."; - f->PutStr(temp); - } - f->EndLine(); - - temp = AString("Unclaimed silver: ") + unclaimed + "."; - f->PutStr(temp); - if (Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) { - temp = AString("Silver in the Bank: ") + bankaccount; - if (Globals->ALLOW_BANK & GameDefs::BANK_TRADEINTEREST) - temp += AString(" (+")+interest+AString(" interest)"); - temp += + "."; - f->PutStr(temp); - } f->PutStr(""); - - forlist(&present_regions) { - ((ARegionPtr *) elem)->ptr->WriteReport(f, this, pGame->month, &(pGame->regions)); - } - // LLS - maybe we don't want this -- I'll assume not, for now - //f->PutStr("#end"); - if(Globals->FORM_TEMPLATES) WriteFormTemplates(f); - if(!Globals->SEPERATE_TEMPLATES) WriteTemplate(f,pGame); - else f->EndLine(); - -} - -//export the unit templates -void Faction::WriteFormTemplates(Areport *f) -{ - if(!formtemplates.Num()) return; - f->PutStr("Stored Unit Types:"); - forlist(&formtemplates) { - FormTemplate *formtem = (FormTemplate *) elem; - f->PutStr(""); - f->PutStr(*formtem->name); - forlist(&formtem->orders) { - f->PutStr(*((AString *) elem)); - } - } -/* forlist_reuse(&labeltemplates) { - FormTemplate *formtem = (FormTemplate *) elem; - f->PutStr(""); - f->PutStr(*formtem->name); - forlist(&formtem->orders) { - f->PutStr(*((AString *) elem)); - } - }*/ -} - -// LLS - write order template -void Faction::WriteTemplate(Areport *f, Game *pGame) -{ - AString temp; - int tFormat = temformat; - if (!IsNPC()) { - if (tFormat == TEMPLATE_OFF) - tFormat = TEMPLATE_SHORT; - f->PutStr(""); - switch (temformat) { - case TEMPLATE_SHORT: - f->PutStr("Orders Template (Short Format):"); - break; - case TEMPLATE_LONG: - f->PutStr("Orders Template (Long Format):"); - break; - // DK - case TEMPLATE_MAP: - f->PutStr("Orders Template (Map Format):"); - break; - } - - f->PutStr(""); - temp = AString("#atlantis ") + num; - if (!(*password == "none")) { - temp += AString(" \"") + *password + "\""; - } - f->PutStr(temp); - forlist((&present_regions)) { - // DK - ((ARegionPtr *) elem)->ptr->WriteTemplate(f, this, &(pGame->regions), pGame->month); - } - - f->PutStr(""); - f->PutStr("#end"); - f->EndLine(); - } -} - -void Faction::WriteFacInfo(Aoutfile *file) -{ - file->PutStr(AString("Faction: ") + num); - file->PutStr(AString("Name: ") + *name); - file->PutStr(AString("Email: ") + *address); - file->PutStr(AString("Password: ") + *password); - file->PutStr(AString("LastOrders: ") + lastorders); - file->PutStr(AString("SendTimes: ") + times); - // LLS - write template info to players file - file->PutStr(AString("Template: ") + TemplateStrs[temformat]); - - forlist(&extraPlayers) { - AString *pStr = (AString *) elem; - file->PutStr(*pStr); - } - - extraPlayers.DeleteAll(); -} - -void Faction::CheckExist(ARegionList* regs) -{ - if (IsNPC()) return; - exists = 0; - forlist(regs) { - ARegion* reg = (ARegion *) elem; - if (reg->Present(this)) { - exists = 1; - return; - } - } -} - -void Faction::Error(const AString &s) -{ - if (IsNPC()) return; - if (errors.Num() > 1000) { - if (errors.Num() == 1001) { - errors.Add(new AString("Too many errors!")); - } - return; - } - - AString *temp = new AString(s); - errors.Add(temp); -} - -void Faction::Message(const AString &s) -{ - if (IsNPC()) return; - if (messages.Num() > 1000) { - if (messages.Num() == 1001) { - messages.Add(new AString("Too many messages!")); - } - return; - } - - AString *temp = new AString(s); - messages.Add(temp); -} - -void Faction::Event(const AString &s) -{ - if (IsNPC()) return; - AString *temp = new AString(s); - events.Add(temp); -} - -void Faction::RemoveAttitude(int f) -{ - forlist((&attitudes)) { - Attitude *a = (Attitude *) elem; - if (a->factionnum == f) { - attitudes.Remove(a); - delete a; - return; - } - } -} - -int Faction::GetAttitude(int n) -{ - if (n == num) return A_ALLY; - forlist((&attitudes)) { - Attitude *a = (Attitude *) elem; - if (a->factionnum == n) - return a->attitude; - } - return defaultattitude; -} - -void Faction::SetAttitude(int num, int att) -{ - forlist((&attitudes)) { - Attitude *a = (Attitude *) elem; - if (a->factionnum == num) { - if (att == -1) { - attitudes.Remove(a); - delete a; - return; - } else { - a->attitude = att; - return; - } - } - } - if (att != -1) { - Attitude *a = new Attitude; - a->factionnum = num; - a->attitude = att; - attitudes.Add(a); - } -} - -int Faction::CanCatch(ARegion *r, Unit *t) -{ - if(t->guard == GUARD_GUARD) return 1; //I think ... hope this doesn't give wierd behaviour. BS - - if (TerrainDefs[r->type].similar_type == R_OCEAN && ((t->object && t->object->IsBoat()) || !t->CanFly())) return CanCatchAtSea(r,t); - - int def = t->GetDefenseRiding(); - - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u == t && o->type != O_DUMMY) return 1; - if (u->faction == this && u->GetAttackRiding() >= def) return 1; - } - } - return 0; -} - -int Faction::CanCatchAtSea(ARegion *r, Unit *t) -{ -//target is either in a boat, or not flying. Go by boat speed. - - int attspeed = 0; - int defspeed = ObjectDefs[t->object->type].speed; - - forlist(&r->objects) { - Object *o = (Object *) elem; - int boatspeed = 0; - int targetpresent = 0; - int sailors = 0; - int weight = 0; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if(u == t) targetpresent = 1; - sailors += u->GetSkill(S_SAILING) * u->GetMen(); - weight += u->Weight(); - } - if(sailors >= ObjectDefs[o->type].sailors && weight <= ObjectDefs[o->type].capacity) boatspeed = ObjectDefs[o->type].speed; - else { - boatspeed = 0; - if(targetpresent) defspeed = 0; - } - forlist_reuse(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == this) { - if(u->CanSwim()) return 1; - if(boatspeed >= defspeed) return 1; - if(boatspeed > attspeed) attspeed = boatspeed; - } - } - } - //if our ship can catch his (ie if he does not have enough sailors), return 1 - if(attspeed >= defspeed) return 1; - - //otherwise, we can't catch him - return 0; -} - -int Faction::CanSee(ARegion* r, Unit* u, int practice) -{ - if(u->dead) return 0; //this is only for spirits of the dead in Arcadia. NB better hope spirits are never guard-1. - - int detfac = 0; - if (u->faction == this) return 2; - if (u->reveal == REVEAL_FACTION) return 2; - int retval = 0; - if (u->reveal == REVEAL_UNIT) retval = 1; - forlist((&r->objects)) { - Object* obj = (Object *) elem; - int dummy = 0; - if (obj->type == O_DUMMY) dummy = 1; - forlist((&obj->units)) { - Unit* temp = (Unit *) elem; - if (u == temp && dummy == 0) retval = 1; - if (temp->faction == this) { - if (temp->GetAttribute("observation") > - u->GetAttribute("stealth")) { - if (practice) { - temp->PracticeAttribute("observation"); - retval = 2; - } - else - return 2; - } else { - if (temp->GetAttribute("observation") == - u->GetAttribute("stealth")) { - if (practice) temp->PracticeAttribute("observation"); - if (retval < 1) retval = 1; - } - } - if (temp->GetSkill(S_MIND_READING) > 2 || (Globals->ARCADIA_MAGIC && temp->GetSkill(S_MIND_READING) > 1)) detfac = 1; - } - } - } - if (retval == 1 && detfac) return 2; - return retval; -} - -void Faction::DefaultOrders() -{ - war_regions.DeleteAll(); - trade_regions.DeleteAll(); - numshows = 0; -} - -void Faction::TimesReward() -{ - if (Globals->TIMES_REWARD) { - Event(AString("Times reward of ") + Globals->TIMES_REWARD + " silver."); - unclaimed += Globals->TIMES_REWARD; - } -} - -void Faction::SetNPC() -{ - for (int i=0; inum == n) - return (Faction *) elem; - return 0; -} - -Faction *GetFaction2(AList *facs, int n) -{ - forlist(facs) - if (((FactionPtr *) elem)->ptr->num == n) - return ((FactionPtr *) elem)->ptr; - return 0; -} - -void Faction::DiscoverItem(int item, int force, int full) -{ - int seen = items.GetNum(item); - if(!seen) { - if(full) { - items.SetNum(item, 2); - } else { - items.SetNum(item, 1); - } - force = 1; - } else { - if(seen == 1) { - if(full) { - items.SetNum(item, 2); - } - force = 1; - } else { - full = 1; - } - } - if(force) { - itemshows.Add(ItemDescription(item, full)); - } -} diff --git a/arcadia/faction.h b/arcadia/faction.h deleted file mode 100644 index ff25ac16c..000000000 --- a/arcadia/faction.h +++ /dev/null @@ -1,265 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2000/MAR/14 Davis Kulis Added a new reporting Template. -// 2001/Feb/18 Joseph Traub Added Apprentices from Lacandon Conquest -#ifndef FACTION_CLASS -#define FACTION_CLASS - -class Faction; -class Game; - -#include "gameio.h" -#include "aregion.h" -#include "fileio.h" -#include "unit.h" -#include "battle1.h" -#include "skills.h" -#include "items.h" -#include "alist.h" -#include "astring.h" - -enum { - A_HOSTILE, - A_UNFRIENDLY, - A_NEUTRAL, - A_FRIENDLY, - A_ALLY, - NATTITUDES -}; - -enum { - F_WAR, - F_TRADE, - F_MAGIC, - NFACTYPES -}; - -// DK -// LLS - make templates cleaner for save/restore -enum { - TEMPLATE_OFF, - TEMPLATE_SHORT, - TEMPLATE_LONG, - TEMPLATE_MAP, - NTEMPLATES -}; - -enum { - QUIT_NONE, - QUIT_BY_ORDER, - QUIT_BY_GM, - QUIT_AND_RESTART, - QUIT_WON_GAME, - QUIT_GAME_OVER, -}; - -extern char ** AttitudeStrs; -extern char ** FactionStrs; - -// LLS - include strings for the template enum -extern char **TemplateStrs; -int ParseTemplate(AString *); - -int ParseAttitude(AString *); - -int MagesByFacType(int); - -class FactionVector { -public: - FactionVector(int); - ~FactionVector(); - - void ClearVector(); - void SetFaction(int, Faction *); - Faction *GetFaction(int); - - Faction **vector; - int vectorsize; -}; - -class Attitude : public AListElem { -public: - Attitude(); - ~Attitude(); - void Writeout(Aoutfile * ); - void Readin( Ainfile *, ATL_VER version ); - - int factionnum; - int attitude; -}; - -class Statistic { -public: - Statistic(); - ~Statistic(); - - int Value() const { return value; } - void AddValue(int addvalue) {value += addvalue; } //not used at the moment - int value; - int rank; - int maxvalue; -}; - -class FormTemplate : public AListElem -{ - public: - FormTemplate(); - ~FormTemplate(); - void Writeout(Aoutfile * ); - void Readin( Ainfile * ); - AString * GetLine(int); - - AString * name; - AList orders; -}; - -class FactionPtr : public AListElem { -public: - Faction * ptr; -}; - -class Faction : public AListElem -{ -public: - Faction(); - Faction(int); - ~Faction(); - - void Readin( Ainfile *, ATL_VER version ); - void Writeout( Aoutfile * ); - void View(); - - void SetName(AString *); - void SetNameNoChange( AString *str ); - void SetAddress( AString &strNewAddress ); - - void CheckExist(ARegionList *); - void Error(const AString &); - void Event(const AString &); - void Message(const AString &); //BS mod. - - AString FactionTypeStr(); - void WriteReport( Areport *f, Game *pGame ); - // LLS - write order template - void WriteTemplate(Areport *f, Game *pGame); - void WriteFormTemplates(Areport *f); - void WriteFacInfo(Aoutfile *); - - void SetAttitude(int,int); /* faction num, attitude */ - /* if attitude == -1, clear it */ - int GetAttitude(int); - void RemoveAttitude(int); - - int CanCatch(ARegion *,Unit *); - int CanCatchAtSea(ARegion *,Unit *); - /* Return 1 if can see, 2 if can see faction */ - int CanSee(ARegion *,Unit *, int practice = 0); - - void DefaultOrders(); - void TimesReward(); - - void SetNPC(); - int IsNPC(); - - void DiscoverItem(int item, int force, int full); - - int num; - - // - // The type is only used if Globals->FACTION_LIMIT_TYPE == - // FACLIM_FACTION_TYPES - // - int type[NFACTYPES]; - int ethnicity; - - int lastchange; - int lastorders; - int unclaimed; - int bankaccount; - int interest; // not written to game.out - AString * name; - AString * address; - AString * password; - int times; - int showunitattitudes; - int temformat; - char exists; - int quit; - int numshows; - - int nummages; - int numapprentices; - int numqms; - int numtacts; - Statistic guardedcities; - Statistic totalsilver; - Statistic itemnetworth; - Statistic skillnetworth; - Statistic totalnetworth; - Statistic nummen; - Statistic magepower; - int labryinth; // Arcadia only, "labryinth counter". Needs to be saved in the gamefile. - AList war_regions; - AList trade_regions; - - /* Used when writing reports */ - AList present_regions; - - int defaultattitude; - AList attitudes; - SkillList skills; - ItemList items; - //List of templates - AList formtemplates; //FORM_TEMPLATES - AList labeltemplates; //FORM_TEMPLATES - - // - // Both are lists of AStrings - // - AList extraPlayers; - AList messages; // BS mod, extra list for the report. - AList errors; - AList events; - AList battles; - AList shows; - AList itemshows; - AList objectshows; - AList terrainshows; - - // These are used for 'granting' units to a faction via the players.in - // file - ARegion *pReg; - ARegion *pStartLoc; - int start; - int noStartLeader; -}; - -Faction * GetFaction(AList *,int); -Faction * GetFaction2(AList *,int); /*This AList is a list of FactionPtr*/ - -#endif diff --git a/arcadia/fileio.cpp b/arcadia/fileio.cpp deleted file mode 100644 index 5225c0e11..000000000 --- a/arcadia/fileio.cpp +++ /dev/null @@ -1,466 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "fileio.h" -#include "gameio.h" - -#include -#include -using namespace std; - -#define F_ENDLINE '\n' - -extern long _ftype,_fcreator; - -static char buf[1024]; - -Aoutfile::Aoutfile() -{ - file = new ofstream; -} - -Aoutfile::~Aoutfile() -{ - delete file; -} - -Ainfile::Ainfile() -{ - file = new ifstream; -} - -Ainfile::~Ainfile() -{ - delete file; -} - -Aorders::Aorders() -{ - file = new ifstream; -} - -Aorders::~Aorders() -{ - delete file; -} - -Areport::Areport() -{ - file = new ofstream; -} - -Areport::~Areport() -{ - delete file; -} - -Arules::Arules() -{ - file = new ofstream; -} - -Arules::~Arules() -{ - delete file; -} - -void Aoutfile::Open(const AString &s) -{ - while(!(file->rdbuf()->is_open())) { - AString *name = getfilename(s); - file->open(name->Str(), ios::out|ios::ate); - delete name; - // Handle a broke ios::ate implementation on some boxes - file->seekp(0, ios::end); - if((int)file->tellp()!= 0) file->close(); - } -} - -int Aoutfile::OpenByName(const AString &s, int append) -{ - AString temp = s; - if(!append) file->open(temp.Str(), ios::out|ios::ate); - else file->open(temp.Str(), ios::out|ios::app); - if(!file->rdbuf()->is_open()) return -1; - // Handle a broke ios::ate implementation on some boxes - file->seekp(0, ios::end); - if((int)file->tellp() != 0 && !append) { - file->close(); - return -1; - } - return 0; -} - -void Ainfile::Open(const AString &s) -{ - while (!(file->rdbuf()->is_open())) { - AString *name = getfilename(s); - file->open(name->Str(),ios::in); - delete name; - } -} - -int Ainfile::OpenByName(const AString &s) -{ - AString temp = s; - file->open(temp.Str(),ios::in); - if (!(file->rdbuf()->is_open())) return -1; - return 0; -} - -void Aoutfile::Close() -{ - file->close(); -} - -void Ainfile::Close() -{ - file->close(); -} - -void Aorders::Close() -{ - file->close(); -} - -void Areport::Close() -{ - file->close(); -} - -void skipwhite(ifstream *f) -{ - if (f->eof()) return; - int ch = f->peek(); - while((ch == ' ') || (ch == '\n') || (ch == '\t') || - (ch == '\r') || (ch == '\0')) { - f->get(); - if (f->eof()) return; - ch = f->peek(); - } -} - -AString * Ainfile::GetStr() -{ - skipwhite(file); - if (file->peek() == -1 || file->eof()) return 0; - file->getline(buf,1023,F_ENDLINE); - AString * s = new AString((char *) &(buf[0])); - return s; -} - -AString * Ainfile::GetStrNoSkip() -{ - if (file->peek() == -1 || file->eof()) return 0; - file->getline(buf,1023,F_ENDLINE); - AString * s = new AString((char *) &(buf[0])); - return s; -} - -int Ainfile::GetInt() -{ - int x; - *file >> x; - return x; -} - -void Aoutfile::PutInt(int x) -{ - *file << x; - *file << F_ENDLINE; -} - -void Aoutfile::PutStr(char *s) -{ - *file << s << F_ENDLINE; -} - -void Aoutfile::PutStr(const AString &s) -{ - *file << s << F_ENDLINE; -} - -void Aorders::Open(const AString &s) -{ - while (!(file->rdbuf()->is_open())) { - AString *name = getfilename(s); - file->open(name->Str(),ios::in); - delete name; - } -} - -int Aorders::OpenByName(const AString &s) -{ - AString temp = s; - file->open(temp.Str(),ios::in); - if (!(file->rdbuf()->is_open())) return -1; - return 0; -} - -AString * Aorders::GetLine() -{ - skipwhite(file); - if (file->eof()) return 0; - if (file->peek() == -1) return 0; - file->getline(buf,1023,F_ENDLINE); - AString *s = new AString((char *) &(buf[0])); - return s; -} - -void Areport::Open(const AString &s) -{ - while(!(file->rdbuf()->is_open())) { - AString *name = getfilename(s); - file->open(name->Str(),ios::out|ios::ate); - delete name; - // Handle a broke ios::ate implementation on some boxes - file->seekp(0, ios::end); - if((int)file->tellp()!=0) file->close(); - } - tabs = 0; -} - -int Areport::OpenByName(const AString &s) -{ - AString temp = s; - file->open(temp.Str(), ios::out|ios::ate); - if (!file->rdbuf()->is_open()) return -1; - // Handle a broke ios::ate implementation on some boxes - file->seekp(0, ios::end); - if((int)file->tellp() != 0) { - file->close(); - return -1; - } - tabs = 0; - return 0; -} - -void Areport::AddTab() -{ - tabs++; -} - -void Areport::DropTab() -{ - if (tabs > 0) tabs--; -} - -void Areport::ClearTab() -{ - tabs = 0; -} - -void Areport::PutStr(const AString &s,int comment) -{ - AString temp; - for (int i=0; irdbuf()->is_open())) { - AString *name = getfilename(s); - file->open(name->Str(),ios::out|ios::ate); - delete name; - // Handle a broke ios::ate implementation on some boxes - file->seekp(0, ios::end); - if((int)file->tellp()!=0) file->close(); - } - tabs = 0; - wraptab = 0; -} - -int Arules::OpenByName(const AString &s) -{ - AString temp = s; - file->open(temp.Str(), ios::out|ios::trunc); - if (!file->rdbuf()->is_open()) return -1; - // Handle a broke ios::ate implementation on some boxes - file->seekp(0, ios::end); - if((int)file->tellp() != 0) { - file->close(); - return -1; - } - tabs = 0; - wraptab = 0; - return 0; -} - -void Arules::AddTab() -{ - tabs++; -} - -void Arules::DropTab() -{ - if (tabs > 0) tabs--; -} - -void Arules::ClearTab() -{ - tabs = 0; -} - -void Arules::AddWrapTab() -{ - wraptab++; -} - -void Arules::DropWrapTab() -{ - if(wraptab > 0) wraptab--; -} - -void Arules::ClearWrapTab() -{ - wraptab = 0; -} - -void Arules::PutStr(const AString &s) -{ - AString temp; - for (int i=0; i"); - AddTab(); - } else { - DropTab(); - PutStr(AString(""); - } -} - -void Arules::TagText(const AString &tag, const AString &text) -{ - Enclose(1, tag); - PutStr(text); - Enclose(0, tag); -} - -// LLS - converted HTML tags to lowercase -void Arules::ClassTagText(const AString &tag, const AString &cls, - const AString &text) -{ - AString temp = tag; - temp += " class=\""; - temp += cls; - temp += "\""; - Enclose(1, temp); - PutStr(text); - Enclose(0, tag); -} - -// LLS - converted HTML tags to lowercase -void Arules::Paragraph(const AString &text) -{ - Enclose(1, "p"); - PutStr(text); - Enclose(0, "p"); -} - -// LLS - converted HTML tags to lowercase -void Arules::CommandExample(const AString &header, const AString &examp) -{ - Paragraph(header); - Paragraph(""); - Enclose(1, "pre"); - PutNoFormat(examp); - Enclose(0, "pre"); -} - -// LLS - converted HTML tags to lowercase -AString Arules::Link(const AString &href, const AString &text) -{ - return (AString(""+text+""); -} - -// LLS - converted HTML tags to lowercase -void Arules::LinkRef(const AString &name) -{ - PutStr(AString(""); -} diff --git a/arcadia/fileio.h b/arcadia/fileio.h deleted file mode 100644 index 89656ee8b..000000000 --- a/arcadia/fileio.h +++ /dev/null @@ -1,136 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef FILE_IO -#define FILE_IO - -#include "astring.h" - -#include -#include -using namespace std; - -class Ainfile { - public: - Ainfile(); - ~Ainfile(); - - void Open(const AString &); - int OpenByName(const AString &); - void Close(); - - AString *GetStr(); - AString *GetStrNoSkip(); - int GetInt(); - - ifstream *file; -}; - -class Aoutfile { - public: - Aoutfile(); - ~Aoutfile(); - - void Open(const AString &); - int OpenByName(const AString &, int append = 0); - void Close(); - - void PutStr(char *); - void PutStr(const AString &); - void PutInt(int); - - ofstream *file; -}; - -class Aorders { - public: - Aorders(); - ~Aorders(); - - void Open(const AString &); - int OpenByName(const AString &); - void Close(); - - AString *GetLine(); - - ifstream *file; -}; - -class Areport { - public: - Areport(); - ~Areport(); - - void Open(const AString &); - int OpenByName(const AString &); - void Close(); - - void AddTab(); - void DropTab(); - void ClearTab(); - - void PutStr(const AString &,int = 0); - void PutNoFormat(const AString &); - void EndLine(); - - ofstream *file; - int tabs; -}; - -class Arules { - public: - Arules(); - ~Arules(); - - void Open(const AString &); - int OpenByName(const AString &); - void Close(); - - void AddTab(); - void DropTab(); - void ClearTab(); - - void AddWrapTab(); - void DropWrapTab(); - void ClearWrapTab(); - - void PutStr(const AString &); - void WrapStr(const AString &); - void PutNoFormat(const AString &); - void EndLine(); - - void Enclose(int flag, const AString &tag); - void TagText(const AString &tag, const AString &text); - void ClassTagText(const AString &tag, const AString &cls, - const AString &text); - void Paragraph(const AString &text); - void CommandExample(const AString &header, const AString &examp); - AString Link(const AString &href, const AString &text); - void LinkRef(const AString &name); - - ofstream *file; - int tabs; - int wraptab; -}; -#endif diff --git a/arcadia/formation1.cpp b/arcadia/formation1.cpp deleted file mode 100644 index 869023ccc..000000000 --- a/arcadia/formation1.cpp +++ /dev/null @@ -1,473 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "army1.h" -#include "formation1.h" -#include "gameio.h" -#include "gamedata.h" - - -Formation::Formation() -{ - reserve = 0; - flank = 0; - concealed = 0; - bonus = 0; - tempbonus = 0; - nummen = 0; - size = 0; - lastkilled = 0; - type = FORM_FOOT; - behind = 0; - canattack = 0; -} - -Formation::~Formation() -{ - #ifdef DEBUG - Awrite("Formation Destructor"); - #endif - - delete [] pSoldiers; - - #ifdef DEBUG - Awrite("End of Formation Destructor"); - #endif -} - -void Formation::SetupFormation(int formnum, int count) -{ - type = (formnum%6)/2; //0=foot, 1=ride, 2=fly - behind = formnum%2; //0=front, 1=behind - flank = formnum/6; //0=normal, 1 = trying to flank, 2 = has flanked - number = formnum; - if(flank == FORM_FRONT && type != FORM_FOOT) reserve = 1; - - pSoldiers = new SoldierPtr[count]; - for(int i=0; i nummen-1 || soldiernum < 0) { - Awrite(AString("Illegal Get Soldier Access ") + soldiernum + "/" + (nummen-1) ); - return 0; - } - - return pSoldiers[soldiernum]; -} - -Soldier * Formation::GetAttacker(int soldiernum) -//Get a pointer to a particular soldier, and move that soldier out of the canattack section of the soldierarray -//The soldier number should be from 0 to canattack-1. -{ - if(soldiernum > canattack-1 || soldiernum < 0) { - Awrite("Illegal Get Attacker Access"); - return 0; - } - Soldier *temp = pSoldiers[soldiernum]; - //swop temp and the last soldier who can attack - pSoldiers[soldiernum] = pSoldiers[canattack-1]; - pSoldiers[canattack-1] = temp; - canattack--; - return temp; -} - -int Formation::GetNonIllusionSize() const -{ - int hits = 0; - for(int i=0; iillusion) continue; - hits += pSoldiers[i]->maxhits; - } - return hits; -} - -int Formation::CountMages() const -{ - int mages = 0; - for(int i=0; islevel) continue; - if(pSoldiers[i]->unit->type != U_MAGE && pSoldiers[i]->unit->type != U_GUARDMAGE) continue; - if(!(ItemDefs[pSoldiers[i]->race].type & IT_MAN) ) continue; - mages++; - } - return mages; -} - -Soldier * Formation::GetMage(int mage) -{ - for(int i=0; islevel) continue; - if(pSoldiers[i]->unit->type != U_MAGE && pSoldiers[i]->unit->type != U_GUARDMAGE) continue; - if(!(ItemDefs[pSoldiers[i]->race].type & IT_MAN) ) continue; - if(!mage) return pSoldiers[i]; - mage--; - } - return 0; -} - - - -void Formation::AddSoldier(Soldier * pNewsoldier) -//Add a soldier to a formation -//This routine adjust nummen, but does not adjust canattack - ie if it -//is called during a combat round the soldier should not be able -//to attack (eg is dead!). -{ - #ifdef DEBUG - if(nummen < 0) { - Awrite("Number of men out of bounds"); - system("pause"); - } - #endif - - size += pNewsoldier->maxhits; - pSoldiers[nummen++] = pNewsoldier; - pNewsoldier->inform = number; -} - -void Formation::AddCanAttackSoldier(Soldier * pNewsoldier) -//Add a soldier to the front (canattack part) of a formation -//This routine adjust nummen, and canattack - it should only be -//called for soldiers who can attack. -{ - #ifdef DEBUG - if(nummen < 0) { - Awrite("Number of men out of bounds"); - system("pause"); - } - #endif - - size += pNewsoldier->maxhits; - pSoldiers[nummen++] = pSoldiers[canattack]; - pSoldiers[canattack++] = pNewsoldier; - pNewsoldier->inform = number; -} - - -Soldier * Formation::RemoveSoldier(int soldiernum) -//Remove a soldier from a formation -//soldiernum should be a value from 0 to nummen-1. -//This routine adjusts nummen and canattack, so can be called -//anytime, but is slightly quicker if canattack == 0. -{ - if(soldiernum >= nummen || soldiernum < 0) { - Awrite("Illegal Remove Soldier Access"); - return 0; - } - - //temp is the soldier we want to remove - Soldier * temp = pSoldiers[soldiernum]; - - if(soldiernum < canattack) { - //move the last soldier who can attack into temp's old position. - pSoldiers[soldiernum] = pSoldiers[canattack-1]; - //move the last soldier into the newly vacated spot - pSoldiers[canattack-1] = pSoldiers[nummen-1]; - //decrease canattack, marking the last filled spot as cannot attack. - canattack--; - } else { - //move the last soldier into temp's old position. - pSoldiers[soldiernum] = pSoldiers[nummen-1]; - } - - //empty old last soldier's position for safety. - pSoldiers[nummen-1] = 0; - - //decrease number of men and return. - nummen--; - size -= temp->maxhits; - return temp; -} - -void Formation::TransferSoldier(int soldiernum, Formation * pToForm) -//Transfer a soldier from this formation to another. This preserves the -//canattack status of the soldier. -{ - int canatt = 0; - if(soldiernum < canattack) canatt = 1; - //Remove soldier from this formation - Soldier * emmigrant = RemoveSoldier(soldiernum); - //Add soldier to new formation - //Check if the soldier canattack or not. - if(canatt) pToForm->AddCanAttackSoldier(emmigrant); - //remember than canattack just got decreased by 1, hence the '<=' above. - else pToForm->AddSoldier(emmigrant); -} - -void Formation::MoveSoldiers(Formation *pToForm) -//Move all soldiers to target formation. This preserves the canattack -//status of the soldiers. -{ - while(nummen) { - TransferSoldier(0, pToForm); - } -} - -int Formation::MoveSoldiers(Formation *pToForm, int sizetomove, int condition) -//If soldiers are >1 hit, size moved may not be exactly 'sizetomove'. In this -//situation, 'condition' gets tested: -//condition 0: moves equal or less than wanted -//condition 1: moves equal or more than wanted -//return number of men (not size!) moved. -//if sizetomove is negative, will return gracefully. -{ - int nummoved = 0; - while(sizetomove > 0 && GetNumMen()) { - int moving = getrandom(nummen); - if(condition || pSoldiers[moving]->maxhits <= sizetomove) { - sizetomove -= pSoldiers[moving]->maxhits; - TransferSoldier(moving, pToForm); - nummoved++; - } else sizetomove = 0; - } - - return nummoved; -} - -void Formation::Kill(int soldiernum, Army * itsarmy, int numhits) -//This adjusts nummen and canattack, so can be called during -//a combat round. -{ - if(soldiernum >= nummen || soldiernum < 0) { - Awrite("Illegal Soldier Access"); - return; - } - - if(numhits < 0) return; - - if (pSoldiers[soldiernum]->amuletofi) return; - - if(numhits == 1 || pSoldiers[soldiernum]->hits == 1) { - pSoldiers[soldiernum]->damage++; - pSoldiers[soldiernum]->hits--; - //return if soldier is alive - if(pSoldiers[soldiernum]->hits) return; //return if still alive - } else { - //doing more than one hit - if(numhits >= pSoldiers[soldiernum]->hits) { - pSoldiers[soldiernum]->damage += pSoldiers[soldiernum]->hits; - pSoldiers[soldiernum]->hits = 0; - } else { - pSoldiers[soldiernum]->damage += numhits; - pSoldiers[soldiernum]->hits -= numhits; - return; //still alive - } - } - - //soldier is dead! - pSoldiers[soldiernum]->isdead = 1; - pSoldiers[soldiernum]->unit->losses++; - - //transfer soldier to the "dead" formation. - TransferSoldier(soldiernum, &itsarmy->formations[NUMFORMS]); -} - -void Formation::Reset() -//called at the start of a normal round after formation phase -{ - canattack = nummen; - for(int i=0; iClearOneTimeEffects(); - } -} - -void Formation::ResetHeal() const -{ - for(int i=0; iillusion) pSoldiers[i]->canbehealed = 1; - } -} - -void Formation::Regenerate(Battle * b) const -{ - for(int i=0; imaxhits - s->hits; - if (diff > 0) { - AString aName = s->name; - - if (s->damage != 0) { - b->AddLine(aName + " takes " + s->damage + - " hits bringing it to " + s->hits + "/" + - s->maxhits + "."); - s->damage = 0; - } else { - b->AddLine(aName + " takes no hits leaving it at " + - s->hits + "/" + s->maxhits + "."); - } - if (s->regen) { - int regen = s->regen; - if (regen > diff) regen = diff; - s->hits += regen; - b->AddLine(aName + " regenerates " + regen + - " hits bringing it to " + s->hits + "/" + - s->maxhits + "."); - } - } - } -} - -int Formation::Engaged(Army *itsarmy) const -{ - if(GetNumMen() == 0) return 0; - for(int i=0; iengagements[number][i] == ENGAGED_ENGAGED) return 1; - } - return 0; -} - -void Formation::Sort(Army *itsarmy, Battle *b, int regtype) -{ - int i=0; - int missort=0; -// int terrainlimited = 0; -// int tacerror = 0; //1 = one downgrade, 2 = two downgrades - - while(idefaultform == 0) i++; - else if( getrandom(100) < itsarmy->taccontrol) { - //Sorted correctly, move to its default formation. - TransferSoldier(i,&itsarmy->formations[pSoldiers[i]->defaultform]); - } else { - int form = pSoldiers[i]->defaultform; - missort++; - int fallthru = 1; - while(fallthru && (form>0) ) { - //does it fall through again? - if(getrandom(100) < itsarmy->taccontrol) fallthru = 0; - //if behind, 50% chance to fall either way. - if(form%2 && getrandom(2) ) form -= 1; - else form -= 2; - } - if(form < 1) i++; - else TransferSoldier(i,&itsarmy->formations[form]); - } - } - - if(itsarmy->taccontrol == 100) b->AddLine(AString(*(itsarmy->pLeader->name)) + " has full control of his army. All soldiers are correctly assigned to their place."); - else { - AString temp; - if(itsarmy->taccontrol > 70) temp = "slightly."; - else if(itsarmy->taccontrol > 30) temp = "considerably."; - b->AddLine(AString(*(itsarmy->pLeader->name)) + " has " + itsarmy->taccontrol + "% control his army. " + missort + " soldiers are misassigned, and maneuvering is impaired " + temp); - } -} - -int Formation::NumMeleeAttacks() const -{ - int attacks = 0; - for(int i=0; iattacktype == ATTACK_COMBAT) { - if(pSoldiers[i]->attacks>0) attacks += pSoldiers[i]->attacks; - if(pSoldiers[i]->attacks<0) if(!getrandom(-pSoldiers[i]->attacks)) attacks++; - } - } - return attacks; -} - -int Formation::NumRangedAttacks() const -//this is only used for selecting best target. Could maybe include tactics skill etc. here. -{ - int attacks = 0; - int heroes = 0; - for(int i=0; iattacktype == ATTACK_RANGED) { - if(pSoldiers[i]->attacks>0) attacks += pSoldiers[i]->attacks; - if(pSoldiers[i]->attacks<0 && !(getrandom(-pSoldiers[i]->attacks))) attacks++; - } - if(pSoldiers[i]->special) { - SpecialType *sp = FindSpecial(pSoldiers[i]->special); - int damage = 0; - for(int j = 0; j < 4; j++) { - if(sp->damage[j].type == -1) continue; - int times = sp->damage[j].value; - if(sp->effectflags & SpecialType::FX_USE_LEV) times *= pSoldiers[j]->slevel; - if(sp->damage[j].effect == NULL) times *= 2; //ie if it is a killing spell *2, else *1 for fear/storm. - attacks += times; - damage = 1; - } - if(!damage) attacks += pSoldiers[i]->slevel * 20; //some bonus for other spells, - //eg shields, concealment, etc. - } - if(pSoldiers[i]->unit->type == U_LEADER) { - attacks += 1; //increased value for leaders - } - if(pSoldiers[i]->unit->type == U_MAGE) { - forlist(&pSoldiers[i]->unit->skills) { - Skill *sk = (Skill *)elem; - attacks += (sk->days + sk->experience) / 30; //increased value for heroes - } - heroes++; - } - } - - //each hero gives an additional multiplicative bonus to the values - attacks = (attacks * (6+heroes))/6; - return attacks; -} - -float Formation::MeleeAttackLevel() const -{ - int level = 0; - int totalattacks = 0; - for(int i=0; iattacktype == ATTACK_COMBAT) { - int attacks = 0; - if(pSoldiers[i]->attacks>0) attacks = pSoldiers[i]->attacks; - if(pSoldiers[i]->attacks<0 && !getrandom(-pSoldiers[i]->attacks)) attacks = 1; - totalattacks += attacks; - level += pSoldiers[i]->askill * attacks; - } - } - float averagelevel = (float) level / totalattacks; - return averagelevel; -} - -float Formation::MeleeDefenceLevel() const -{ - int level = 0; - for(int i=0; idskill[ATTACK_COMBAT]; - } - float averagelevel = (float) level / nummen; - return averagelevel; -} diff --git a/arcadia/formation1.h b/arcadia/formation1.h deleted file mode 100644 index 9e71a2ab5..000000000 --- a/arcadia/formation1.h +++ /dev/null @@ -1,138 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef FORMATION_CLASS -#define FORMATION_CLASS - -#include -#include -using namespace std; - -class Formation; - -#include "soldier1.h" -#include "unit.h" -#include "alist.h" -#include "items.h" -#include "object.h" -#include "helper.h" - -enum { - FORM_FOOT, - FORM_RIDE, - FORM_FLY, - FORM_ANY -}; - -enum { - ENGAGED_NONE, - ENGAGED_CONDITIONAL, - ENGAGED_CANATTACK, - ENGAGED_TRYATTACK, - ENGAGED_ENGAGED, - ENGAGED_ANY -}; - -enum { - FORM_FRONT, - FORM_FLANKING, - FORM_FLANKED, - FORM_DEAD -}; - -class Formation -{ - public: - Formation(); - ~Formation(); - - void SetupFormation(int formnum, int count); - - int bonus; // modifies the attack chance from 50% to 67% (+1) or 33% (-1) etc. - int tempbonus; // this only applies to the formation currently attacking - - //access methods - int GetNumMen() const { return nummen; } - int GetSize() const { return size; } - void AddSize(int addsize) {size += addsize; } - int Type() const { return type; } - int Behind() const { return behind; } - int Flank() const { return flank; } - int Reserve() const { return reserve; } - int IsConcealed() const { return concealed; } - void SetConcealed(int state) { concealed = state; } - int CanAttack() const { return canattack; } - void SetTemporaryBonus(int b); - void RemoveTemporaryBonus(); - Soldier * GetSoldier(int soldiernum) const; - Soldier * GetAttacker(int soldiernum); - int GetNonIllusionSize() const; - int CountMages() const; - Soldier * GetMage(int); - - - //modification methods - void AddSoldier(Soldier * pSoldier); - void AddCanAttackSoldier(Soldier * pSoldier); - Soldier * RemoveSoldier(int soldiernum); - void TransferSoldier(int, Formation * pToForm); - void MoveSoldiers(Formation * pToForm); - int MoveSoldiers(Formation * pToForm, int sizetomove, int condition=0); - void Kill(int soldiernum, Army *itsarmy, int numhits = 1); - - void Reset(); - void ResetHeal() const; - void Regenerate(Battle *b) const; - - //Magic Targetting: - int CheckSpecialTarget(char *, int soldiernum) const; //This is in specials.cpp - - //Formation Phase methods - int Engaged(Army *itsarmy) const; - void Sort(Army *itsarmy, Battle *b, int regtype); - - int NumMeleeAttacks() const; - int NumRangedAttacks() const; - float MeleeAttackLevel() const; - float MeleeDefenceLevel() const; - - - - private: - //ultimately, type, behind, flank and reserve could all be determined from number, - //so could be got rid of to save 16*19*2 = 608 bytes of memory ;) - SoldierPtr * pSoldiers; - int nummen; - int size; //number of hits in the formation (including illusions). - int lastkilled; //don't think this is used yet? - int type; //should be constant after creation - int behind; //should be constant after creation - int canattack; - int flank; //should be constant after creation - int concealed; // whether formation is concealed (for flanking maneuvres only). - int reserve; - int number; //should be constant after creation. Don't think this is needed? -}; -#endif diff --git a/arcadia/game.cpp b/arcadia/game.cpp deleted file mode 100644 index 086fcacc9..000000000 --- a/arcadia/game.cpp +++ /dev/null @@ -1,2952 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifdef WIN32 -#include // Needed for memcpy on windows -#endif - -#include - -#include "game.h" -#include "unit.h" -#include "fileio.h" -#include "astring.h" -#include "gamedata.h" - -Game::Game() -{ - gameStatus = GAME_STATUS_UNINIT; - ppUnits = 0; - maxppunits = 0; -} - -Game::~Game() -{ - delete ppUnits; - ppUnits = 0; - maxppunits = 0; - Awrite("Deleting Game"); -} - -int Game::TurnNumber() -{ - return (year-1)*12 + month + 1; -} - -// ALT, 25-Jul-2000 -// Default work order procedure -void Game::DefaultWorkOrder() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(r->type == R_NEXUS) continue; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->monthorders || u->faction->IsNPC() || - (Globals->TAX_PILLAGE_MONTH_LONG && - u->taxing != TAX_NONE)) - continue; - if(u->GetFlag(FLAG_AUTOTAX) && - (Globals->TAX_PILLAGE_MONTH_LONG && u->Taxers(1))) { - u->taxing = TAX_AUTO; - } else { - if(Globals->DEFAULT_WORK_ORDER) ProcessWorkOrder(u, 0, 1); - } - } - } - } -} - - -AString Game::GetXtraMap(ARegion *reg,int type) -{ - int i; - - if (!reg) - return(" "); - - switch (type) { - case 0: - return (reg->IsStartingCity() ? "!" : - (reg->HasShaft() ? "*" : " ")); - case 1: - i = reg->CountWMons(); - return (i ? ((AString) i) : (AString(" "))); - case 2: - forlist(®->objects) { - Object *o = (Object *) elem; - if (!(ObjectDefs[o->type].flags & ObjectType::CANENTER)) { - if (o->units.First()) { - return "*"; - } else { - return "."; - } - } - } - return " "; - case 3: - if (reg->gate) return "*"; - return " "; - } - return(" "); -} - -void Game::WriteSurfaceMap(Aoutfile *f, ARegionArray *pArr, int type) -{ - ARegion *reg; - int yy = 0; - int xx = 0; - - f->PutStr(AString("Map (") + xx*32 + "," + yy*16 + ")"); - for (int y=0; y < pArr->y; y+=2) { - AString temp; - int x; - for (x=0; x< pArr->x; x+=2) { - reg = pArr->GetRegion(x+xx*32,y+yy*16); - temp += AString(GetRChar(reg)); - temp += GetXtraMap(reg,type); - temp += " "; - } - f->PutStr(temp); - temp = " "; - for (x=1; x< pArr->x; x+=2) { - reg = pArr->GetRegion(x+xx*32,y+yy*16+1); - temp += AString(GetRChar(reg)); - temp += GetXtraMap(reg,type); - temp += " "; - } - f->PutStr(temp); - } - f->PutStr(""); -} - -void Game::WriteUnderworldMap(Aoutfile *f, ARegionArray *pArr, int type) -{ - ARegion *reg, *reg2; - int xx = 0; - int yy = 0; - f->PutStr(AString("Map (") + xx*32 + "," + yy*16 + ")"); - for (int y=0; y< pArr->y; y+=2) { - AString temp = " "; - AString temp2; - int x; - for (x=0; x< pArr->x; x+=2) { - reg = pArr->GetRegion(x+xx*32,y+yy*16); - reg2 = pArr->GetRegion(x+xx*32+1,y+yy*16+1); - temp += AString(GetRChar(reg)); - temp += GetXtraMap(reg,type); - if(reg2->neighbors[D_NORTH]) temp += "|"; - else temp += " "; - - temp += " "; - if (reg->neighbors[D_SOUTHWEST]) temp2 += "/"; - else temp2 += " "; - - temp2 += " "; - if (reg->neighbors[D_SOUTHEAST]) temp2 += "\\"; - else temp2 += " "; - - temp2 += " "; - } - f->PutStr(temp); - f->PutStr(temp2); - - temp = " "; - temp2 = " "; - for (x=1; x< pArr->x; x+=2) { - reg = pArr->GetRegion(x+xx*32,y+yy*16+1); - reg2 = pArr->GetRegion(x+xx*32-1,y+yy*16); - - if (reg2->neighbors[D_SOUTH]) temp += "|"; - else temp += " "; - - temp += AString(" "); - temp += AString(GetRChar(reg)); - temp += GetXtraMap(reg,type); - - if (reg->neighbors[D_SOUTHWEST]) temp2 += "/"; - else temp2 += " "; - - temp2 += " "; - if (reg->neighbors[D_SOUTHEAST]) temp2 += "\\"; - else temp2 += " "; - - temp2 += " "; - } - f->PutStr(temp); - f->PutStr(temp2); - } - f->PutStr(""); -} - -int Game::ViewMap(const AString & typestr,const AString & mapfile) -{ - int type = 0; - if (AString(typestr) == "wmon") type = 1; - if (AString(typestr) == "lair") type = 2; - if (AString(typestr) == "gate") type = 3; - - Aoutfile f; - if(f.OpenByName(mapfile) == -1) return(0); - - switch (type) { - case 0: - f.PutStr("Geographical Map"); - break; - case 1: - f.PutStr("Wandering Monster Map"); - break; - case 2: - f.PutStr("Lair Map"); - break; - case 3: - f.PutStr("Gate Map"); - break; - } - - int i; - for(i = 0; i < regions.numLevels; i++) { - f.PutStr(""); - ARegionArray *pArr = regions.pRegionArrays[i]; - switch(pArr->levelType) { - case ARegionArray::LEVEL_NEXUS: - f.PutStr(AString("Level ") + i + ": Nexus"); - break; - case ARegionArray::LEVEL_SURFACE: - f.PutStr(AString("Level ") + i + ": Surface"); - WriteSurfaceMap(&f, pArr, type); - break; - case ARegionArray::LEVEL_UNDERWORLD: - f.PutStr(AString("Level ") + i + ": Underworld"); - WriteUnderworldMap(&f, pArr, type); - break; - case ARegionArray::LEVEL_UNDERDEEP: - f.PutStr(AString("Level ") + i + ": Underdeep"); - WriteUnderworldMap(&f, pArr, type); - break; - } - } - - f.Close(); - - return(1); -} - -int Game::NewGame() -{ - factionseq = 1; - guardfaction = 0; - monfaction = 0; - unitseq = 1; - SetupUnitNums(); - shipseq = 100; - year = 1; - month = -1; - gameStatus = GAME_STATUS_NEW; - - // - // Seed the random number generator with a different value each time. - // - seedrandomrandom(); - - CreateWorld(); - Awrite("Creating Factions"); - CreateNPCFactions(); - Awrite("Creating City Guards"); - if(Globals->CITY_MONSTERS_EXIST) - CreateCityMons(); - Awrite("Creating Monsters"); - if(Globals->WANDERING_MONSTERS_EXIST) - CreateWMons(); - if(Globals->LAIR_MONSTERS_EXIST) - CreateLMons(); - - if(Globals->LAIR_MONSTERS_EXIST) - CreateVMons(); - - if(Globals->PLAYER_ECONOMY) { - DevelopTowns(); - Equilibrate(); - } - - return(1); -} - -int Game::OpenGame() -{ - // - // The order here must match the order in SaveGame - // - Ainfile f; - if(f.OpenByName("game.in") == -1) return(0); - - // - // Read in Globals - // - AString *s1 = f.GetStr(); - if(!s1) return(0); - - AString *s2 = s1->gettoken(); - delete s1; - if(!s2) return(0); - - if (!(*s2 == "atlantis_game")) { - delete s2; - f.Close(); - return(0); - } - delete s2; - - ATL_VER eVersion = f.GetInt(); - Awrite(AString("Saved Game Engine Version: ") + ATL_VER_STRING(eVersion)); - if(ATL_VER_MAJOR(eVersion) != ATL_VER_MAJOR(CURRENT_ATL_VER) || - ATL_VER_MINOR(eVersion) != ATL_VER_MINOR(CURRENT_ATL_VER)) { - Awrite("Incompatible Engine versions!"); - return(0); - } - if(ATL_VER_PATCH(eVersion) > ATL_VER_PATCH(CURRENT_ATL_VER)) { - Awrite("This game was created with a more recent Atlantis Engine!"); - return(0); - } - - AString *gameName = f.GetStr(); - if(!gameName) return(0); - - if(!(*gameName == Globals->RULESET_NAME)) { - Awrite("Incompatible rule-set!"); - return(0); - } - - ATL_VER gVersion = f.GetInt(); - Awrite(AString("Saved Rule-Set Version: ") + ATL_VER_STRING(gVersion)); - - if(ATL_VER_MAJOR(gVersion) < ATL_VER_MAJOR(Globals->RULESET_VERSION)) { - Awrite(AString("Upgrading to ") + - ATL_VER_STRING(MAKE_ATL_VER( - ATL_VER_MAJOR(Globals->RULESET_VERSION), 0, 0))); - if (!UpgradeMajorVersion(gVersion)) { - Awrite("Unable to upgrade! Aborting!"); - return(0); - } - gVersion = MAKE_ATL_VER(ATL_VER_MAJOR(Globals->RULESET_VERSION), 0, 0); - } - if(ATL_VER_MINOR(gVersion) < ATL_VER_MINOR(Globals->RULESET_VERSION)) { - Awrite(AString("Upgrading to ") + - ATL_VER_STRING(MAKE_ATL_VER( - ATL_VER_MAJOR(Globals->RULESET_VERSION), - ATL_VER_MINOR(Globals->RULESET_VERSION), 0))); - if (! UpgradeMinorVersion(gVersion)) { - Awrite("Unable to upgrade! Aborting!"); - return(0); - } - gVersion = MAKE_ATL_VER(ATL_VER_MAJOR(gVersion), - ATL_VER_MINOR(Globals->RULESET_VERSION), 0); - } - if(ATL_VER_PATCH(gVersion) < ATL_VER_PATCH(Globals->RULESET_VERSION)) { - Awrite(AString("Upgrading to ") + - ATL_VER_STRING(Globals->RULESET_VERSION)); - if (! UpgradePatchLevel(gVersion)) { - Awrite("Unable to upgrade! Aborting!"); - return(0); - } - gVersion = MAKE_ATL_VER(ATL_VER_MAJOR(gVersion), - ATL_VER_MINOR(gVersion), - ATL_VER_PATCH(Globals->RULESET_VERSION)); - } - - year = f.GetInt(); - month = f.GetInt(); - seedrandom(f.GetInt()); - factionseq = f.GetInt(); - unitseq = f.GetInt(); - shipseq = f.GetInt(); - guardfaction = f.GetInt(); - monfaction = f.GetInt(); - elfguardfaction = f.GetInt(); - dwarfguardfaction = f.GetInt(); - independentguardfaction = f.GetInt(); - ghostfaction = f.GetInt(); - peasantfaction = f.GetInt(); - - // - // Read in the Factions - // - int i = f.GetInt(); - - for (int j=0; jReadin(&f, eVersion); - factions.Add(temp); - } - - // - // Read in the ARegions - // - i = regions.ReadRegions(&f, &factions, eVersion); - if(!i) return 0; - - SetupUnitNums(); - - f.Close(); - return(1); -} - -int Game::SaveGame() -{ - Awrite("Writing the Gamefile"); - Aoutfile f; - if(f.OpenByName("game.out") == -1) return(0); - - // - // Write out Globals - // - f.PutStr("atlantis_game"); - f.PutInt(CURRENT_ATL_VER); - f.PutStr(Globals->RULESET_NAME); - f.PutInt(Globals->RULESET_VERSION); - - f.PutInt(year); - f.PutInt(month); - f.PutInt(getrandom(10000)); - f.PutInt(factionseq); - f.PutInt(unitseq); - f.PutInt(shipseq); - f.PutInt(guardfaction); - f.PutInt(monfaction); - f.PutInt(elfguardfaction); - f.PutInt(dwarfguardfaction); - f.PutInt(independentguardfaction); - f.PutInt(ghostfaction); - f.PutInt(peasantfaction); - - // - // Write out the Factions - // - f.PutInt(factions.Num()); - - forlist(&factions) { - ((Faction *) elem)->Writeout(&f); - } - - // - // Write out the ARegions - // - //Awrite("Writing Regions"); - regions.WriteRegions(&f); - - f.Close(); - return(1); -} - -void Game::DummyGame() -{ - // - // No need to set anything up; we're just syntax checking some orders. - // -} - -void Game::FakeGame(Faction *realfac) -{ - //in all regions not visible to the realfac, make terrain "fake" and destroy all units - //in regions visible but not present, destroy all units - //in regions present, destroy all units cannot see - //this leaves us with just what the faction knows about from their last report. - - Awrite("Making a fake game!"); - - forlist(®ions) { - ARegion *reg = (ARegion *)elem; - reg->marker = 0; //regions marked "0" default. - } - - forlist_reuse(®ions) { - ARegion *reg = (ARegion *)elem; - if(reg->Present(realfac)) { - reg->marker = 1; //if we're present, regions get marked "1". - - for (int j=0; jneighbors[j]) { - if(!reg->neighbors[j]->marker) reg->neighbors[j]->marker = 2; //this region is visible to us. If we're not present there, mark it "2". - } - } - } - } - forlist_reuse(®ions) { - ARegion *reg = (ARegion *)elem; - if(reg->marker == 0) { - //we could not see this region. Make it a fake region type - reg->Fake(); - } - - if(reg->marker != 1) { - //delete all units here since we're not present - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - u->MoveUnit(0); //routine for destroying a unit, from ARegion::Kill() - reg->hell.Add(u); - } - } - //clear hexsides that aren't visible - if(Globals->HEXSIDE_TERRAIN) { - for (int i=0; ineighbors[i] && reg->neighbors[i]->marker != 1) { - reg->hexside[i]->type = H_DUMMY; - reg->hexside[i]->road = 0; - reg->hexside[i]->bridge = 0; - reg->hexside[i]->harbour = 0; - } - } - } - } else { - //we are present here ... - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - if(u->faction != realfac) { - if(!realfac->CanSee(reg, u, 0)) { - u->MoveUnit(0); //we can't see it, so it doesn't exist! - reg->hell.Add(u); - } //else if its foggy, delete the unit - } - } - } - } - } - - - //spread free love around the world ... - forlist_reuse(&factions) { - Faction *f = (Faction *) elem; - if(f == realfac) continue; - //all other factions love everybody ... - f->defaultattitude = A_ALLY; - f->attitudes.DeleteAll(); - } -} - - - -#define PLAYERS_FIRST_LINE "AtlantisPlayerStatus" - -int Game::WritePlayers() -{ - Aoutfile f; - if(f.OpenByName("players.out") == -1) return(0); - - f.PutStr(PLAYERS_FIRST_LINE); - f.PutStr(AString("Version: ") + CURRENT_ATL_VER); - f.PutStr(AString("TurnNumber: ") + TurnNumber()); - - if(gameStatus == GAME_STATUS_UNINIT) - return(0); - else if(gameStatus == GAME_STATUS_NEW) - f.PutStr(AString("GameStatus: New")); - else if(gameStatus == GAME_STATUS_RUNNING) - f.PutStr(AString("GameStatus: Running")); - else if(gameStatus == GAME_STATUS_FINISHED) - f.PutStr(AString("GameStatus: Finished")); - - f.PutStr(""); - - forlist(&factions) { - Faction *fac = (Faction *) elem; - fac->WriteFacInfo(&f); - } - - f.Close(); - return(1); -} - -int Game::ReadPlayers() -{ - Aorders f; - if(f.OpenByName("players.in") == -1) return(0); - - AString *pLine = 0; - AString *pToken = 0; - - // - // Default: failure. - // - int rc = 0; - - do { - // - // The first line of the file should match. - // - pLine = f.GetLine(); - if(!(*pLine == PLAYERS_FIRST_LINE)) break; - SAFE_DELETE(pLine); - - // - // Get the file version number. - // - pLine = f.GetLine(); - pToken = pLine->gettoken(); - if(!pToken || !(*pToken == "Version:")) break; - SAFE_DELETE(pToken); - - pToken = pLine->gettoken(); - if(!pToken) break; - - int nVer = pToken->value(); - if(ATL_VER_MAJOR(nVer) != ATL_VER_MAJOR(CURRENT_ATL_VER) || - ATL_VER_MINOR(nVer) != ATL_VER_MINOR(CURRENT_ATL_VER) || - ATL_VER_PATCH(nVer) > ATL_VER_PATCH(CURRENT_ATL_VER)) { - Awrite("The players.in file is not compatible with this " - "version of Atlantis."); - break; - } - SAFE_DELETE(pToken); - SAFE_DELETE(pLine); - - // - // Ignore the turn number line. - // - pLine = f.GetLine(); - SAFE_DELETE(pLine); - - // - // Next, the game status. - // - pLine = f.GetLine(); - pToken = pLine->gettoken(); - if(!pToken || !(*pToken == "GameStatus:")) break; - SAFE_DELETE(pToken); - - pToken = pLine->gettoken(); - if(!pToken) break; - - if(*pToken == "New") - gameStatus = GAME_STATUS_NEW; - else if(*pToken == "Running") - gameStatus = GAME_STATUS_RUNNING; - else if(*pToken == "Finished") - gameStatus = GAME_STATUS_FINISHED; - else { - // - // The status doesn't seem to be valid. - // - break; - } - SAFE_DELETE(pToken); - - // - // Now, we should have a list of factions. - // - pLine = f.GetLine(); - Faction *pFac = 0; - - int lastWasNew = 0; - - // - // OK, set our return code to success; we'll set it to fail below - // if necessary. - // - rc = 1; - - while(pLine) { - pToken = pLine->gettoken(); - if(!pToken) { - SAFE_DELETE(pLine); - pLine = f.GetLine(); - continue; - } - - if(*pToken == "Faction:") { - // - // Get the new faction - // - SAFE_DELETE(pToken); - pToken = pLine->gettoken(); - if(!pToken) { - rc = 0; - break; - } - - if(*pToken == "new") { - AString save = *pLine; - int noleader = 0; - int x, y, z; - ARegion *pReg = NULL; - - /* Check for the noleader flag */ - SAFE_DELETE(pToken); - pToken = pLine->gettoken(); - if (pToken && *pToken == "noleader") { - noleader = 1; - SAFE_DELETE(pToken); - pToken = pLine->gettoken(); - /* Initialize pReg to something useful */ - pReg = regions.GetRegion(0, 0, 0); - } - if (pToken) { - x = pToken->value(); - y = -1; - z = 1; - SAFE_DELETE(pToken); - pToken = pLine->gettoken(); - if (pToken) { - y = pToken->value(); - SAFE_DELETE(pToken); - pToken = pLine->gettoken(); - if (pToken) { - z = pToken->value(); - } - pReg = regions.GetRegion(x, y, z); - } - if (pReg == NULL) - Awrite(AString("Bad faction line: ")+save); - } else { - int numfound = 0; - forlist(®ions) { - ARegion *reg = (ARegion *) elem; - if(reg->flagpole == FL_UNUSED_START_LOC) { - numfound++; - if(!getrandom(numfound)) pReg = reg; - } - } - if(pReg) pReg->flagpole = FL_USED_START_LOC; - } - - pFac = AddFaction(noleader, pReg); - if(!pFac) { - Awrite("Failed to add a new faction!"); - rc = 0; - break; - } - - lastWasNew = 1; - } else { - if(pFac && lastWasNew) { - WriteNewFac(pFac); - } - int nFacNum = pToken->value(); - pFac = GetFaction(&factions, nFacNum); - lastWasNew = 0; -// if(pFac) pFac->TimesReward(); //Arcadia mod, always on! - } - } else if(pFac) { - if(!ReadPlayersLine(pToken, pLine, pFac, lastWasNew)) { - rc = 0; - break; - } - } - - SAFE_DELETE(pToken); - SAFE_DELETE(pLine); - pLine = f.GetLine(); - } - if(pFac && lastWasNew) { - WriteNewFac(pFac); - } - } while(0); - - SAFE_DELETE(pLine); - SAFE_DELETE(pToken); - f.Close(); - - return(rc); -} - -Unit *Game::ParseGMUnit(AString *tag, Faction *pFac) -{ - char *str = tag->Str(); - if(*str == 'g' && *(str+1) == 'm') { - AString p = AString(str+2); - int gma = p.value(); - forlist(®ions) { - ARegion *reg = (ARegion *)elem; - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - if(u->faction->num == pFac->num && u->gm_alias == gma) { - return u; - } - } - } - } - } else { - int v = tag->value(); - if((unsigned int)v >= maxppunits) return NULL; - return GetUnit(v); - } - return NULL; -} - -int Game::ReadPlayersLine(AString *pToken, AString *pLine, Faction *pFac, - int newPlayer) -{ - AString *pTemp = 0; - - if(*pToken == "Name:") { - pTemp = pLine->StripWhite(); - if(pTemp) { - if(newPlayer) { - *pTemp += AString(" (") + (pFac->num) + ")"; - } - pFac->SetNameNoChange(pTemp); - } - } else if(*pToken == "RewardTimes") { - pFac->TimesReward(); - } else if(*pToken == "Village:") { - pTemp = pLine->StripWhite(); - if(pTemp) { - if(pFac->pStartLoc) { - if(pFac->pStartLoc->town) { - AString *newname = pTemp->getlegal(); - delete pFac->pStartLoc->town->name; - pFac->pStartLoc->town->name = newname; - } - } - } - } else if(*pToken == "Hero:") { - pTemp = pLine->StripWhite(); - if(pTemp && pFac->pStartLoc) { - forlist(&pFac->pStartLoc->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if(u->faction == pFac && u->type == U_MAGE && pTemp) { - u->SetName(pTemp); - pTemp = 0; - } - } - } - } - } else if(*pToken == "Race:") { - pTemp = pLine->gettoken(); - if(pTemp && pFac->pStartLoc) { - forlist(&pFac->pStartLoc->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - int starter = 1; - if(u->faction == pFac && u->type == U_MAGE) { - while(pTemp && starter) { - int item = ParseEnabledItem(pTemp); - ManType *mt = 0; - if(item > -1) mt = FindRace(ItemDefs[item].abr); - if(mt && mt->ethnicity == u->GetEthnicity()) { - pFac->pStartLoc->race = item; - int firstman = 1; - forlist(&u->items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MAN) { - if(firstman) i->type = item; - else i->num = 0; - firstman = 0; - } - } - } - pTemp = pLine->gettoken(); - } - starter = 0; - } - } - } - } - } else if(*pToken == "Email:") { - pTemp = pLine->gettoken(); - if(pTemp) { - delete pFac->address; - pFac->address = pTemp; - pTemp = 0; - } - } else if(*pToken == "Password:") { - pTemp = pLine->StripWhite(); - delete pFac->password; - if(pTemp) { - pFac->password = pTemp; - pTemp = 0; - } else { - AString * pDefault = new AString("none"); - pFac->password = pDefault; - } - } else if(*pToken == "Template:") { - // LLS - looked like a good place to stick the Template test - pTemp = pLine->gettoken(); - int nTemp = ParseTemplate(pTemp); - pFac->temformat = TEMPLATE_LONG; - if (nTemp != -1) pFac->temformat = nTemp; - } else if(*pToken == "Reward:") { - pTemp = pLine->gettoken(); - int nAmt = pTemp->value(); - pFac->Event(AString("Reward of ") + nAmt + " silver."); - pFac->unclaimed += nAmt; - } else if(*pToken == "SendTimes:") { - // get the token, but otherwise ignore it - pTemp = pLine->gettoken(); - pFac->times = pTemp->value(); - } else if (*pToken == "LastOrders:") { - // Read this line and correctly set the lastorders for this - // faction if the game itself isn't maintaining them. - pTemp = pLine->gettoken(); - if(Globals->LASTORDERS_MAINTAINED_BY_SCRIPTS) - pFac->lastorders = pTemp->value(); - } else if(*pToken == "Loc:") { - int x, y, z; - pTemp = pLine->gettoken(); - if(pTemp) { - x = pTemp->value(); - delete pTemp; - pTemp = pLine->gettoken(); - if(pTemp) { - y = pTemp->value(); - delete pTemp; - pTemp = pLine->gettoken(); - if(pTemp) { - z = pTemp->value(); - ARegion *pReg = regions.GetRegion(x, y, z); - if(pReg) { - pFac->pReg = pReg; - } else { - Awrite(AString("Invalid Loc:")+x+","+y+","+z+ - " in faction " + pFac->num); - pFac->pReg = NULL; - } - } - } - } - } else if(*pToken == "NewUnit:") { - // Creates a new unit in the location specified by a Loc: line - // with a gm_alias of whatever is after the NewUnit: tag. - if(!pFac->pReg) { - Awrite(AString("NewUnit is not valid without a Loc: ") + - "for faction "+ pFac->num); - } else { - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("NewUnit: must be followed by an alias ") + - "in faction "+pFac->num); - } else { - int val = pTemp->value(); - if(!val) { - Awrite(AString("NewUnit: must be followed by an alias ") + - "in faction "+pFac->num); - } else { - Unit *u = GetNewUnit(pFac); - u->gm_alias = val; - u->MoveUnit(pFac->pReg->GetDummy()); - u->Event("Is given to your faction."); - } - } - } - } else if(*pToken == "Item:") { - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Item: needs to specify a unit in faction ") + - pFac->num); - } else { - Unit *u = ParseGMUnit(pTemp, pFac); - if(!u) { - Awrite(AString("Item: needs to specify a unit in faction ") + - pFac->num); - } else { - if(u->faction->num != pFac->num) { - Awrite(AString("Item: unit ")+ u->num + - " doesn't belong to " + "faction " + pFac->num); - } else { - delete pTemp; - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Must specify a number of items to ") + - "give for Item: in faction " + pFac->num); - } else { - int v = pTemp->value(); - if(!v) { - Awrite(AString("Must specify a number of ") + - "items to give for Item: in " + - "faction " + pFac->num); - } else { - delete pTemp; - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Must specify a valid item ") + - "to give for Item: in faction " + - pFac->num); - } else { - int it = ParseAllItems(pTemp); - if(it == -1) { - Awrite(AString("Must specify a valid ") + - "item to give for Item: in " + - "faction " + pFac->num); - } else { - int has = u->items.GetNum(it); - u->items.SetNum(it, has + v); - if(!u->gm_alias) { - u->Event(AString("Is given ") + - ItemString(it, v) + - " by the gods."); - } - u->faction->DiscoverItem(it, 0, 1); - } - } - } - } - } - } - } - } else if(*pToken == "Skill:") { - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Skill: needs to specify a unit in faction ") + - pFac->num); - } else { - Unit *u = ParseGMUnit(pTemp, pFac); - if(!u) { - Awrite(AString("Skill: needs to specify a unit in faction ") + - pFac->num); - } else { - if(u->faction->num != pFac->num) { - Awrite(AString("Skill: unit ")+ u->num + - " doesn't belong to " + "faction " + pFac->num); - } else { - delete pTemp; - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Must specify a valid skill for ") + - "Skill: in faction " + pFac->num); - } else { - int sk = ParseSkill(pTemp); - if(sk == -1) { - Awrite(AString("Must specify a valid skill for ")+ - "Skill: in faction " + pFac->num); - } else { - delete pTemp; - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Must specify a days for ") + - "Skill: in faction " + pFac->num); - } else { - int days = pTemp->value() * u->GetMen(); - if(!days) { - Awrite(AString("Must specify a days for ")+ - "Skill: in faction " + pFac->num); - } else { - int odays = u->skills.GetDays(sk); - u->skills.SetDays(sk, odays + days); - u->AdjustSkills(); - int lvl = u->GetRealSkill(sk); - if(lvl > pFac->skills.GetDays(sk)) { - pFac->skills.SetDays(sk, lvl); - pFac->shows.Add(new ShowSkill(sk,lvl)); - } - if(!u->gm_alias) { - u->Event(AString("Is taught ") + - days + " days of " + - SkillStrs(sk) + - " by the gods."); - } - /* - * This is NOT quite the same, but the gods - * are more powerful than mere mortals - */ - int mage = (SkillDefs[sk].flags & - SkillType::MAGIC); - int app = (SkillDefs[sk].flags & - SkillType::APPRENTICE); - if(mage) { - u->type = U_MAGE; - } - if(app && u->type == U_NORMAL) { - u->type = U_APPRENTICE; - } - } - } - } - } - } - } - } - } else if(*pToken == "Order:") { - pTemp = pLine->StripWhite(); - if(*pTemp == "quit") { - pFac->quit = QUIT_BY_GM; - } else { - // handle this as a unit order - delete pTemp; - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Order: needs to specify a unit in faction ") + - pFac->num); - } else { - Unit *u = ParseGMUnit(pTemp, pFac); - if(!u) { - Awrite(AString("Order: needs to specify a unit in ")+ - "faction " + pFac->num); - } else { - if(u->faction->num != pFac->num) { - Awrite(AString("Order: unit ")+ u->num + - " doesn't belong to " + "faction " + - pFac->num); - } else { - delete pTemp; - AString saveorder = *pLine; - int getatsign = pLine->getat(); - int getquietsign = pLine->getexclamation(); - pTemp = pLine->gettoken(); - if(!pTemp) { - Awrite(AString("Order: must provide unit order ")+ - "for faction "+pFac->num); - } else { - int o = Parse1Order(pTemp); - if(o == -1 || o == O_ATLANTIS || o == O_END || - o == O_UNIT || o == O_FORM || - o == O_ENDFORM) { - Awrite(AString("Order: invalid order given ")+ - "for faction "+pFac->num); - } else { - if(getatsign) { - u->oldorders.Add(new AString(saveorder)); - } - ProcessOrder(o, u, pLine, NULL, getquietsign); - } - } - } - } - } - } - } else { - pTemp = new AString(*pToken + *pLine); - pFac->extraPlayers.Add(pTemp); - pTemp = 0; - } - - if(pTemp) delete pTemp; - return(1); -} - -void Game::WriteNewFac(Faction *pFac) -{ - AString *strFac = new AString(AString("Adding ") + *(pFac->address) + "."); - newfactions.Add(strFac); -} - -int Game::DoOrdersCheck(const AString &strOrders, const AString &strCheck) -{ - Aorders ordersFile; - if(ordersFile.OpenByName(strOrders) == -1) { - Awrite("No such orders file!"); - return(0); - } - - Aoutfile checkFile; - if(checkFile.OpenByName(strCheck) == -1) { - Awrite("Couldn't open the orders check file!"); - return(0); - } - - OrdersCheck check; - check.pCheckFile = &checkFile; - - ParseOrders(0, &ordersFile, &check); - - ordersFile.Close(); - checkFile.Close(); - - return(1); -} - -int Game::DoOrdersCheckAll(const AString &strOrders, const AString &strCheck) -{ - Awrite("Setting Up Turn..."); - PreProcessTurn(); - - Awrite("Reading the Gamemaster File..."); - if(!ReadPlayers()) return(0); - - Awrite("Done."); - - if(gameStatus == GAME_STATUS_FINISHED) { - Awrite("This game is finished!"); - return(0); - } - gameStatus = GAME_STATUS_RUNNING; - - if(Globals->ARCADIA_MAGIC) { - SetupGuardsmenAttitudes(); - } - - //setup the orders checking - Aorders ordersFile; - if(ordersFile.OpenByName(strOrders) == -1) { - Awrite("No such orders file!"); - return(0); - } - - Aoutfile checkFile; - if(checkFile.OpenByName(strCheck) == -1) { - Awrite("Couldn't open the orders check file!"); - return(0); - } - - OrdersCheck check; - check.pCheckFile = &checkFile; - - Faction *checkfaction = ReadUnknownOrders(&ordersFile); - - if(!checkfaction) { - Awrite("We're stuffed now!"); - checkFile.PutStr("Something went wrong with identifying your faction. Please contact the GM."); - } else { - FakeGame(checkfaction); - //we now have a game consisting only of the faction in question and what they can see. - //normally we would now runorders. However, there are some which we might like not to use. - - RunCheckAllOrders(); - //the game's now done as far as the faction is concerned. - - if (checkfaction->errors.Num()) { - checkFile.PutStr("Testing your orders appears to have generated the following errors:"); - checkFile.PutStr(""); - - forlist((&checkfaction->errors)) { - checkFile.PutStr(*((AString *) elem)); - } - checkfaction->errors.DeleteAll(); - checkFile.PutStr(""); - checkFile.PutStr("Please note that those errors were generated without consideration for the actions of other factions, the conduct of battles, or terrain or units not visible in your last report. As such they may not be an accurate representation of your eventual turn."); - } else { - checkFile.PutStr("Testing your orders appears to have generated no errors."); - } - } - checkFile.PutStr(""); - checkFile.PutStr("Below is the traditional order check, which currently may show additional or different errors."); - checkFile.PutStr(""); - - //need to delete the game situation. - //currently not done ... seems to work *fingers crossed* - - ordersFile.Close(); -// ordersFile.OpenByName(strOrders); //recycling the old one this way doesn't seem to work, don't know why. So making a new one: - Aorders ordersFile2; - if(ordersFile2.OpenByName(strOrders) == -1) { - Awrite("No such orders file!"); - return(0); - } - - DummyGame(); - ParseOrders(0, &ordersFile2, &check); - - ordersFile2.Close(); - checkFile.Close(); - - return(1); -} - -int Game::RunGame() -{ - Awrite("Setting Up Turn..."); - PreProcessTurn(); - - Awrite("Reading the Gamemaster File..."); - if(!ReadPlayers()) return(0); - - if(gameStatus == GAME_STATUS_FINISHED) { - Awrite("This game is finished!"); - return(0); - } - gameStatus = GAME_STATUS_RUNNING; - - Awrite("Reading the Orders File..."); - ReadOrders(); - - if(Globals->MAX_INACTIVE_TURNS != -1) { - Awrite("QUITting Inactive Factions..."); - RemoveInactiveFactions(); - } - - if(Globals->ARCADIA_MAGIC) { - SetupGuardsmenAttitudes(); - } - - Awrite("Running the Turn..."); - RunOrders(); - - Awrite("Writing times articles..."); - CreateTimesReports(); - - Awrite("Writing the Report File..."); - WriteReports(); - Awrite(""); - // LLS - write order templates - if(Globals->SEPERATE_TEMPLATES) { - Awrite("Writing order templates..."); - WriteTemplates(); - Awrite(""); - } - battles.DeleteAll(); - - if(month==11 || month==5) WritePowers(); - - Awrite("Writing Playerinfo File..."); - WritePlayers(); - - Awrite("Removing Dead Factions..."); - DeleteDeadFactions(); - Awrite("done"); - - return(1); -} - -void Game::PreProcessTurn() -{ - month++; - if (month>11) { - month = 0; - year++; - } - SetupUnitNums(); - forlist(&factions) { - ((Faction *) elem)->DefaultOrders(); - } - { - forlist(®ions) { - ARegion *pReg = (ARegion *) elem; - if(Globals->WEATHER_EXISTS) - pReg->SetWeather(regions.GetWeather(pReg, month)); - if(Globals->GATES_NOT_PERENNIAL) - pReg->SetGateStatus(month); - pReg->DefaultOrders(peasantfaction); - } - } -} - -void Game::ClearOrders(Faction *f) -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == f) { - u->ClearOrders(); - } - } - } - } -} - -void Game::ReadOrders() -{ - forlist(&factions) { - Faction *fac = (Faction *) elem; - if(!fac->IsNPC()) { - AString str = "orders."; - str += fac->num; - Aorders file; - if(file.OpenByName(str) != -1) { - ParseOrders(fac->num, &file, 0); - file.Close(); - } - DefaultWorkOrder(); //does this need to be repeated after each load? - } - } -} - -Faction * Game::ReadUnknownOrders(Aorders *f) -{ - Faction *fac = ParseOrders(0, f, 0); - return fac; -} - -void Game::MakeFactionReportLists() -{ - FactionVector vector(factionseq); - - forlist(®ions) { - vector.ClearVector(); - - ARegion *reg = (ARegion *) elem; - forlist(®->farsees) { - Faction *fac = ((Farsight *) elem)->faction; - vector.SetFaction(fac->num, fac); - } - { - forlist(®->passers) { - Faction *fac = ((Farsight *)elem)->faction; - vector.SetFaction(fac->num, fac); - } - } - { - forlist(®->objects) { - Object *obj = (Object *) elem; - - forlist(&obj->units) { - Unit *unit = (Unit *) elem; - vector.SetFaction(unit->faction->num, unit->faction); - } - } - } - - for (int i=0; iptr = reg; - vector.GetFaction(i)->present_regions.Add(ptr); - } - } - } -} - - -int Game::RunStatistics() -{ - - Aoutfile f; - Ainfile g; - - MakeFactionReportLists(); - CountAllMages(); - if(Globals->APPRENTICES_EXIST) CountAllApprentices(); - CountAllPower(); //counts men as well - CountGuardedCities(); - - AString str = "stats"; - str = str + year; - str = str + "-"; - str = str + (month+1); - str = str + ".txt"; - - AString oldstr = "stats"; - int tmpmonth = month; - int tmpyear = year; - if(tmpmonth == 0) { - tmpmonth = 12; - tmpyear--; - } - oldstr = oldstr + tmpyear; - oldstr = oldstr + "-"; - oldstr = oldstr + tmpmonth; - oldstr = oldstr + ".txt"; - - int i = f.OpenByName( str ); - int j = g.OpenByName(oldstr); - - if(i != -1) { - WriteStatistics( &f, &g, j ); - f.Close(); - } - - return (1); -} - -int Game::WriteStatistics( Aoutfile *f, Ainfile *g, int gfile ) -{ - //stats stuff: - int population = 0; - forlist(®ions) { - ARegion *r = (ARegion *)elem; - population += r->Population(); - } - - -//Format is: - -// Faction -//Value, , , ... -//Size, , , ... - - if(gfile == -1) { - f->PutStr(AString("World_Population, ") + population); - f->PutStr("_"); - - forlist(&factions) { - Faction *fac = (Faction *)elem; - f->PutStr( AString(fac->num) + " Faction"); - f->PutStr( AString("Men, ") + fac->nummen.Value()); - f->PutStr( AString("Item_Value, ") + fac->itemnetworth.Value()); - f->PutStr( AString("Skill_Value, ") + fac->skillnetworth.Value()); - f->PutStr( AString("Total_Value, ") + fac->totalnetworth.Value()); - f->PutStr( AString("Heros, ") + fac->magepower.Value()); - f->PutStr( AString("Cities, ") + fac->guardedcities.Value()); - f->PutStr( AString("Labryinth, ") + fac->labryinth); - f->PutStr( AString("_") ); //seems to have problems parsing empty lines - } - return 1; - } -//is a gfile! - - //general game stuff - AString *pop = g->GetStr(); - *pop += AString(", ") + population; - f->PutStr( *pop ); - delete pop; - AString *drag4 = g->GetStr(); - *drag4 += "_"; - f->PutStr( *drag4 ); - delete drag4; - - - //faction stuff - forlist_reuse(&factions) { - Faction *fac = (Faction *)elem; - AString *s1 = g->GetStr(); - if(!s1) return(0); - - int num = s1->value(); - while(num != fac->num) { - //write an empty faction (ie one now dead) - f->PutStr(*s1); //faction line - delete s1; - for(int i=0; i<8; i++) { //must change this number if add more stats lines - AString *temp = g->GetStr(); - if(!temp) return(0); - if(i<7) *temp += ", 0"; //all lines except the blank end. change this number also! - else *temp += "_"; - f->PutStr(*temp); - delete temp; - } - s1 = g->GetStr(); - if(!s1) return(0); - num = s1->value(); - } - - f->PutStr(*s1); //faction line - delete s1; - AString *s2 = g->GetStr(); - *s2 += AString(", ") + fac->nummen.Value(); - f->PutStr(*s2); - delete s2; - AString *s3 = g->GetStr(); - *s3 += AString(", ") + fac->itemnetworth.Value(); - f->PutStr(*s3); - delete s3; - AString *ss3 = g->GetStr(); - *ss3 += AString(", ") + fac->skillnetworth.Value(); - f->PutStr(*ss3); - delete ss3; - AString *sss3 = g->GetStr(); - *sss3 += AString(", ") + fac->totalnetworth.Value(); - f->PutStr(*sss3); - delete sss3; - AString *s4 = g->GetStr(); - *s4 += AString(", ") + fac->magepower.Value(); - f->PutStr(*s4); - delete s4; - AString *s5 = g->GetStr(); - *s5 += AString(", ") + fac->guardedcities.Value(); - f->PutStr( *s5 ); - delete s5; - AString *s6 = g->GetStr(); //blank - *s6 += AString(", ") + fac->labryinth; - f->PutStr( *s6 ); - delete s6; - AString *s7 = g->GetStr(); //blank - *s7 += "_"; - f->PutStr( *s7 ); - delete s7; - } - return 1; -} - -void Game::WritePowers() -{ - Areport f; - - AString str = "times.5"; - - int i = f.OpenByName( str ); - if(i != -1) { - f.PutStr("From the Peasants of Xanaxor."); - f.PutStr("Bringing you statistics in June and December."); - f.PutStr(""); - - f.PutStr("A list of Empire Values:"); - f.PutStr(""); - for(int i=1; i<17; i++) { - forlist(&factions) { - Faction * fac = (Faction *) elem; - if(fac->IsNPC()) continue; - if(fac->totalnetworth.rank == i) { - f.PutStr( AString("Rank ") + i + ": " + fac->totalnetworth.Value() + " silver"); - } - } - } - - f.PutStr(""); - f.PutStr("A list of Empire Sizes:"); - f.PutStr(""); - for(int i=1; i<17; i++) { - forlist(&factions) { - Faction * fac = (Faction *) elem; - if(fac->IsNPC()) continue; - if(fac->nummen.rank == i) { - f.PutStr( AString("Rank ") + i + ": " + fac->nummen.Value() + " men"); - } - } - } - - f.PutStr(""); - f.PutStr("A list of Hero Scores:"); - f.PutStr(""); - for(int i=1; i<17; i++) { - forlist(&factions) { - Faction * fac = (Faction *) elem; - if(fac->IsNPC()) continue; - if(fac->magepower.rank == i) { - f.PutStr( AString("Rank ") + i + ": " + fac->magepower.Value()); - } - } - } -/* - f.PutStr(""); - f.PutStr("A count of Guarded Cities:"); - f.PutStr(""); - for(int i=1; i<18; i++) { //including guards - forlist(&factions) { - Faction * fac = (Faction *) elem; - if(fac->num == 1 && i == 1) f.PutStr( AString("Guardsmen: ") + fac->guardedcities.Value()); - if(fac->IsNPC()) continue; - if(fac->guardedcities.rank == i) { - f.PutStr( AString("Rank ") + i + ": " + fac->guardedcities.Value()); - } - } - } -*/ - f.PutStr(""); - - f.PutStr(""); -// f.PutStr(AString("World Population: ") + population); - - f.Close(); - } -} - -void Game::WriteReports() -{ - Areport f; - - MakeFactionReportLists(); - CountAllMages(); - if(Globals->APPRENTICES_EXIST) - CountAllApprentices(); - if (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) - CountAllQuarterMasters(); - if (Globals->TACTICS_NEEDS_WAR) - CountAllTacticians(); - CountAllPower(); //counts men as well - - - forlist(&factions) { - Faction *fac = (Faction *) elem; - AString str = "report."; - str = str + fac->num; - if(!fac->IsNPC() || - ((((month == 0) && (year == 1)) || Globals->GM_REPORT) && - (fac->num == 1))) { - int i = f.OpenByName(str); - if(i != -1) { - fac->WriteReport(&f, this); - f.Close(); - } - } - Adot(); - } -} - -// LLS - write order templates for factions -void Game::WriteTemplates() -{ - Areport f; - - forlist(&factions) { - Faction *fac = (Faction *) elem; - AString str = "template."; - str = str + fac->num; - - if(!fac->IsNPC()) { - int i = f.OpenByName(str); - if (i != -1) { - fac->WriteTemplate(&f, this); - f.Close(); - } - fac->present_regions.DeleteAll(); - } - Adot(); - } -} - - -void Game::DeleteDeadFactions() -{ - forlist(&factions) { - Faction *fac = (Faction *) elem; - if (!fac->IsNPC() && !fac->exists) { - factions.Remove(fac); - forlist((&factions)) - ((Faction *) elem)->RemoveAttitude(fac->num); - delete fac; - } - } -} - -Faction *Game::AddFaction(int noleader, ARegion *pStart) -{ - // - // set up faction - // - Faction *temp = new Faction(factionseq); - AString x("NoAddress"); - temp->SetAddress(x); - temp->lastorders = TurnNumber(); - temp->pStartLoc = pStart; - temp->pReg = pStart; - if(pStart) temp->start = pStart->num; - temp->noStartLeader = noleader; - - if (!SetupFaction(temp)) { - delete temp; - return 0; - } - factions.Add(temp); - factionseq++; - return temp; -} - -void Game::ViewFactions() -{ - forlist((&factions)) - ((Faction *) elem)->View(); -} - -void Game::SetupUnitSeq() -{ - int max = 0; - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(u && u->num > max) max = u->num; - } - } - } - unitseq = max+1; -} - -void Game::SetupUnitNums() -{ - if(ppUnits) delete ppUnits; - - SetupUnitSeq(); - - maxppunits = unitseq+10000; - - ppUnits = new Unit *[maxppunits]; - - unsigned int i; - for(i = 0; i < maxppunits ; i++) ppUnits[i] = 0; - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - i = u->num; - if((i > 0) && (i < maxppunits)) { - if(!ppUnits[i]) - ppUnits[u->num] = u; - else { - Awrite(AString("Error: Unit number ") + i + - " multiply defined."); - if((unitseq > 0) && (unitseq < maxppunits)) { - u->num = unitseq; - ppUnits[unitseq++] = u; - } - } - } else { - Awrite(AString("Error: Unit number ")+i+ - " out of range."); - if((unitseq > 0) && (unitseq < maxppunits)) { - u->num = unitseq; - ppUnits[unitseq++] = u; - } - } - } - } - } -} - -Unit *Game::GetNewUnit(Faction *fac, int an) -{ - unsigned int i; - for(i = 1; i < unitseq; i++) { - if(!ppUnits[i]) { - Unit *pUnit = new Unit(i, fac, an); - ppUnits[i] = pUnit; - return(pUnit); - } - } - - Unit *pUnit = new Unit(unitseq, fac, an); - ppUnits[unitseq] = pUnit; - unitseq++; - if(unitseq >= maxppunits) { - Unit **temp = new Unit*[maxppunits+10000]; - memcpy(temp, ppUnits, maxppunits*sizeof(Unit *)); - maxppunits += 10000; - delete ppUnits; - ppUnits = temp; - } - - return(pUnit); -} - -Unit *Game::GetUnit(int num) -{ - if(num < 0 || (unsigned int)num >= maxppunits) return NULL; - return(ppUnits[num]); -} - -void Game::CountAllMages() -{ - forlist(&factions) { - ((Faction *) elem)->nummages = 0; - } - - { - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->type == U_MAGE) u->faction->nummages++; - } - } - } - } -} - -void Game::CountGuardedCities() -{ - forlist(&factions) { - Faction *f = (Faction *) elem; - f->guardedcities.value = 0; - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if(!r->town) continue; - if(r->town->TownType() != TOWN_CITY) continue; - int guarded = 0; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == f && u->guard == GUARD_GUARD) guarded = 1; - } - } - if(guarded) f->guardedcities.value++; - } - } - - forlist_reuse(&factions) { - Faction *f1 = (Faction *) elem; - forlist(&factions) { - Faction *f2 = (Faction *) elem; - if(f2->IsNPC()) continue; - if(f2->guardedcities.Value() > f1->guardedcities.Value()) f1->guardedcities.rank++; - if(f2->guardedcities.Value() > f1->guardedcities.maxvalue) f1->guardedcities.maxvalue = f2->guardedcities.Value(); - } - } -} - -void Game::CountAllPower() -{ - forlist(&factions) { - Faction *f = (Faction *)elem; - f->totalsilver.value = f->unclaimed; - f->itemnetworth.value = 0; - f->skillnetworth.value = 0; - f->totalnetworth.value = 0; - f->nummen.value = 0; - f->magepower.value = 0; - } - forlist_reuse(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(r->zloc == 0 && u->faction->IsNPC()) continue; //don't count nexus guards (XXXX) - if(u==o->GetOwner() && o->incomplete<1) { - if (ObjectDefs[o->type].item == I_WOOD_OR_STONE) u->faction->totalnetworth.value += ObjectDefs[o->type].cost * ItemDefs[I_WOOD].baseprice * 3 / 2; - else u->faction->totalnetworth.value += ObjectDefs[o->type].cost * ItemDefs[ObjectDefs[o->type].item].baseprice * 3 / 2; - } - forlist(&u->items) { - Item *item = (Item *)elem; - if(item->type == I_SILVER) u->faction->totalsilver.value += item->num; - else if(!(ItemDefs[item->type].type & IT_MAN) && !(ItemDefs[item->type].type & IT_MAGIC)) u->faction->itemnetworth.value += 3 * ItemDefs[item->type].baseprice * item->num / 2; - else if (ItemDefs[item->type].type & IT_MAN) { - u->faction->totalnetworth.value += ItemDefs[item->type].baseprice * item->num; - u->faction->nummen.value += item->num; - } else u->faction->itemnetworth.value += ItemDefs[item->type].baseprice * item->num; //eg magic items - } - } - } - } - CountSkillPower(); - - forlist_reuse(&factions) { - Faction *f = (Faction *)elem; - f->totalnetworth.value += f->totalsilver.Value() + f->itemnetworth.Value() + f->skillnetworth.Value(); - f->magepower.value = f->magepower.Value()/30; - } - - forlist_reuse(&factions) { - Faction *f1 = (Faction *) elem; - forlist(&factions) { - Faction *f2 = (Faction *) elem; - if(f2->IsNPC()) continue; - //total silver - if(f2->totalsilver.Value() > f1->totalsilver.Value()) f1->totalsilver.rank++; - if(f2->totalsilver.Value() > f1->totalsilver.maxvalue) f1->totalsilver.maxvalue = f2->totalsilver.Value(); - //items - if(f2->itemnetworth.Value() > f1->itemnetworth.Value()) f1->itemnetworth.rank++; - if(f2->itemnetworth.Value() > f1->itemnetworth.maxvalue) f1->itemnetworth.maxvalue = f2->itemnetworth.Value(); - //skill - if(f2->skillnetworth.Value() > f1->skillnetworth.Value()) f1->skillnetworth.rank++; - if(f2->skillnetworth.Value() > f1->skillnetworth.maxvalue) f1->skillnetworth.maxvalue = f2->skillnetworth.Value(); - //total NW - if(f2->totalnetworth.Value() > f1->totalnetworth.Value()) f1->totalnetworth.rank++; - if(f2->totalnetworth.Value() > f1->totalnetworth.maxvalue) f1->totalnetworth.maxvalue = f2->totalnetworth.Value(); - //nummen - if(f2->nummen.Value() > f1->nummen.Value()) f1->nummen.rank++; - if(f2->nummen.Value() > f1->nummen.maxvalue) f1->nummen.maxvalue = f2->nummen.Value(); - //magepower - if(f2->magepower.Value() > f1->magepower.Value()) f1->magepower.rank++; - if(f2->magepower.Value() > f1->magepower.maxvalue) f1->magepower.maxvalue = f2->magepower.Value(); - } - } - -} - -void Game::CountSkillPower() -{ - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - forlist(&u->skills) { - Skill *sk = (Skill *)elem; - u->faction->skillnetworth.value += SkillDefs[sk->type].cost * (sk->days + sk->experience) / 30; - if(u->type == U_MAGE /*&& (SkillDefs[sk->type].flags & SkillType::MAGIC)*/) u->faction->magepower.value += sk->days + sk->experience; - } - } - } - } -} - -void Game::CountAllQuarterMasters() -{ - forlist(&factions) { - ((Faction *) elem)->numqms = 0; - } - - { - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->GetRealSkill(S_QUARTERMASTER)) - u->faction->numqms++; - } - } - } - } -} - -// This, along with counting apprentices, mages and quartermasters, -// should all be in the one function (CountSpecialists?) -void Game::CountAllTacticians() -{ - forlist(&factions) { - ((Faction *) elem)->numtacts = 0; - } - - { - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->GetRealSkill(S_TACTICS) == 5) - u->faction->numtacts++; - } - } - } - } -} - -// LLS -void Game::UnitFactionMap() -{ - Aoutfile f; - unsigned int i; - Unit *u; - - Awrite("Opening units.txt"); - if (f.OpenByName("units.txt") == -1) { - Awrite("Couldn't open file!"); - } else { - Awrite(AString("Writing ") + unitseq + " units"); - for (i = 1; i < unitseq; i++) { - u = GetUnit(i); - if (!u) { - Awrite("doesn't exist"); - } else { - Awrite(AString(i) + ":" + u->faction->num); - f.PutStr(AString(i) + ":" + u->faction->num); - } - } - } - f.Close(); -} - - -//The following function added by Creative PBM February 2000 -void Game::RemoveInactiveFactions() -{ - if(Globals->MAX_INACTIVE_TURNS == -1) return; - - int cturn; - cturn = TurnNumber(); - forlist(&factions) { - Faction *fac = (Faction *) elem; - if ((cturn - fac->lastorders) >= Globals->MAX_INACTIVE_TURNS && - !fac->IsNPC()) { - fac->quit = QUIT_BY_GM; - } - } -} - -void Game::CountAllApprentices() -{ - if(!Globals->APPRENTICES_EXIST) return; - - forlist(&factions) { - ((Faction *)elem)->numapprentices = 0; - } - { - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(u->type == U_APPRENTICE) - u->faction->numapprentices++; - } - } - } - } -} - -int Game::CountQuarterMasters(Faction *pFac) -{ - int i = 0; - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(u->faction == pFac && u->GetRealSkill(S_QUARTERMASTER)) i++; - } - } - } - return i; -} - -int Game::CountTacticians(Faction *pFac) -{ - int i = 0; - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(u->faction == pFac && u->GetRealSkill(S_TACTICS) == 5) i++; - } - } - } - return i; -} - -int Game::CountApprentices(Faction *pFac) -{ - int i = 0; - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(u->faction == pFac && u->type == U_APPRENTICE) i++; - } - } - } - return i; -} - -int Game::AllowedMages(Faction *pFac) -{ - int points = pFac->type[F_MAGIC]; - - if (points < 0) points = 0; - if (points > allowedMagesSize - 1) points = allowedMagesSize - 1; - - return allowedMages[points]; -} - -int Game::AllowedQuarterMasters(Faction *pFac) -{ - int points = pFac->type[F_TRADE]; - - if (points < 0) points = 0; - if (points > allowedQuartermastersSize - 1) - points = allowedQuartermastersSize - 1; - - return allowedQuartermasters[points]; -} - -int Game::AllowedTacticians(Faction *pFac) -{ - int points = pFac->type[F_WAR]; - - if (points < 0) points = 0; - if (points > allowedTacticiansSize - 1) - points = allowedTacticiansSize - 1; - - return allowedTacticians[points]; -} - -int Game::AllowedApprentices(Faction *pFac) -{ - int points = pFac->type[F_MAGIC]; - - if (points < 0) points = 0; - if (points > allowedApprenticesSize - 1) - points = allowedApprenticesSize - 1; - - return allowedApprentices[points]; -} - -int Game::AllowedTaxes(Faction *pFac) -{ - int points = pFac->type[F_WAR]; - - if (points < 0) points = 0; - if (points > allowedTaxesSize - 1) points = allowedTaxesSize - 1; - - return allowedTaxes[points]; -} - -int Game::AllowedTrades(Faction *pFac) -{ - int points = pFac->type[F_TRADE]; - - if (points < 0) points = 0; - if (points > allowedTradesSize - 1) points = allowedTradesSize - 1; - - return allowedTrades[points]; -} - -int Game::UpgradeMajorVersion(int savedVersion) -{ - return 0; -} - -int Game::UpgradeMinorVersion(int savedVersion) -{ - return 1; -} - -int Game::UpgradePatchLevel(int savedVersion) -{ - return 1; -} - -void Game::MidProcessUnitExtra(ARegion *r, Unit *u) -{ - if(Globals->CHECK_MONSTER_CONTROL_MID_TURN) MonsterCheck(r, u); -} - -void Game::PostProcessUnitExtra(ARegion *r, Unit *u) -{ - if(!Globals->CHECK_MONSTER_CONTROL_MID_TURN) MonsterCheck(r, u); - //passive skills - if(Globals->REAL_EXPERIENCE) { - int level = u->GetRealSkill(S_STEALTH); - if(level) u->Experience(S_STEALTH,level); //can otherwise only be gained by assassinating or study - - level = u->GetSkill(S_OBSERVATION); - if(level) u->Experience(S_OBSERVATION,level); //can otherwise only be gained by killing would-be-assassins or study - - level = u->GetSkill(S_TRUE_SEEING); - if(level) u->Experience(S_TRUE_SEEING,level); //can otherwise only be gained by study - - level = u->GetSkill(S_SECSIGHT); - if(level) u->Experience(S_SECSIGHT,level); //can otherwise only be gained by study - - level = u->GetSkill(S_TRADING); - if(level && u->numtraded) { -// u->Experience(S_TRADING,level); //can otherwise only be gained by study - int exper = 1; //1 experience for trading anything at all - int value = 200; - while(u->numtraded > value) { - exper++; - value *= 2; - } - //ie 1 for trading $100, 2 for $200, 4 for $800, 6 for $3200, 8 for $12800 etc. - u->Experience(S_TRADING,exper); - } - - level = u->GetSkill(S_MERCHANTRY); - if(level && u->nummerchanted) { -// u->Experience(S_MERCHANTRY,level); //can otherwise only be gained by study - int exper = 1; //1 experience for trading anything at all - int value = 100; - while(u->nummerchanted > value) { - exper++; - value *= 2; - } - //ie 1 for trading $100, 2 for $200, 4 for $800, 6 for $3200, 8 for $12800 etc. - u->Experience(S_MERCHANTRY,exper); - } - - - level = u->GetSkill(S_ARCADIA_QUARTERMASTERY); - if(level && u->numquartermastered) { -// u->Experience(S_ARCADIA_QUARTERMASTERY,level); //can otherwise only be gained by study - int exper = 3; //3 experience for trading anything at all - int value = 400; - while(u->numquartermastered > value && exper < 10) { //this one can potentially be abused, so cap at 10. - exper++; - value *= 2; - } - //ie 4 for sending $400, 6 for $1600, 8 for $6400, 10 for $25600. - u->Experience(S_ARCADIA_QUARTERMASTERY,exper); - } - } -} - -void Game::MonsterCheck(ARegion *r, Unit *u) -{ - AString tmp; - int skill; -// int linked = 0; -// map< int, int > chances; //what the hell is this? - - if (u->type != U_WMON) { - - forlist (&u->items) { - Item *i = (Item *) elem; - if(!i->num) continue; - if (!ItemDefs[i->type].escape) continue; - - // Okay, check flat loss. - if (ItemDefs[i->type].escape & ItemType::LOSS_CHANCE) { - int losses = (i->num + - getrandom(ItemDefs[i->type].esc_val)) / - ItemDefs[i->type].esc_val; - if(losses > 0) { //to prevent getting '0 liches decay' messages. - u->items.SetNum(i->type,i->num - losses); - AString temp = ItemString(i->type, losses) + " decay"; - if(losses == 1) temp += "s"; - temp += " into nothingness"; - u->Event(temp); - } - } else if (ItemDefs[i->type].escape & ItemType::HAS_SKILL) { - tmp = ItemDefs[i->type].esc_skill; - skill = LookupSkill(&tmp); - if (u->GetRealSkill(skill) < ItemDefs[i->type].esc_val) { //real skill so that units can't disable their skill - if(Globals->WANDERING_MONSTERS_EXIST) { - Faction *mfac = GetFaction(&factions, monfaction); - Unit *mon = GetNewUnit(mfac, 0); - MonType *mp = FindMonster(ItemDefs[i->type].abr, - (ItemDefs[i->type].type & IT_ILLUSION)); - mon->MakeWMon(mp->name, i->type, i->num); - mon->MoveUnit(r->GetDummy()); - // This will be zero unless these are set. (0 means - // full spoils) - mon->free = Globals->MONSTER_NO_SPOILS + - Globals->MONSTER_SPOILS_RECOVERY; - } - u->Event(AString("Loses control of ") + - ItemString(i->type, i->num) + "."); - u->items.SetNum(i->type, 0); - } - } else { - // ESC_LEV_SQUARED or ESC_LEV_QUAD - tmp = ItemDefs[i->type].esc_skill; - skill = LookupSkill(&tmp); - int level = u->GetRealSkill(skill); - int chance; - - if (!level) level = 1; //BS mod to make controlled releases for farming or missiles harder. - - int top = i->num * i->num; - int bottom = 0; - if (ItemDefs[i->type].escape & ItemType::ESC_LEV_SQUARE) - bottom = level * level; - else if (ItemDefs[i->type].escape & ItemType::ESC_LEV_QUAD) - bottom = level * level * level * level; - else - bottom = 1; - bottom = bottom * ItemDefs[i->type].esc_val; - chance = (top * 10000)/bottom; - - -/* if (ItemDefs[i->type].escape & ItemType::LOSE_LINKED) { //disabled in Arcadia - if (chance > chances[ItemDefs[i->type].type]) - chances[ItemDefs[i->type].type] = chance; - linked = 1; - } else*/ if (chance > getrandom(10000)) { - if(Globals->WANDERING_MONSTERS_EXIST) { - Faction *mfac = GetFaction(&factions, monfaction); - Unit *mon = GetNewUnit(mfac, 0); - MonType *mp = FindMonster(ItemDefs[i->type].abr, - (ItemDefs[i->type].type & IT_ILLUSION)); - mon->MakeWMon(mp->name, i->type, i->num); - mon->MoveUnit(r->GetDummy()); - // This will be zero unless these are set. (0 means - // full spoils) - mon->free = Globals->MONSTER_NO_SPOILS + - Globals->MONSTER_SPOILS_RECOVERY; - } - u->Event(AString("Loses control of ") + - ItemString(i->type, i->num) + "."); - u->items.SetNum(i->type, 0); - } - } - } - -/* if (linked) { - map < int, int >::iterator i; - for (i = chances.begin(); i != chances.end(); i++) { - // walk the chances list and for each chance, see if - // escape happens and if escape happens then walk all items - // and everything that is that type, get rid of it. - if ((*i).second < getrandom(10000)) continue; - forlist (&u->items) { - Item *it = (Item *)elem; - if (ItemDefs[it->type].type == (*i).first) { - if(Globals->WANDERING_MONSTERS_EXIST) { - Faction *mfac = GetFaction(&factions, monfaction); - Unit *mon = GetNewUnit(mfac, 0); - MonType *mp = FindMonster(ItemDefs[it->type].abr, - (ItemDefs[it->type].type & IT_ILLUSION)); - mon->MakeWMon(mp->name, it->type, it->num); - mon->MoveUnit(r->GetDummy()); - // This will be zero unless these are set. (0 means - // full spoils) - mon->free = Globals->MONSTER_NO_SPOILS + - Globals->MONSTER_SPOILS_RECOVERY; - } - u->Event(AString("Loses control of ") + - ItemString(it->type, it->num) + "."); - u->items.SetNum(it->type, 0); - } - } - } - }*/ - } -} - -void Game::CheckUnitMaintenance(int consume) -{ - CheckUnitMaintenanceItem(I_FOOD, Globals->UPKEEP_FOOD_VALUE, consume); - CheckUnitMaintenanceItem(I_GRAIN, Globals->UPKEEP_FOOD_VALUE, consume); - CheckUnitMaintenanceItem(I_LIVESTOCK, Globals->UPKEEP_FOOD_VALUE, consume); - CheckUnitMaintenanceItem(I_FISH, Globals->UPKEEP_FOOD_VALUE, consume); -} - -void Game::CheckFactionMaintenance(int con) -{ - CheckFactionMaintenanceItem(I_FOOD, Globals->UPKEEP_FOOD_VALUE, con); - CheckFactionMaintenanceItem(I_GRAIN, Globals->UPKEEP_FOOD_VALUE, con); - CheckFactionMaintenanceItem(I_LIVESTOCK, Globals->UPKEEP_FOOD_VALUE, con); - CheckFactionMaintenanceItem(I_FISH, Globals->UPKEEP_FOOD_VALUE, con); -} - -void Game::CheckAllyMaintenance() -{ - CheckAllyMaintenanceItem(I_FOOD, Globals->UPKEEP_FOOD_VALUE); - CheckAllyMaintenanceItem(I_GRAIN, Globals->UPKEEP_FOOD_VALUE); - CheckAllyMaintenanceItem(I_LIVESTOCK, Globals->UPKEEP_FOOD_VALUE); - CheckAllyMaintenanceItem(I_FISH, Globals->UPKEEP_FOOD_VALUE); -} - -void Game::CheckUnitHunger() -{ - CheckUnitHungerItem(I_FOOD, Globals->UPKEEP_FOOD_VALUE); - CheckUnitHungerItem(I_GRAIN, Globals->UPKEEP_FOOD_VALUE); - CheckUnitHungerItem(I_LIVESTOCK, Globals->UPKEEP_FOOD_VALUE); - CheckUnitHungerItem(I_FISH, Globals->UPKEEP_FOOD_VALUE); -} - -void Game::CheckFactionHunger() -{ - CheckFactionHungerItem(I_FOOD, Globals->UPKEEP_FOOD_VALUE); - CheckFactionHungerItem(I_GRAIN, Globals->UPKEEP_FOOD_VALUE); - CheckFactionHungerItem(I_LIVESTOCK, Globals->UPKEEP_FOOD_VALUE); - CheckFactionHungerItem(I_FISH, Globals->UPKEEP_FOOD_VALUE); -} - -void Game::CheckAllyHunger() -{ - CheckAllyHungerItem(I_FOOD, Globals->UPKEEP_FOOD_VALUE); - CheckAllyHungerItem(I_GRAIN, Globals->UPKEEP_FOOD_VALUE); - CheckAllyHungerItem(I_LIVESTOCK, Globals->UPKEEP_FOOD_VALUE); - CheckAllyHungerItem(I_FISH, Globals->UPKEEP_FOOD_VALUE); -} - -char Game::GetRChar(ARegion *r) -{ - int t; - - if (!r) - return '#'; - t = r->type; - if (t < 0 || t > R_NUM) return '?'; - char c = TerrainDefs[r->type].marker; - if (r->town) { - c = (c - 'a') + 'A'; - } - return c; -} - -void Game::CreateNPCFactions() -{ - Faction *f; - AString *temp; - if(Globals->CITY_MONSTERS_EXIST) { - f = new Faction(factionseq++); - guardfaction = f->num; - temp = new AString("The Guardsmen"); - if(Globals->ARCADIA_MAGIC) { - *temp = "Human Guardsmen"; - f->ethnicity = RA_HUMAN; - } - f->SetName(temp); - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - if(Globals->ARCADIA_MAGIC) { - f = new Faction(factionseq++); - elfguardfaction = f->num; - temp = new AString("Elvish Guardsmen"); - f->SetName(temp); - f->ethnicity = RA_ELF; - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - f = new Faction(factionseq++); - dwarfguardfaction = f->num; - temp = new AString("Dwarven Guardsmen"); - f->ethnicity = RA_DWARF; - f->SetName(temp); - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - f = new Faction(factionseq++); - independentguardfaction = f->num; - temp = new AString("Independent Guardsmen"); - f->ethnicity = RA_OTHER; - f->SetName(temp); - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - } else { - elfguardfaction = 0; - dwarfguardfaction = 0; - independentguardfaction = 0; - } - } else { - guardfaction = 0; - elfguardfaction = 0; - dwarfguardfaction = 0; - independentguardfaction = 0; - } - // Only create the monster faction if wandering monsters or lair - // monsters exist. - if(Globals->LAIR_MONSTERS_EXIST || Globals->WANDERING_MONSTERS_EXIST) { - f = new Faction(factionseq++); - monfaction = f->num; - temp = new AString("Creatures"); - f->SetName(temp); - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - } else - monfaction = 0; - // Create the ghost faction if ARCADIA_MAGIC enabled - if(Globals->ARCADIA_MAGIC) { - f = new Faction(factionseq++); - ghostfaction = f->num; - temp = new AString("Shades of the Dead"); - f->SetName(temp); - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - f = new Faction(factionseq++); - peasantfaction = f->num; - temp = new AString("Peasantfolk"); - f->SetName(temp); - f->SetNPC(); - f->lastorders = 0; - factions.Add(f); - } else{ - ghostfaction = 0; - peasantfaction = 0; - } -} - -void Game::CreateFortMon(ARegion *pReg, Object *o) -{ - //no regional guards in towns, else their behaviour will get reset to town guards later :( - if(pReg->town) return; - -//The world is set up by now -//However, some regions (eg nexus) do not have a race assigned. If leaders are disabled that can cause this to crash. So: - int i=0; - while(pReg->race < 0) { //we're desperate, take the first enabled race ;) - if((ItemDefs[i].type & IT_MAN) && !(ItemDefs[i].flags & ItemType::DISABLED)) { - pReg->race = i; - } - i++; - } - int size = ObjectDefs[o->type].protect; - if(size < 10) return; - int skilllevel = 1; - if(size > 40) skilllevel++; - if(size > 160) skilllevel++; - int num = size / (5*skilllevel); - num *= 5; //ie only have guard units in multiples of 5 - - int fac = guardfaction; - if(Globals->ARCADIA_MAGIC) { - ManType *mt = FindRace(ItemDefs[pReg->race].abr); - switch(mt->ethnicity) { - case RA_ELF: - fac = elfguardfaction; - break; - case RA_DWARF: - fac = dwarfguardfaction; - break; - case RA_OTHER: - fac = independentguardfaction; - break; - default: - fac = guardfaction; - break; - } - } - - Faction *pFac = GetFaction(&factions, fac); - - - if(skilllevel > 1) { - //one front unit - AString *s = new AString("Regional Guards"); - - Unit *u = MakeManUnit(pFac, pReg, num, skilllevel, 1, - 0, 0); - u->SetMoney(num * Globals->GUARD_MONEY / 2); - u->SetName(s); - u->type = U_GUARD; - u->guard = GUARD_GUARD; - u->SetSkill(S_OBSERVATION, skilllevel); - u->SetFlag(FLAG_HOLDING,1); - u->reveal = REVEAL_FACTION; - u->MoveUnit(o); - //one behind unit - AString *s2 = new AString("Regional Guards"); - - Unit *u2 = MakeManUnit(pFac, pReg, num, skilllevel, 1, - 0, 1); - u2->SetMoney(num * Globals->GUARD_MONEY / 2); - u2->SetName(s2); - u2->type = U_GUARD; - u2->guard = GUARD_GUARD; - u2->SetSkill(S_OBSERVATION, skilllevel); - u2->SetFlag(FLAG_HOLDING,1); - u2->reveal = REVEAL_FACTION; - u2->MoveUnit(o); - } - if(skilllevel != 2) { - //one unit of best type - int behind = SkillMax("XBOW", pReg->race); - if (SkillMax("LBOW", pReg->race) > behind) behind = SkillMax("LBOW", pReg->race); - int front = SkillMax("COMB", pReg->race); - if (SkillMax("RIDI", pReg->race) > front && (TerrainDefs[pReg->type].flags & TerrainType::RIDINGMOUNTS) && !(TerrainDefs[pReg->type].flags & TerrainType::RIDINGLIMITED)) - front = SkillMax("RIDI", pReg->race); - if(behind > front) behind = 1; - else behind = 0; - - AString *s = new AString("Regional Guards"); - - Unit *u = MakeManUnit(pFac, pReg, num, skilllevel, 1, - 0, behind); - u->SetMoney(num * Globals->GUARD_MONEY / 2); - u->SetName(s); - u->type = U_GUARD; - u->guard = GUARD_GUARD; - u->SetSkill(S_OBSERVATION, skilllevel); - u->SetFlag(FLAG_HOLDING,1); - u->reveal = REVEAL_FACTION; - u->MoveUnit(o); - } -} - -void Game::CreateCityMon(ARegion *pReg, int percent, int needguard) -#define GUARDFRONT 1 -#define GUARDBEHIND 2 -#define GUARDMAGE 4 -{ -//The world is set up by now -//However, some regions (eg nexus) do not have a race assigned. If leaders are disabled that can cause this to crash. So: - int i=0; - while(pReg->race < 0) { //we're desperate, take the first enabled race ;) - if((ItemDefs[i].type & IT_MAN) && !(ItemDefs[i].flags & ItemType::DISABLED)) { - pReg->race = i; - } - i++; - } - int skilllevel; - int AC = 0; - int IV = 0; - int num; - if(pReg->type == R_NEXUS || pReg->IsStartingCity()) { - skilllevel = TOWN_CITY + 1; - if(Globals->SAFE_START_CITIES || (pReg->type == R_NEXUS)) - IV = 1; - AC = 1; - num = Globals->AMT_START_CITY_GUARDS; - } else { - skilllevel = pReg->town->TownType() + 1; - num = Globals->CITY_GUARD * skilllevel; - if(!Globals->GUARD_DEPENDS_ON_TAX || !pReg->money) num = Globals->CITY_GUARD * skilllevel; - else num = pReg->money * Globals->CITY_GUARD / 5000; - } - if(Globals->GUARD_DEPENDS_ON_TAX && percent < 20) { //why less than 20? Need to excuse 100% for the initial start ... - num = pReg->untaxed / (20 * Globals->GUARD_MONEY); - } else { - num = num * percent / 100; - } - int fac = guardfaction; - if(Globals->ARCADIA_MAGIC) { - ManType *mt = FindRace(ItemDefs[pReg->race].abr); - switch(mt->ethnicity) { - case RA_ELF: - fac = elfguardfaction; - break; - case RA_DWARF: - fac = dwarfguardfaction; - break; - case RA_OTHER: - fac = independentguardfaction; - break; - default: - fac = guardfaction; - break; - } - } - Faction *pFac = GetFaction(&factions, fac); - Unit *u = 0; - Unit *u2 = 0; - AString *s = new AString("City Guard"); - - /* - AString temp = TerrainDefs[pReg->type].name; - temp += AString(" (") + pReg->xloc + "," + pReg->yloc; - temp += ")"; - temp += AString(" in ") + *pReg->name; - Awrite(temp); - */ - if((Globals->LEADERS_EXIST)) { - /* standard Leader-type guards */ - u = GetNewUnit(pFac); - u->SetMen(I_LEADERS,num); - u->items.SetNum(I_SWORD,num); - if (IV) u->items.SetNum(I_AMULETOFI,num); - u->SetMoney(num * Globals->GUARD_MONEY); - u->SetSkill(S_COMBAT,skilllevel); - u->SetName(s); - u->type = U_GUARD; - u->guard = GUARD_GUARD; - } else { - /* non-leader guards */ - int n = 3 * num / 4; - int plate = 0; - if((AC) && (Globals->START_CITY_GUARDS_PLATE)) plate = 1; - if(needguard%(2*GUARDFRONT)/GUARDFRONT) { - u = MakeManUnit(pFac, pReg, n, skilllevel, 1, - plate, 0); - if (IV) u->items.SetNum(I_AMULETOFI,num); - u->SetMoney(num * Globals->GUARD_MONEY / 2); - u->SetName(s); - u->type = U_GUARD; - u->guard = GUARD_GUARD; - } - if(needguard%(2*GUARDBEHIND)/GUARDBEHIND) { - u2 = MakeManUnit(pFac, pReg, n, skilllevel, 1, - plate, 1); - if (IV) u2->items.SetNum(I_AMULETOFI,num); - u2->SetMoney(num * Globals->GUARD_MONEY / 2); - AString *un = new AString("City Guard"); - u2->SetName(un); - u2->type = U_GUARD; - u2->guard = GUARD_GUARD; - } - } - if(u) { - u->SetSkill(S_OBSERVATION, skilllevel); - u->SetFlag(FLAG_HOLDING,1); - u->reveal = REVEAL_FACTION; - u->MoveUnit(pReg->GetDummy()); - } - if(u2) { - u2->SetFlag(FLAG_HOLDING,1); - u2->reveal = REVEAL_FACTION; - u2->MoveUnit(pReg->GetDummy()); - } - if((pReg->type == R_NEXUS || (Globals->START_CITY_MAGES + skilllevel - 3) > 0) && (needguard%(2*GUARDMAGE)/GUARDMAGE)) { - u = GetNewUnit(pFac); - s = new AString("City Mage"); - u->SetName(s); - u->type = U_GUARDMAGE; - if((Globals->LEADERS_EXIST)) { - u->SetMen(I_LEADERS,1); - if(IV) u->items.SetNum(I_AMULETOFI,1); - u->SetMoney(Globals->GUARD_MONEY); - if(!Globals->ARCADIA_MAGIC) u->SetSkill(S_FORCE,Globals->START_CITY_MAGES); - else u->SetSkill(S_BASE_WINDKEY,Globals->START_CITY_MAGES+skilllevel-3); - u->SetSkill(S_FIRE,Globals->START_CITY_MAGES+skilllevel-3); - if(Globals->START_CITY_TACTICS && !(SkillDefs[S_TACTICS].flags & SkillType::DISABLED)) - u->SetSkill(S_TACTICS, Globals->START_CITY_TACTICS); - u->combat = S_FIRE; - u->SetFlag(FLAG_BEHIND, 1); - u->SetFlag(FLAG_HOLDING, 1); - u->reveal = REVEAL_FACTION; - u->MoveUnit(pReg->GetDummy()); - } else { - u->SetMen(pReg->race,1); - u->SetMoney(Globals->GUARD_MONEY); - if(!Globals->ARCADIA_MAGIC) u->SetSkill(S_FORCE,Globals->START_CITY_MAGES); - else u->SetSkill(S_BASE_WINDKEY,Globals->START_CITY_MAGES+skilllevel-3); - u->SetSkill(S_FIRE,Globals->START_CITY_MAGES+skilllevel-3); - u->combat = S_FIRE; - u->SetFlag(FLAG_BEHIND, 1); - u->SetFlag(FLAG_HOLDING, 1); - u->reveal = REVEAL_FACTION; - u->MoveUnit(pReg->GetDummy()); - } - } -} - -void Game::AdjustCityMons(ARegion *r) -{ -/*#define GUARDFRONT 1 -#define GUARDBEHIND 2 -#define GUARDMAGE 4*/ - int needguard = GUARDFRONT + GUARDBEHIND + GUARDMAGE; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->type == U_GUARD || u->type == U_GUARDMAGE) { - AdjustCityMon(r, u); - /* Don't create new city guards if we have some */ - if(u->type == U_GUARDMAGE) needguard -= GUARDMAGE; - else if(u->GetFlag(FLAG_BEHIND)) needguard -= GUARDBEHIND; - else needguard -= GUARDFRONT; - } - if(u->guard == GUARD_GUARD) needguard = 0; //ie if someone else is guarding, no guards needed. This could subsequently go negative ... - } - } - - if ((needguard > 0) && (getrandom(100) < Globals->GUARD_REGEN) && r->untaxed > getrandom(r->money)) { //less chance if being taxed. - if(!Globals->GUARD_DEPENDS_ON_TAX || r->untaxed >= 20*Globals->GUARD_MONEY) CreateCityMon(r, 10, needguard); - } -} - -void Game::AdjustCityMon(ARegion *r, Unit *u) -{ - int towntype; - if(r->town) towntype = r->town->TownType(); - else towntype = TOWN_CITY; //nexus -// int AC = 0; - int men; -// int IV = 0; - int mantype; - int maxmen; - int weapon = -1; - int maxweapon = 0; - int armor = -1; - int maxarmor = 0; - int mount = -1; - int maxmount = 0; - for(int i=0; iitems.GetNum(i); - if(num == 0) continue; - if(ItemDefs[i].type & IT_MAN) mantype = i; - if((ItemDefs[i].type & IT_WEAPON) - && (num > maxweapon)) { - weapon = i; - maxweapon = num; - } - if((ItemDefs[i].type & IT_ARMOR) - && (num > maxarmor)) { - armor = i; - maxarmor = num; - } - if((ItemDefs[i].type & IT_MOUNT) - && (num > maxmount)) { - mount = i; - maxmount = num; - } - } - - int skill = S_COMBAT; //put in a mod for riding races in riding terrain - - if (weapon != -1) { - WeaponType *wp = FindWeapon(ItemDefs[weapon].abr); - if(FindSkill(wp->baseSkill) == FindSkill("XBOW")) skill = S_CROSSBOW; - if(FindSkill(wp->baseSkill) == FindSkill("LBOW")) skill = S_LONGBOW; - } else weapon = I_SWORD; - - if (mount != -1) { - if(skill == S_COMBAT && (u->GetSkillKnowledgeMax(S_RIDING) > u->GetSkillKnowledgeMax(S_COMBAT)) && (TerrainDefs[r->type].flags & TerrainType::RIDINGMOUNTS) && !(TerrainDefs[r->type].flags & TerrainType::RIDINGLIMITED)) { - skill = S_RIDING; - } else mount = -1; - } - - if(u->type == U_GUARDMAGE) { - men = 1; - } else { - if(!Globals->GUARD_DEPENDS_ON_TAX || !r->money) maxmen = Globals->CITY_GUARD * (towntype+1); - else maxmen = r->money * Globals->CITY_GUARD / 5000; - if(!Globals->LEADERS_EXIST) maxmen = 3 * maxmen / 4; - if(!Globals->GUARD_DEPENDS_ON_TAX) men = u->GetMen() + (maxmen/10); - else men = u->GetMen() + r->untaxed / (40 * Globals->GUARD_MONEY); //one-quarter the Nylandor rate per unit! - if(men > maxmen) men = maxmen; - } - - u->SetMen(mantype,men); -// if (IV) u->items.SetNum(I_AMULETOFI,men); - - if(u->type == U_GUARDMAGE) { - if(Globals->START_CITY_TACTICS && !(SkillDefs[S_TACTICS].flags & SkillType::DISABLED)) - u->SetSkill(S_TACTICS, Globals->START_CITY_TACTICS); - if(!Globals->ARCADIA_MAGIC) u->SetSkill(S_FORCE,Globals->START_CITY_MAGES); - else u->SetSkill(S_BASE_WINDKEY,Globals->START_CITY_MAGES+towntype-2); - if(Globals->ARCADIA_MAGIC && u->IsASpeciality(S_LIGHT) && !u->IsASpeciality(S_FIRE) ) { - u->SetSkill(S_LIGHT, Globals->START_CITY_MAGES+towntype-2); - u->combat = S_LIGHT; - } else { - u->SetSkill(S_FIRE, Globals->START_CITY_MAGES+towntype-2); - u->combat = S_FIRE; - } - u->SetSkill(S_OBSERVATION,towntype + 1); //added AFTER adjust skills, as otherwise non-leaders are limited to ONE skill :(. - u->SetSkill(S_COMBAT,towntype + 1); //added AFTER adjust skills, as otherwise non-leaders are limited to ONE skill :(. - - u->SetFlag(FLAG_BEHIND, 1); - u->reveal = REVEAL_FACTION; - u->SetMoney(Globals->GUARD_MONEY); - } else { - int money = men * Globals->GUARD_MONEY; - u->SetMoney(money); - u->SetSkill(skill, towntype + 1); - u->AdjustSkills(1); - u->SetSkill(S_OBSERVATION,towntype); //added AFTER adjust skills, as otherwise non-leaders are limited to ONE skill :(. Note the mage has +1 obse compared to normal guards. This set so that the obse should never become a unit's default skill (fingers crossed ... maybe still in cities). - u->items.SetNum(weapon,men); - if(armor != -1) u->items.SetNum(armor,men); - if(mount != -1) u->items.SetNum(mount,men); - } -} - -void Game::BankInterest() -{ - int interest; - - forlist(&factions) { - Faction * fac = (Faction *) elem; - interest = (fac->bankaccount/100)*fac->type[F_TRADE]; - fac->bankaccount += interest; - fac->interest = interest; - } -} - -void Game::ProcessMigration() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - r->Migrate(); - } -} - -void Game::DevelopTowns() -{ - for(int i=0; i<5; i++) { - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if((!r) || (!r->town)) continue; - r->CheckTownIncrease(); - } - } -} - -void Game::Equilibrate() -{ - Awrite("Initialising the economy"); - for(int a=0; a<25; a++) { - Adot(); - ProcessMigration(); - forlist(®ions) { - ARegion *r = (ARegion *) elem; - r->PostTurn(®ions); - } - } - Awrite(""); -} diff --git a/arcadia/game.h b/arcadia/game.h deleted file mode 100644 index 0afbc2132..000000000 --- a/arcadia/game.h +++ /dev/null @@ -1,702 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef GAME_CLASS -#define GAME_CLASS - -class Game; - -#include "aregion.h" -#include "alist.h" -#include "faction.h" -#include "production.h" -#include "object.h" - -#define CURRENT_ATL_VER MAKE_ATL_VER(5, 0, 0) - -class OrdersCheck -{ -public: - OrdersCheck(); - - Aoutfile *pCheckFile; - Unit dummyUnit; - Faction dummyFaction; - Order dummyOrder; - int numshows; - - void Error(const AString &error); -}; - -class WorldEvent : public AListElem -{ -public: - WorldEvent(); - ~WorldEvent(); - - enum { - BATTLE, - CITY_CONQUEST, - ARMY, - CONVERSION, - HERO_DEATH, - HERO_DISMISSED, - HERO_HOPE, - }; - - int type; - int reportdelay; - int age; - int fact1; - int fact2; - Location *place; - - AString *Text(); -}; - -/// The main game class -/** Currently this doc is here to switch on the class so that -I can see what the modify.cpp docs look like. -*/ -class Game -{ - friend class Faction; -public: - Game(); - ~Game(); - - int NewGame(); - int OpenGame(); - void DummyGame(); - void FakeGame(Faction *); - - void DefaultWorkOrder(); - - int RunGame(); - int RunStatistics(); - int EditGame(int *pSaveGame); - int SaveGame(); - int WritePlayers(); - int ReadPlayers(); - int ReadPlayersLine(AString *pToken, AString *pLine, Faction *pFac, - int newPlayer); - void WriteNewFac(Faction *pFac); - - int ViewMap(const AString &, const AString &); - // LLS - void UnitFactionMap(); - int GenRules(const AString &, const AString &, const AString &); - int DoOrdersCheck(const AString &strOrders, const AString &strCheck); - int DoOrdersCheckAll(const AString &strOrders, const AString &strCheck); - - Faction *AddFaction(int noleader=0, ARegion *pStart = NULL); - - // - // Give this particular game a chance to set up the faction. This is in - // extra.cpp. - // - int SetupFaction(Faction *pFac); - - void ViewFactions(); - - // - // Get a new unit, with its number assigned. - // - Unit *GetNewUnit(Faction *fac, int an = 0); - - // - // Setup the array of units. - // - void SetupUnitSeq(); - void SetupUnitNums(); - - // - // Get a unit by its number. - // - Unit *GetUnit(int num); - - // Handle special gm unit modification functions - Unit *ParseGMUnit(AString *tag, Faction *pFac); - - int TurnNumber(); - - // JLT - // Functions to allow enabling/disabling parts of the data tables - void ModifyTablesPerRuleset(void); - - int numcities; - -private: - // - // Game editing functions. - // - ARegion *EditGameFindRegion(); - void EditGameFindUnit(); - void EditGameCreateUnit(); - void EditGameRegion(ARegion *pReg); - void EditGameRegionObjects(ARegion *pReg); - void EditGameRegionTerrain(ARegion *pReg ); - void EditGameRegionMarkets(ARegion *pReg ); - void EditGameRegionExits(ARegion *pReg ); - ARegion * EditGameRegionNavigate(ARegion *pReg); - ARegion * EditGameRegionNavigate(ARegion *pReg, AString *dirs); - void EditGameUnit(Unit *pUnit); - void EditGameUnitItems(Unit *pUnit); - void EditGameUnitSkills(Unit *pUnit); - void EditGameUnitMove(Unit *pUnit); - void EditGameUnitDetails(Unit *pUnit); - void EditGameGlobalEffects(); - void ImportMapFile(AString *name, int level); - void ImportEthFile(AString *name, int level); - void ImportRivFile(AString *name, int level); - void ImportFortFile(AString *name, int level); - int GetMarketTradeVariance(); - void EditGameBuildingsSummary(); - void EditGameProductsSummary(); - void EditGameTradeSummary(); - void EditGameWriteoutLine(int,int,int,int); - void EditGameWriteoutLine(int,int,int,int,int,int,int,int); - - void PreProcessTurn(); - void ReadOrders(); - Faction * ReadUnknownOrders(Aorders *f); //used for checkall. - void RunOrders(); - void RunCheckAllOrders(); - void ClearOrders(Faction *); - void MakeFactionReportLists(); - void CountAllMages(); - void CountAllApprentices(); - void CountAllQuarterMasters(); - void CountAllTacticians(); - void CountGuardedCities(); - void CountAllPower(); - void CountSkillPower(); - void WriteReports(); - void ClearCombatMovementMaluses(); - // LLS - write order templates - void WriteTemplates(); - - void DeleteDeadFactions(); - - // - // Standard creation functions. - // - void CreateCityMons(); - void CreateWMons(); - void CreateLMons(); - void CreateVMons(); - Unit *MakeManUnit(Faction*, ARegion*, int, int, int, int, int); - - // - // Game-specific creation functions (see world.cpp). - // - void CreateWorld(); - void CreateNPCFactions(); - void CreateCityMon(ARegion *pReg, int percent, int needguard); - void CreateFortMon(ARegion *pReg, Object *o); - int MakeWMon(ARegion *pReg); - void MakeLMon(Object *pObj); - // Dynamic creation functions - void ResolveExits(ARegion *reg, Unit *u); - - // These are in magic.cpp: - void GenerateDragons(ARegion *r); - void GenerateVolcanic(ARegion *r); - void ModifyLabryinth(ARegion *r); - void RemoveMages(ARegion *r); - void SpecialErrors(ARegion *r); - void SpecialError(ARegion *r, AString message, Faction *dontshowtothisfac = NULL); - void SetupGuardsmenAttitudes(); - - void WriteSurfaceMap(Aoutfile *f, ARegionArray *pArr, int type); - void WriteUnderworldMap(Aoutfile *f, ARegionArray *pArr, int type); - char GetRChar(ARegion *r); - AString GetXtraMap(ARegion *, int); - - // LLS - // Functions to do upgrades to the ruleset -- should be in extras.cpp - int UpgradeMajorVersion(int savedVersion); - int UpgradeMinorVersion(int savedVersion); - int UpgradePatchLevel(int savedVersion); - - // JLT - // Functions to allow enabling/disabling parts of the data tables - void EnableSkill(int sk); // Enabled a disabled skill - void DisableSkill(int sk); // Prevents skill being studied or used - void ModifySkillDependancy(int sk, int i, char *dep, int lev); - void ModifyBaseSkills(int base, int, int = -1, int = -1, int = -1, int = -1); - void ModifySkillFlags(int sk, int flags); - void ModifySkillCost(int sk, int cost); - void ModifySkillSpecial(int sk, char *special); - void ModifySkillRange(int sk, char *range); - void ModifySkillName(int sk, char *name, char *abbr); - - void EnableItem(int it); // Enables a disabled item - void DisableItem(int it); // Prevents item being generated/produced - void ModifyItemFlags(int it, int flags); - void ModifyItemType(int it, int type); - void ModifyItemWeight(int it, int weight); - void ModifyItemName(int it, char *name, char *names, char *abr); - void ModifyItemBasePrice(int it, int price); - void ModifyItemCapacities(int it, int walk, int ride, int fly, int swim); - void ModifyItemProductionBooster(int it, int item, int bonus); - void ModifyItemHitch(int it, int item, int bonus); - void ModifyItemProductionSkill(int it, char *sk, int lev); - void ModifyItemProductionOutput(int it, int months, int count); - void ModifyItemProductionInput(int it, int i, int input, int amount); - void ModifyItemMagicSkill(int it, char *sk, int lev); - void ModifyItemMagicOutput(int it, int count); - void ModifyItemMagicInput(int it, int i, int input, int amount); - void ModifyItemEscapeSkill(int it, char *sk, int val); - - void ModifyRaceSkillLevels(char *race, int special, int def); - void ModifyRaceHits(char *race, int num); - void ModifyRaceSkills(char *race, int i, char *sk); - void ModifyRaceSkills(char *r, char *sk1, - char *sk2 = NULL, char *sk3 = NULL, char *sk4 = NULL, - char *sk5 = NULL, char *sk6 = NULL); - - void ModifyMonsterAttackLevel(char *mon, int lev); - void ModifyMonsterDefense(char *mon, int defenseType, int level); - void ModifyMonsterAttacksAndHits(char *mon, int num, int hits, int regen); - void ModifyMonsterSkills(char *mon, int tact, int stealth, int obs); - void ModifyMonsterSpecial(char *mon, char *special, int lev); - void ModifyMonsterSpoils(char *mon, int silver, int spoilType); - void ModifyMonsterThreat(char *mon, int num, int hostileChance); - - void ModifyWeaponSkills(char *weap, char *baseSkill, char *orSkill); - void ModifyWeaponFlags(char *weap, int flags); - void ModifyWeaponAttack(char *weap, int wclass, int attackType, int numAtt); - void ModifyWeaponBonuses(char *weap, int attack, int defense, int vsMount); - - void ModifyArmorFlags(char *armor, int flags); - void ModifyArmorSaveFrom(char *armor, int from); - void ModifyArmorSaveValue(char *armor, int wclass, int val); - void ModifyArmorSaveAll(char *armor, int from, int, int, int); - - void ModifyMountSkill(char *mount, char *skill); - void ModifyMountBonuses(char *mount, int min, int max, int hampered); - void ModifyMountSpecial(char *mount, char *special, int level); - - void EnableObject(int ob); // Enables a disabled object - void EnableHexside(int hex); // Enables a hexside terrain - void DisableObject(int ob); // Prevents object being built - void ModifyObjectFlags(int ob, int flags); - void ModifyObjectDecay(int ob, int maxMaint, int maxMonthDecay, int mFact); - void ModifyObjectProduction(int ob, int it); - void ModifyObjectMonster(int ob, int monster); - void ModifyObjectConstruction(int ob, int it, int num, char *sk, int lev); - void ModifyObjectManpower(int ob, int prot, int cap, int sail, int mages); - void ModifyObjectDefence(int ob, int co, int en, int sp, int we, int ri, int ra); - - void ClearTerrainRaces(int t); - void ModifyTerrainRace(int t, int i, int r); - void ModifyTerrainCoastRace(int t, int i, int r); - void ClearTerrainItems(int t); - void ModifyTerrainItems(int t, int i, int p, int c, int a); - void ModifyTerrainWMons(int t, int freq, int smon, int bigmon, int hum); - void ModifyTerrainLairChance(int t, int chance); - void ModifyTerrainLair(int t, int i, int lair); - void ModifyTerrainEconomy(int t, int pop, int wages, int econ, int move); - - void ModifyBattleItemFlags(char *item, int flags); - void ModifyBattleItemSpecial(char *item, char *special, int level); - - void ModifySpecialTargetFlags(char *special, int targetflags); - void ModifySpecialTargetObjects(char *special, int index, int obj); - void ModifySpecialTargetItems(char *special, int index, int item); - void ModifySpecialTargetEffects(char *special, int index, char *effect); - void ModifySpecialEffectFlags(char *special, int effectflags); - void ModifySpecialShields(char *special, int index, int type); - void ModifySpecialDefenseMods(char *special, int index, int type, int val); - void ModifySpecialDamage(char *special, int index, int type, int min, - int val, int flags, int cls, char *effect); - - void ModifyEffectFlags(char *effect, int flags); - void ModifyEffectAttackMod(char *effect, int val); - void ModifyEffectDefenseMod(char *effect, int index, int type, int val); - void ModifyEffectCancelEffect(char *effect, char *uneffect); - - void ModifyRangeFlags(char *range, int flags); - void ModifyRangeClass(char *range, int rclass); - void ModifyRangeMultiplier(char *range, int mult); - void ModifyRangeLevelPenalty(char *range, int pen); - - void ModifyAttribMod(char *mod, int index, int flags, char *ident, - int type, int val); - - AList factions; - AList newfactions; /* List of strings */ - AList battles; - AList worldevents; - ARegionList regions; - int factionseq; - unsigned int unitseq; - Unit **ppUnits; - unsigned int maxppunits; - int shipseq; - int year; - int month; - - enum { - GAME_STATUS_UNINIT, - GAME_STATUS_NEW, - GAME_STATUS_RUNNING, - GAME_STATUS_FINISHED, - }; - int gameStatus; - - int guardfaction; - int elfguardfaction; - int dwarfguardfaction; - int independentguardfaction; - int monfaction; - int ghostfaction; - int peasantfaction; - int doExtraInit; - - // - // Parsing functions - // - void ParseError(OrdersCheck *pCheck, Unit *pUnit, Faction *pFac, - const AString &strError); - UnitId *ParseUnit(AString *s); - int ParseDir(AString *token); - - - Faction * ParseOrders(int faction, Aorders *ordersFile, OrdersCheck *pCheck); - void ProcessOrder(int orderNum, Unit *unit, AString *order, - OrdersCheck *pCheck, int isquiet); - void ProcessFollowOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessMoveOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessAdvanceOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - Unit *ProcessFormOrder(Unit *former, AString *order, - OrdersCheck *pCheck, int isquiet); - void ProcessAddressOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessAvoidOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessGuardOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessNameOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessDescribeOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessLabelOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessBehindOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessFightAsOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessTacticsOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessGiveOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessSendOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessMasterOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessWishdrawOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessWishskillOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessWithdrawOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessDeclareOrder(Faction *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessStudyOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessTeachOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessWorkOrder(Unit *, OrdersCheck *pCheck, int isquiet); - void ProcessProduceOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessBuyOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessSellOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessAttackOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessBuildOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessSailOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessEnterOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessLeaveOrder(Unit *, OrdersCheck *pCheck, int isquiet); - void ProcessPromoteOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessEvictOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessTaxOrder(Unit *, OrdersCheck *pCheck, int isquiet); - void ProcessPillageOrder(Unit *, OrdersCheck *pCheck, int isquiet); - void ProcessConsumeOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessRevealOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessFindOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessDestroyOrder(Unit *, OrdersCheck *pCheck, int isquiet); - void ProcessQuitOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessRestartOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessAssassinateOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessStealOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessFactionOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessClaimOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessCombatOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessCommandOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessPrepareOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessWeaponOrder(Unit *u, AString *o, OrdersCheck *pCheck); - void ProcessArmorOrder(Unit *u, AString *o, OrdersCheck *pCheck); - void ProcessCastOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessEntertainOrder(Unit *, OrdersCheck *pCheck, int isquiet); - void ProcessForgetOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessReshowOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessHoldOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessNoaidOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessDisableOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessNocrossOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessTypeOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessNospoilsOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessSpoilsOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessAutoTaxOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessOptionOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessPasswordOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessExchangeOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessIdleOrder(Unit *, AString *, OrdersCheck *pCheck); - void ProcessTransportOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessDistributeOrder(Unit *, AString *, OrdersCheck *pCheck, int isquiet); - void ProcessShareOrder(Unit *, AString *, OrdersCheck *pCheck); - AString *ProcessTurnOrder(Unit *, Aorders *, OrdersCheck *pCheck, int, int &fl, FormTemplate *ft = 0); - AString *ProcessTemplateOrder(Aorders *, OrdersCheck *pCheck, AString *, Faction *fac); - AString *ProcessAllOrder(Aorders *, OrdersCheck *pCheck, AString *, Faction *fac); - void DoLabelOrders(OrdersCheck *pCheck, Unit *u, Faction *fac, int faction); - void DoLabelOrder(OrdersCheck *pCheck, Unit *u, Faction *fac, int faction, AString *unittype); - - void RemoveInactiveFactions(); - - // - // Game running functions - // - - // - // This can be called by parse functions - // - int CountMages(Faction *); - int CountApprentices(Faction *); - int CountQuarterMasters(Faction *); - int CountTacticians(Faction *); - - void WritePowers(); - - void FindDeadFactions(); - void DeleteEmptyUnits(); - void DeleteEmptyInRegion(ARegion *); - void EmptyHell(); - void DoGuard1Orders(); - void DoGiveOrders(); - void DoSendOrders(); - void RecieveSentGoods(); - void DoWithdrawOrders(); - - void DoExchangeOrders(); - void DoExchangeOrder(ARegion *, Unit *, ExchangeOrder *); - - // - // Faction limit functions. - // - // The first 4 are game specific and can be found in extra.cpp. They - // may return -1 to indicate no limit. - // - int AllowedMages(Faction *pFac); - int AllowedApprentices(Faction *pFact); - int AllowedQuarterMasters(Faction *pFact); - int AllowedTacticians(Faction *pFact); - int AllowedTaxes(Faction *pFac); - int AllowedTrades(Faction *pFac); - int TaxCheck(ARegion *pReg, Faction *pFac); - int TradeCheck(ARegion *pReg, Faction *pFac); - - // - // The DoGiveOrder returns 0 normally, or 1 if no more GIVE orders - // should be allowed - // - int DoGiveOrder(ARegion *, Unit *, GiveOrder *); - int DoSendOrder(ARegion *, Unit *, SendOrder *); - // - // The DoWithdrawOrder returns 0 normally, or 1 if no more WITHDRAW - // orders should be allowed - // - int DoWithdrawOrder(ARegion *, Unit *, WithdrawOrder *); - int DoWishdrawOrder(ARegion *, Unit *, WishdrawOrder *); - int DoWishskillOrder(ARegion *, Unit *, WishskillOrder *); - - // - // These are game specific, and can be found in extra.cpp - // - void CheckUnitMaintenance(int consume); - void CheckFactionMaintenance(int consume); - void CheckAllyMaintenance(); - - // Bank functions - void ProcessBankOrder(Unit *, AString *, OrdersCheck *, int isquiet); - void DoBankDepositOrders(); - void DoBankWithdrawOrders(); - void BankInterest(); - void DoBankOrder(ARegion *, Unit *, BankOrder *); - - // Similar to the above, but for minimum food requirements - void CheckUnitHunger(); - void CheckFactionHunger(); - void CheckAllyHunger(); - - void CheckUnitMaintenanceItem(int item, int value, int consume); - void CheckFactionMaintenanceItem(int item, int value, int consume); - void CheckAllyMaintenanceItem(int item, int value); - - // Hunger again - void CheckUnitHungerItem(int item, int value); - void CheckFactionHungerItem(int item, int value); - void CheckAllyHungerItem(int item, int value); - - void SinkLandRegions(); - void DistributeFog(); - void RechargeMages(); - - void AssessMaintenance(); - - void GrowWMons(int); - void GrowLMons(int); - void GrowVMons(); - void PostProcessUnit(ARegion *, Unit *); - void MidProcessUnit(ARegion *, Unit *); - - // - // Mid and PostProcessUnitExtra can be used to provide game-specific - // unit processing at the approrpriate times. - // - void MidProcessUnitExtra(ARegion *, Unit *); - void MidProcessTurn(); - void PostProcessUnitExtra(ARegion *, Unit *); - void PostProcessTurn(); - - // Migration effects for alternate player-driven economy - void ProcessMigration(); - - // Run setup and equilibration turns (econ-only) at start - void DevelopTowns(); - void Equilibrate(); - - // Handle escaped monster check - void MonsterCheck(ARegion *r, Unit *u); - - // - // CheckVictory is used to see if the game is over. - // - Faction *CheckVictory(AString *victoryline); - - void EndGame(Faction *pVictor, AString *victoryline); - - void RunBuyOrders(); - void DoBuy(ARegion *, Market *); - int GetBuyAmount(ARegion *, Market *); - void RunSellOrders(); - void DoSell(ARegion *, Market *); - int GetSellAmount(ARegion *, Market *); - void DoAttackOrders(); - void CheckWMonAttack(ARegion *, Unit *); - Unit *GetWMonTar(ARegion *, int, Unit *); - int CountWMonTars(ARegion *, Unit *); - void AttemptAttack(ARegion *, Unit *, Unit *, int, int=0); - void DoAutoAttacks(); - void DoAutoAttacksRegion(ARegion *); - void DoAdvanceAttack(ARegion *, Unit *); - void DoAutoAttack(ARegion *, Unit *); - void DoAdvanceAttacks(AList *); - void DoAutoAttackOn(ARegion *, Unit *); - void RemoveEmptyObjects(); - void RunEnterOrders(); - void Do1EnterOrder(ARegion *, Object *, Unit *); - void RunPromoteOrders(); - void Do1PromoteOrder(Object *, Unit *); - void Do1EvictOrder(Object *, Unit *); - void RunPillageOrders(); - int CountPillagers(ARegion *); - void ClearPillagers(ARegion *); - void RunPillageRegion(ARegion *); - void RunTaxOrders(); - void RunTaxRegion(ARegion *); - int FortTaxBonus(Object *, Unit *); - int CountTaxes(ARegion *); - void RunFindOrders(); - void RunFindUnit(Unit *); - void RunDestroyOrders(); - void Do1Destroy(ARegion *, Object *, Unit *); - void RunQuitOrders(); - void RunForgetOrders(); - void Do1Quit(Faction *); - void SinkUncrewedShips(); - void TransferNonShipUnits(); - void DrownUnits(); - void RunStealOrders(); - void RunTransportOrders(); - void CheckTransportOrders(); - AList *CanSeeSteal(ARegion *, Unit *); - void Do1Steal(ARegion *, Object *, Unit *); - void Do1Assassinate(ARegion *, Object *, Unit *); - void AdjustCityMons(ARegion *pReg); - void AdjustCityMon(ARegion *pReg, Unit *u); - void UpdateFactionAffiliations(); - - // - // Month long orders - // - void RunMoveOrders(); - void SetupFollowers(int phase); - Location *DoAMoveOrder(Unit *, ARegion *, Object *); - void DoMoveEnter(Unit *, ARegion *, Object **); - void SailShips(ARegion *r, int phase, AList * locations); // BS mod, integrating movement and sailing - ARegion *DoASailOrder(ARegion *r, Object *ship, Unit *captain); - void RunMonthOrders(); - void RunStudyOrders(ARegion *); - void Do1StudyOrder(Unit *, Object *); - void RunTeachOrders(); - void Do1TeachOrder(ARegion *, Unit *); - void RunProduceOrders(ARegion *); - void RunIdleOrders(ARegion *); - void RunMasterOrders(); - int ValidProd(Unit *, ARegion *, Production *); - int FindAttemptedProd(ARegion *, Production *); - void RunAProduction(ARegion *, Production *); - void RunUnitProduce(ARegion *, Unit *); - int HexsideCanGoThere(ARegion * ,Object * ,Unit *); - void Run1BuildOrder(ARegion *, Object *, Unit *); - void Run1BuildHexsideOrder(ARegion *, Object *, Unit *); - void RunBuildHelpers(ARegion *); - void ClearCastEffects(); - void RunCastOrders(); - void RunACastOrder(ARegion *, Object *, Unit *, CastOrder *); - void RunTeleportOrders(); - - // - // include spells.h for spell function declarations - // -#define GAME_SPELLS -#include "spells.h" -#undef GAME_SPELLS - - // - // Battle function - // - void KillDead(Location *); - int RunBattle(ARegion *, Unit *, Unit *, int = 0, int = 0); - void GetSides(ARegion *, AList &, AList &, AList &, AList &, Unit *, Unit *, - int = 0, int = 0); - int CanAttack(ARegion *, AList *, Unit *); - void GetAFacs(ARegion *, Unit *, Unit *, AList &, AList &, AList &); - void GetDFacs(ARegion *, Unit *, AList &); - - void CountUnits(); //testing - - //Times Reports - int WriteStatistics( Aoutfile *f, Ainfile *g, int infile ); - void WriteRumour(int &rumournum, AString rumour); - void WriteTimes(int timesnum, AString times); - void CreateTimesReports(); - void CreateBattleEvents(); - -}; - -#endif diff --git a/arcadia/gamedata.cpp b/arcadia/gamedata.cpp deleted file mode 100644 index 7e8e2b267..000000000 --- a/arcadia/gamedata.cpp +++ /dev/null @@ -1,5366 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "gamedata.h" -#include "items.h" -#include "skills.h" -#include "object.h" -#include "aregion.h" - -// -// Table of items -// -// name, plural, abbr, -// flags, -// pSkill, pLevel, pMonths, pOutput, pInput array -// mSkill, mLevel, mOutput, mInput array -// weight, type, baseprice, combat, index -// walk, ride, fly, swim, -// hitchItem, hitchwalk -// mult_item, mult_val, max_inventory -// escape, esc_skill, esc_val - -ItemType id[] = -{ - {"leader", "leaders", "LEAD", - ItemType::NOTRANSPORT, - NULL, 0, 0, 0, {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - NULL, 0, 0, {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - 10, IT_MAN | IT_LEADER, 100, 1, - 15, 0, 0, 0, - -1, 0, - -1, 0, 0, - 0, NULL, 0}, - {"viking", "vikings", "VIKI", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50, 1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"barbarian","barbarians","BARB", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50, 1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"eskimo","eskimos","ESKI", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"nomad","nomads","NOMA", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"tribesman","tribesmen","TMAN", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"darkman","darkmen","DMAN", //AELF - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"wood elf","wood elves","WELF", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"sea elf","sea elves","SELF", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"high elf","high elves","HELF", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"tribal elf","tribal elves","TELF", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"plainsman","plainsmen","PLAI", //PDWA - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50, 1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ice dwarf","ice dwarves","IDWA", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"hill dwarf","hill dwarves","HDWA", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"under dwarf","under dwarves","UDWA", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"desert dwarf","desert dwarves","DDWA", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"merman","mermen","MERM", - ItemType::NOTRANSPORT | ItemType::DISABLED, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,15, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"orc","orcs","ORC", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"gnome","gnomes","GNOM", - ItemType::NOTRANSPORT | ItemType::DISABLED, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"silver","silver","SILV", - ItemType::NOMARKET, - NULL,0,0,0, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 0, IT_NORMAL | IT_MONEY, 1,0, - 0,0,0,0, - -1,0, - I_HARP,20, 0, - 0, NULL, 0}, - {"grain","grain","GRAI", - 0, - "FARM",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_NORMAL | IT_FOOD, 15,0, - 0,0,0,0, - -1,0, - I_BAG,2, 0, - 0, NULL, 0}, - {"livestock","livestock","LIVE", - ItemType::NOTRANSPORT, - "RANC",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_NORMAL | IT_FOOD, 15,0, - 50,0,0,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"iron","iron","IRON", - 0, - "MINI",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_NORMAL, 30,0, - 0,0,0,0, - -1,0, - I_PICK,1, 0, - 0, NULL, 0}, - {"wood","wood","WOOD", - 0, - "LUMB",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_NORMAL, 30,0, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"stone","stone","STON", - 0, - "QUAR",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_NORMAL, 30,0, - 0,0,0,0, - -1,0, - I_PICK,1, 0, - 0, NULL, 0}, - {"fur","furs","FUR", - 0, - "HUNT",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL, 30,0, - 0,0,0,0, - -1,0, - I_SPEAR,1, 0, - 0, NULL, 0}, - {"fish","fish","FISH", - 0, - "FISH",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_FOOD, 15,0, - 0,0,0,0, - -1,0, - I_NET,2, 0, - 0, NULL, 0}, - {"herb","herbs","HERB", - 0, - "HERB",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 0, IT_NORMAL, 30,0, - 0,0,0,0, - -1,0, - I_BAG,2, 0, - 0, NULL, 0}, - {"horse","horses","HORS", - ItemType::NOTRANSPORT, - "HORS",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_NORMAL | IT_MOUNT, 30,1, - 70,70,0,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"dolphin","dolphins","DOLP", - ItemType::NOTRANSPORT | ItemType::ALWAYSSEE, - "DOLP",1,1,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 200, IT_ADVANCED | IT_MOUNT, 30,1, - 0,0,0,220, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"sword","swords","SWOR", - 0, - "WEAP",1,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 60,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"crossbow","crossbows","XBOW", - 0, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 60,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"longbow","longbows","LBOW", - 0, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 60,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"chain armour","chain armour","CARM", - 0, - "ARMO",1,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_ARMOR, 60,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"plate armour","plate armour","PARM", - 0, - "ARMO",3,3,1, {{I_IRON,3},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 3, IT_NORMAL | IT_ARMOR, 250,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"wagon","wagons","WAGO", - 0, - "CARP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_NORMAL, 100,0, - 0,0,0,0, - I_HORSE,250, - I_AXE,1, 0, - 0, NULL, 0}, - {"mithril","mithril","MITH", - 0, - "MINI",3,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_PICK,1, 0, - 0, NULL, 0}, - {"ironwood","ironwood","IRWD", - 0, - "LUMB",3,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"winged horse","winged horses","WING", - ItemType::NOTRANSPORT, - "HORS",5,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_ADVANCED | IT_MOUNT, 100,1, - 70,70,70,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"flying dolphin","flying dolphins","FDOL", - ItemType::NOTRANSPORT, - "DOLP",6,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 200, IT_ADVANCED | IT_MOUNT, 100,1, - 220,220,220,220, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"floater hide","floater hides","FLOA", - 0, - "HUNT",3,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_SPEAR,1, 0, - 0, NULL, 0}, - {"rootstone","rootstone","ROOT", - 0, - "QUAR",3,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_PICK,1, 0, - 0, NULL, 0}, - {"yew","yew","YEW", - 0, - "LUMB",5,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"mithril sword","mithril swords","MSWO", - 0, - "WEAP",3,1,1, {{I_MITHRIL,1},{-1,0},{-1,0},{-1,0}}, - "ESWO",1,5, {{I_SWORD,1},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_WEAPON, 200,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"mithril armour","mithril armour","MARM", - 0, - "ARMO",5,1,1, {{I_MITHRIL,1},{-1,0},{-1,0},{-1,0}}, - "EARM",1,5, {{I_PLATEARMOR,1},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_ARMOR, 500,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"pearl plate armour","pearl plate armour","PPAR", - ItemType::DISABLED, - "GCUT",4,1,1, {{I_PEARL,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_ARMOR, 500,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"double bow","double bows","DBOW", - 0, - "WEAP",5,1,1, {{I_YEW,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_WEAPON, 200,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"pearl","pearls","PEAR", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"wine","wine","WINE", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"wool","wool","WOOL", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"orchids","orchids","ORCH", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"caviar","caviar","CAVI", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"silk","silk","SILK", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"perfume","perfume","PERF", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"chocolate","chocolate","CHOC", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"cashmere","cashmere","CASH", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"jewelry","jewelry","JEWE", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"figurines","figurines","FIGU", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"dye","dye","DYE", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"truffles","truffles","TRUF", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"goatcheese","goatcheeses","CHEE", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"mink","mink","MINK", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"spices","spices","SPIC", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"vodka","vodka","VODK", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"cotton","cotton","COTT", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ivory","ivory","IVOR", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"tarot cards","tarot cards","TARO", - 0, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 60,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"lion","lions","LION", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_ANIMAL, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"wolf","wolves","WOLF", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "WOLF",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_ANIMAL, 50,1, - 15,15,0,0, - -1,0, - -1,0, 0, - ItemType::HAS_SKILL, "WOLF", 1}, - {"grizzly bear","grizzly bears","GRIZ", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50,IT_MONSTER | IT_ANIMAL, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"crocodile","crocodiles","CROC", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_ANIMAL, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"anaconda","anacondas","ANAC", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER | IT_ANIMAL, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"giant scorpion","giant scorpions","SCOR", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER | IT_ANIMAL, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"polar bear","polar bears","POLA", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER | IT_ANIMAL, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"giant rat","giant rats","GRAT", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_ANIMAL, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"giant spider","giant spiders","GSPI", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50,IT_MONSTER | IT_ANIMAL, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"giant lizard","giant lizards","GLIZ", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50,IT_MONSTER | IT_ANIMAL, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"trent","trents","TREN", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER, 50,1, - 300,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"roc","rocs","ROC", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER, 50,1, - 300,300,300,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"bog thing","bog things","BOGT", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"kong","kongs","KONG", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER, 50,1, - 300,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"sphinx","sphinxes","SPHI", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER, 50,1, - 300,300,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ice wurm","ice wurms","ICEW", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER, 50,1, - 300,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"baby dragon","baby dragons","BDRG", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "BDRG",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER | IT_ANIMAL, 50,1, - 300,300,300,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"dragon","dragons","DRAG", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "DRAG",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER | IT_ANIMAL, 50,1, - 300,300,300,0, - -1,0, - -1,0, 0, - ItemType::HAS_SKILL, "DRAG", 1}, - {"gryffin","gryffins","GRYF", - ItemType::CANTGIVE | ItemType::NOTRANSPORT | ItemType::DISABLED, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "GRYF",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 200, IT_MONSTER | IT_ANIMAL, 50,1, - 250,250,250,0, - -1,0, - -1,0, 0, - ItemType::HAS_SKILL, "GRYF", 1}, - {"centaur","centaurs","CENT", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER, 50,1, - 60,60,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"kobold","kobolds","KOBO", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ogre","ogres","OGRE", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"lizard man","lizard men","LMAN", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"wild man","wild men","WMAN", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"sandling","sandlings","SAND", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"yeti","yeti","YETI", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"goblin","goblins","GOBL", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"troll","trolls","TROL", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ettin","ettins","ETTI", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER, 50,1, - 60,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"skeleton","skeletons","SKEL", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "SUSK",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_UNDEAD, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - ItemType::LOSS_CHANCE, NULL, 15}, - {"undead","undead","UNDE", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "RAIS",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_UNDEAD, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - ItemType::LOSS_CHANCE, NULL, 15}, - {"lich","liches","LICH", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "SULI",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_UNDEAD, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - ItemType::LOSS_CHANCE, NULL, 15}, - {"imp","imps","IMP", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "SUIM",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_DEMON, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - ItemType::ESC_LEV_QUAD, "SUIM", 320}, - {"demon","demons","DEMO", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "SUDE",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_MONSTER | IT_DEMON, 50,1, - 60,60,0,0, - -1,0, - -1,0, 0, - ItemType::ESC_LEV_QUAD, "SUDE", 20}, - {"balrog","balrogs","BALR", - ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "SUBA",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250, IT_MONSTER | IT_DEMON, 50,1, - 300,300,300,0, - -1,0, - -1,0, 0, - ItemType::ESC_LEV_SQUARE, "SUBA", 10}, - {"eagle","eagles","EAGL", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "BIRD",3,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER | IT_ANIMAL, 50,1, - 15,15,15,0, - -1,0, - -1,0, 0, - ItemType::HAS_SKILL, "BIRD", 1}, - {"amulet of invulnerability","amulets of invulnerability","XXXX", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC | IT_BATTLE | IT_SPECIAL, 1000000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ring of invisibility","rings of invisibility","RING", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRRI",1,20, {{I_SILVER,600},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC, 4000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"cloak of invulnerability","cloaks of invulnerability","CLOA", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRCL",1,20, {{I_SILVER,800},{-1,0},{-1,0},{-1,0}}, - 0, IT_MAGIC | IT_ARMOR, 8000, 1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"staff of fire","staves of fire","STAF", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRSF",1,20, {{I_SILVER,600},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC | IT_BATTLE, 4000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"staff of lightning","staves of lightning","STAL", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRSL",1,20, {{I_SILVER,1000},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC | IT_BATTLE, 16000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"staff of yew","staves of yew","STAY", - ItemType::NOMARKET | ItemType::NOTRANSPORT | ItemType::DISABLED | ItemType::NEVERLOST, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC | IT_WEAPON | IT_BATTLE | IT_SPECIAL, 1000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"amulet of true seeing","amulets of true seeing","AMTS", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRTA",1,20, {{I_SILVER,600},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC, 4000,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"amulet of protection","amulets of protection","AMPR", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRPA",1,100, {{I_SILVER,200},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC | IT_BATTLE, 1000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"runesword","runeswords","RUNE", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRRU",1,20, {{I_SILVER,800},{-1,0},{-1,0},{-1,0}}, - 1, IT_MAGIC | IT_WEAPON | IT_BATTLE, 8000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"shieldstone","shieldstones","SHST", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRSH",1,100, {{I_SILVER,200},{-1,0},{-1,0},{-1,0}}, - 0, IT_MAGIC | IT_BATTLE, 4000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"magic carpet","magic carpets","CARP", - ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CRMA",1,100, {{I_SILVER,400},{-1,0},{-1,0},{-1,0}}, - 0, IT_MAGIC, 2000,0, - 15,15,15,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"giant rat","giant rats","GRAT", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"wolf","wolves","WOLF", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHBE",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"eagle","eagles","EAGL", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHBE",3,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"gryffin","gryffins","GRYF", - ItemType::CANTGIVE | ItemType::NOTRANSPORT | ItemType::DISABLED, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "ILCR",3,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"dragon","dragons","DRAG", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHBE",5,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"skeleton","skeletons","SKEL", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHUN",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"undead","undead","UNDE", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHUN",3,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"lich","liches","LICH", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHUN",5,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"imp","imps","IMP", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHDE",1,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"demon","demons","DEMO", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHDE",3,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"balrog","balrogs","BALR", - ItemType::CANTGIVE | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "PHDE",5,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_MONSTER | IT_ILLUSION, 1,1, - 1,1,1,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"portal","portals","PORT", - ItemType::NOMARKET, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CPOR",1,20, {{I_SILVER,600},{-1,0},{-1,0},{-1,0}}, - 1, IT_MAGIC | IT_SPECIAL, 1000,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"peasant","peasants","PEAS", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"pick","picks","PICK", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL|IT_WEAPON|IT_TOOL, 60, 1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"spear","spears","SPEA", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL|IT_WEAPON|IT_TOOL,60,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"axe","axes","AXE", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON|IT_TOOL,60,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"hammer","hammers","HAMM", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_NORMAL | IT_WEAPON|IT_TOOL,60,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"magic crossbow","magic crossbows","MXBO", - ItemType::DISABLED, - "WEAP",4,1,1, {{I_IRONWOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_WEAPON, 200,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"magic wagon","magic wagons","MWAG", - ItemType::DISABLED, - "CARP",3,1,1, {{I_IRONWOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50,IT_ADVANCED, 200,0, - 250,250,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"glider","gliders","GLID", - ItemType::DISABLED, - "CARP",5,2,1, {{I_FLOATER,2},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5,IT_ADVANCED, 400,0, - 0,0,15,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"net","nets","NET", - ItemType::DISABLED, - "FISH",1,1,1, {{I_HERBS,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL|IT_TOOL, 60,0, - 0,0,0,0, - -1,0, - I_SPINNING,2, 0, - 0, NULL, 0}, - {"lasso","lassoes","LASS", - ItemType::DISABLED, - "HERB",1,1,1, {{I_HERBS,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL|IT_TOOL, 60,0, - 0,0,0,0, - -1,0, - I_SPINNING,2, 0, - 0, NULL, 0}, - {"bag","bags","BAG", - ItemType::DISABLED, - "HERB",1,1,1, {{I_HERBS,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL|IT_TOOL, 60,0, - 0,0,0,0, - -1,0, - I_SPINNING,2, 0, - 0, NULL, 0}, - {"spinning wheel","spinning wheels","SPIN", - ItemType::DISABLED, - "CARP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_NORMAL|IT_TOOL, 60,0, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"leather armour","leather armour","LARM", - ItemType::DISABLED, - "ARMO",1,1,1, {{I_FUR,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_NORMAL | IT_ARMOR, 45,1, - 0,0,0,0, - -1,0, - I_SPINNING,2, 0, - 0, NULL, 0}, - {"cloth armour","cloth armour","CLAR", - ItemType::DISABLED, - "ARMO",1,1,1, {{I_HERBS,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_NORMAL | IT_ARMOR, 40,1, - 0,0,0,0, - -1,0, - I_SPINNING,2, 0, - 0, NULL, 0}, - {"boots of levitation","boots of levitation","BOOT", - ItemType::DISABLED | ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 0, IT_MAGIC, 1000, 0, - 0,0,0,15, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"pirate","pirates","PIRA", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 15,0,0,15, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"kraken","kraken","KRAK", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MONSTER, 50,1, - 300,0,0,300, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"merfolk","merfolk","MERF", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 0,0,0,15, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"elemental","elementals","ELEM", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250,IT_MONSTER, 50,1, - 300,0,0,300, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"man", "men", "MAN", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50, 1, - 15, 0, 0, 0, - -1,0, - -1, 0, 0, - 0, NULL, 0}, - /* Additional items for Ceran */ - {"fairy","fairies", "FAIR", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 3,IT_MAN, 100,1, - 13,0,13,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"lizardman","lizardmen","LIZA", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MAN, 80,1, - 15,0,0,15, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"uruk","uruks","URUK", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 11,IT_MAN, 80,1, - 21,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"goblin","goblins","GBLN", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 5,IT_MAN, 25,1, - 12,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"hobbit","hobbits","HOBB", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 8,IT_MAN, 50,1, - 12,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"gnoll","gnolls","GNOL", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"drow elf","drow elves","DRLF", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"mercenary","mercenaries","MERC", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"titan","titans","TITA", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 20,IT_MAN, 100,1, - 60,0,0,30, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"amazon","amazons","AMAZ", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ogre","ogres","OGER", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 15,IT_MAN, 80,1, - 30,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"highlander","highlanders","HILA", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"minotaur","minotaurs","MINO", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 15,IT_MAN, 80,1, - 40,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"lance","lances","LANC", - ItemType::DISABLED, - "WCRA",1,2,1, {{I_WOOD,2},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2,IT_ADVANCED | IT_WEAPON, 100,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"mushroom","mushrooms","MUSH", - ItemType::DISABLED, - "HERB",3,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 0,IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_BAG,2, 0, - 0, NULL, 0}, - {"rad rat","rad rats","RRAT", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"noogle","noogles","NOOG", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250,IT_MONSTER, 50,1, - 300,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"mutant","mutants","MUTA", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 15,IT_MONSTER, 50,1, - 20,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"battle axe","battle axes","BAXE", - ItemType::DISABLED, - "WEAP",2,2,1, {{I_IRON,1},{I_WOOD,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2, IT_NORMAL|IT_WEAPON, 90, 1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"mithril battle axe","mithril battle axes","MBAX", - ItemType::DISABLED, - "WCRA",2,2,1, {{I_MITHRIL,1},{I_IRONWOOD,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2, IT_ADVANCED|IT_WEAPON, 300, 1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"admantium","admantium","ADMT", - ItemType::DISABLED | ItemType::NOMARKET, - "MINI",5,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_ADVANCED, 100,0, - 0,0,0,0, - -1,0, - I_PICK,1, 0, - 0, NULL, 0}, - {"admantium sword", "admantium swords", "ASWR", - ItemType::DISABLED | ItemType::NOMARKET, - "WCRA",3,2,1, {{I_ADMANTIUM,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_ADVANCED|IT_WEAPON,2000,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"admantium battle axe","admantium battle axes","ABAX", - ItemType::DISABLED | ItemType::NOMARKET, - "WCRA",5,2,1, {{I_ADMANTIUM,1},{I_YEW,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2, IT_ADVANCED|IT_WEAPON, 3000, 1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"improved mithril armour","improved mithril armour","IMTH", - ItemType::DISABLED | ItemType::NOMARKET, - "ACRA",1,1,1, {{I_MPLATE,1},{I_MITHRIL,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_ADVANCED | IT_ARMOR, 1000,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"admantium ring mail", "admantium ring mails", "ARNG", - ItemType::DISABLED | ItemType::NOMARKET, - "ACRA",3,2,1, {{I_ADMANTIUM,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_ARMOR, 3000,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"admantium plate mail","admantium plate mails","AARM", - ItemType::DISABLED | ItemType::NOMARKET, - "ACRA",5,4,1, {{I_ADMANTIUM,3},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_ARMOR, 6000,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"super bow","super bows","SBOW", - ItemType::DISABLED | ItemType::NOMARKET, - "WCRA",4,2,1, {{I_YEW,2},{I_MITHRIL,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_ADVANCED|IT_WEAPON, 4000, 1, - 0, 0, 0, 0, - -1,0, - I_AXE, 1, 0, - 0, NULL, 0}, - {"camel","camels","CAME", - ItemType::DISABLED | ItemType::NOTRANSPORT, - "CAME",1,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_NORMAL|IT_MOUNT,30,1, - 70,70,0,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"grey elf","grey elves","GELF", - ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_MAN, 50, 1, - 15, 0, 0, 0, - -1,0, - -1, 0, 0, - 0, NULL, 0}, - {"drow warrior","drow warriors","DROW", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"hydra","hydrae","HYDR", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250,IT_MONSTER, 50,1, - 300,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"storm giant","storm giants","STGI", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 200,IT_MONSTER,50,1, - 250,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"cloud giant","cloud giants","CLGI", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 200,IT_MONSTER,50,1, - 250,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"illyrthid","illyrthil","ILLY", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50,IT_MONSTER,50,1, - 75,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"evil sorcerer","evil sorcerers","SORC", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"evil magician","evil magicians","MAGI", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"dark mage","dark mages","DMAG", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 15,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"evil warrior","evil warriors","WARR", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10,IT_MONSTER, 50,1, - 40,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"ice dragon","ice dragons","IDRA", - ItemType::CANTGIVE|ItemType::DISABLED | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 250,IT_MONSTER, 50,1, - 300,300,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"healing potion","healing potions","HPOT", - ItemType::DISABLED, - "HEAL",3,1,1, {{I_HERBS,1},{I_MUSHROOM,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_ADVANCED, 90,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"rough gem", "rough gems", "RGEM", - ItemType::DISABLED, - "MINI",2,1,1, {{-1,0},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2, IT_NORMAL, 60, 0, - 0,0,0,0, - -1,0, - -1, 0, 0, - 0, NULL, 0}, - {"gem", "gems", "GEM", - ItemType::DISABLED, - "GCUT",1,1,1, {{I_ROUGHGEM,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_TRADE, 120, 0, - 0,0,0,0, - -1,0, - -1, 0, 0, - 0, NULL, 0}, - {"javelin", "javelins", "JAVE", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_NORMAL | IT_WEAPON, 60, 1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"pike","pikes","PIKE", - ItemType::DISABLED, - "WCRA",1,2,1, {{I_WOOD,1},{I_IRON,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2,IT_ADVANCED | IT_WEAPON, 100,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"wolf","wolves","MWOL", - ItemType::DISABLED | ItemType::NOMARKET | ItemType::NOTRANSPORT, - "MTRA",1,2,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 10, IT_ADVANCED | IT_MOUNT , 30,1, - 17,17,0,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"giant spider","giant spiders","MSPI", - ItemType::DISABLED | ItemType::NOMARKET | ItemType::NOTRANSPORT, - "MTRA",3,3,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 50, IT_ADVANCED | IT_MOUNT, 30,1, - 60,60,0,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"giant mole","giant moles","MOLE", - ItemType::DISABLED | ItemType::NOMARKET | ItemType::NOTRANSPORT, - "MTRA",3,3,1, {{-1,0}, {-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 100, IT_ADVANCED | IT_MOUNT, 50,1, - 130,130,0,0, - -1,0, - I_LASSO,1, 0, - 0, NULL, 0}, - {"barbarian plate","barbarian plates","BPLA", - ItemType::DISABLED, - "ARMO",2,1,1, {{I_IRONWOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_NORMAL | IT_ARMOR, 75,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"mithril chain armour","mithril chain armour","MCAR", - ItemType::DISABLED, - "ARMO",5,1,2, {{I_MITHRIL,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_ARMOR, 400,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"flaming sword","flaming swords","FSWO", - ItemType::DISABLED | ItemType::NOMARKET | ItemType::NOTRANSPORT, - NULL,0,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - "CFSW",1,1, {{I_SILVER,800},{-1,0},{-1,0},{-1,0}}, - 0,IT_MAGIC | IT_WEAPON | IT_BATTLE, 5000,1, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, - {"quarterstaff","quarterstaves","QUAR", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 55,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"sabre","sabres","SABR", - ItemType::DISABLED, - "WEAP",2,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 75,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"mace","maces","MACE", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 55,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"morning star","morning stars","MSTA", - ItemType::DISABLED, - "WEAP",2,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2, IT_NORMAL | IT_WEAPON, 75,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"dagger","daggers","DAGG", - ItemType::DISABLED, - "WEAP",1,1,2, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON | IT_TOOL, 40,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"parrying dagger","parrying daggers","PDAG", - ItemType::DISABLED, - "WEAP",2,1,1, {{I_IRON,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 50,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"battle hammer","battle hammers","BHAM", - ItemType::DISABLED, - "WEAP",2,2,1, {{I_IRON,1},{I_WOOD,1},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 2, IT_NORMAL | IT_WEAPON, 100,1, - 0,0,0,0, - -1,0, - I_HAMMER,1, 0, - 0, NULL, 0}, - {"bow","bows","BOW", - ItemType::DISABLED, - "WEAP",3,1,1, {{I_IRONWOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_ADVANCED | IT_WEAPON, 60,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"shortbow","shortbows","SHBO", - ItemType::DISABLED, - "WEAP",1,1,1, {{I_WOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_WEAPON, 60,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"heavy crossbow","heavy crossbows","HXBO", - ItemType::DISABLED, - "WEAP",3,1,1, {{I_IRONWOOD,1},{-1,0},{-1,0},{-1,0}}, - NULL,0,0, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1,IT_ADVANCED | IT_WEAPON, 200,1, - 0,0,0,0, - -1,0, - I_AXE,1, 0, - 0, NULL, 0}, - {"harp", "harps", "HARP", - ItemType::DISABLED, - "CARP",3,1,1, {{I_IRONWOOD, 1}, {-1, 0},{-1,0},{-1,0}}, - NULL, 0, 0, {{-1, 0}, {-1, 0},{-1,0},{-1,0}}, - 1, IT_ADVANCED|IT_TOOL, 200, 0, - 0, 0, 0, 0, - -1, 0, - I_DAGGER, 1, 0, - 0, NULL, 0}, - {"food","food","FOOD", - ItemType::DISABLED | ItemType::ORINPUTS | ItemType::SKILLOUT, - "COOK",1,1,1, {{I_GRAIN,1}, {I_LIVESTOCK,1},{I_FISH,1},{-1,0}}, - "CRFD",1,5, {{-1,0},{-1,0},{-1,0},{-1,0}}, - 1, IT_NORMAL | IT_FOOD, 8,0, - 0,0,0,0, - -1,0, - -1,0, 0, - 0, NULL, 0}, -}; -ItemType *ItemDefs = id; - -// -// Table of men -// -// -// abbr, Favourite terrain, race type, hits -// Special level, default, special exp, default exp 1st skill, 2nd, 3rd, 4th, -// -ManType mt[] = { - {NULL, R_NEXUS,RA_NA,1, - 0,0,0,0,{NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"LEAD", R_NEXUS,RA_NA,1, - 5,5,3,3,{NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"VIKI", R_FOREST,RA_HUMAN,1, //RAID - 3,2,2,1,{"SHIP", "SAIL", "LUMB", "COMB", "CONS", NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"PLAI", R_PLAIN,RA_HUMAN,1, //PDWA - 3,2,2,1,{"HORS", "FARM", "CARP", "ENTE", "COOK", "RIDI"}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"DMAN", R_CAVERN,RA_HUMAN,1, //AELF - 3,2,2,1,{"QUAR", "BUIL", "MINI", "ARMO", NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"BARB", R_MOUNTAIN,RA_HUMAN,1, //HUMAN 1 - 3,2,2,1,{"MINI", "HUNT", "WEAP", "COMB", NULL, NULL}, - {"MYST", "WKEY", "BATT", NULL, NULL, NULL}}, - {"ESKI", R_TUNDRA,RA_HUMAN,1, - 3,2,2,1,{"HERB", "FISH", "HUNT", "HEAL", "COOK", NULL}, - {"WKEY", "PTTN", "CHAR", NULL, NULL, NULL}}, - {"NOMA", R_DESERT,RA_HUMAN,1, - 3,2,2,1,{"HORS", "RANC", "XBOW", "CAME", "RIDI", NULL}, - {"CHAR", "SUMM", "MYST", NULL, NULL, NULL}}, - {"TMAN", R_JUNGLE,RA_HUMAN,1, - 3,2,2,1,{"HERB", "HEAL", "FARM", "LUMB", "COOK", NULL}, - {"MYST", "PTTN", "ARTL", NULL, NULL, NULL}}, - {"RAID", R_FOREST,RA_HUMAN,1, - 3,2,2,1,{"XBOW", "RIDI", "HORS", "SAIL", NULL, NULL}, - {"SUMM", "ARTL", "BATT", NULL, NULL, NULL}}, - {"WELF", R_FOREST,RA_ELF,1, //ELF 1 - 3,2,2,1,{"LUMB", "CARP", "LBOW", "ENTE", "CONS", NULL}, - {"PTTN", "CHAR", "BATT", NULL, NULL, NULL}}, - {"SELF", R_PLAIN,RA_ELF,1, - 3,2,2,1,{"SHIP", "SAIL", "FISH", "LBOW", "CONS", NULL}, - {"WKEY", "PTTN", "ARTL", NULL, NULL, NULL}}, - {"HELF", R_PLAIN,RA_ELF,1, - 3,2,2,1,{"HEAL", "FARM", "ENTE", "HORS", NULL, NULL}, - {"SUMM", "WKEY", "CHAR", NULL, NULL, NULL}}, - {"TELF", R_SWAMP,RA_ELF,1, - 3,2,2,1,{"HERB", "HEAL", "RANC", "LBOW", NULL, NULL}, - {"MYST", "PTTN", "CHAR", NULL, NULL, NULL}}, - {"AELF", R_PLAIN,RA_ELF,1, - 3,2,2,1,{"LUMB", "WEAP", "OBSE", "LBOW", NULL, NULL}, - {"MYST", "BATT", "ARTL", NULL, NULL, NULL}}, - {"IDWA", R_TUNDRA,RA_DWARF,1, //DWARF 1 - 3,2,2,1,{"FISH", "BUIL", "XBOW", "SHIP", "CONS", NULL}, - {"WKEY", "PTTN", "SUMM", NULL, NULL, NULL}}, - {"HDWA", R_MOUNTAIN,RA_DWARF,1, - 3,2,2,1,{"MINI", "WEAP", "ARMO", "COMB", NULL, NULL}, - {"BATT", "CHAR", "SUMM", NULL, NULL, NULL}}, - {"UDWA", R_CAVERN,RA_DWARF,1, - 3,2,2,1,{"MINI", "QUAR", "XBOW", "ARMO", NULL, NULL}, - {"MYST", "SUMM", "ARTL", NULL, NULL, NULL}}, - {"DDWA", R_DESERT,RA_DWARF,1, - 3,2,2,1,{"QUAR", "BUIL", "ARMO", "XBOW", NULL, NULL}, - {"PTTN", "BATT", "ARTL", NULL, NULL, NULL}}, - {"PDWA", R_PLAIN,RA_DWARF,1, - 3,2,2,1,{"CONS", "FARM", "SAIL", "ENTE", NULL, NULL}, - {"MYST", "WKEY", "BATT", NULL, NULL, NULL}}, - {"MERM", R_OCEAN,RA_OTHER,1, //OTHER 1 - 3,2,2,1,{"DOLP", "FISH", "ARMO", "STEA", NULL, NULL}, - {"WKEY", "CHAR", "ARTL", NULL, NULL, NULL}}, - {"ORC", R_MOUNTAIN,RA_OTHER,1, - 4,1,3,0,{"COMB", NULL, NULL, NULL, NULL, NULL}, - {"BATT", NULL, NULL, NULL, NULL, NULL}}, - {"MAN", R_NEXUS,RA_NA,1, - 5,5,3,3,{ NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - // Additional races for Ceran - {"FAIR", R_FOREST,RA_OTHER,1, - 4,1,3,0,{"OBSE", "STEA", NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"LIZA", R_SWAMP,RA_OTHER,1, - 3,2,2,1,{"HUNT", "RANC", "LUMB", "HERB", NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"URUK", R_MOUNTAIN,RA_OTHER,1, - 5,1,3,0,{"COMB", NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"GBLN", R_CAVERN,RA_OTHER,1, - 3,2,2,1,{"MTRA", NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"HOBB", R_PLAIN,RA_OTHER,1, - 3,2,2,1,{"FARM", "RANC", "STEA", "FISH", "COOK", NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"GNOL", R_DESERT,RA_OTHER,1, - 3,2,2,1,{"QUAR", "COMB", "HUNT", NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"DRLF", R_UFOREST,RA_OTHER,1, - 3,2,2,1,{"RANC", "WEAP", "STEA", "COMB", NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"MERC", R_NEXUS,RA_OTHER,1, - 1,1,1,1,{ NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"TITA", R_DESERT,RA_OTHER,1, - 3,1,2,1,{"COMB", "TACT", "BUIL", "XBOW", NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"AMAZ", R_FOREST,RA_OTHER,1, - 3,2,2,1,{"LBOW", "WEAP", "STEA", NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"OGER", R_CERAN_HILL,RA_OTHER,1, - 4,2,2,1,{"COMB", NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"GNOM", R_CERAN_HILL,RA_OTHER,1, - 3,2,2,1,{"SHIP", "WEAP", "BUIL", "CARP", NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"HILA", R_CERAN_HILL,RA_OTHER,1, - 3,2,2,1,{"COMB", "WEAP", NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - {"MINO", R_GROTTO,RA_OTHER,1, - 4,1,3,0,{"COMB", "WEAP", NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, - // Tzarg's - {"GELF", R_UFOREST,RA_OTHER,1, - 3,2,2,1,{"XBOW", "COMB", "WEAP", "ARMO", NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL}}, -}; - -ManType *ManDefs = mt; -int NUMMAN = sizeof(mt) / sizeof(mt[0]); - -// -// Table of monsters. -// -// attackLevel, defense array -// numAttacks, hits, regen, -// tactics, stealth, obs -// special, specialLevel, -// silver spoiltype, hostile, number, name, abbr -MonType md[] = { - {0,{0,0,0,0,0,0}, - 0,0,0, - 0,0,0, - NULL,0, - 0,-1,0,0,"None", NULL}, /* none */ - {3,{3,0,0,0,2,0}, - 2,2,0, - 3,2,2, - NULL,0, - 100,-1,10,3,"Pride of Lions", "LION"}, - {2,{2,0,0,0,3,0}, - 1,1,0, - 0,0,0, - NULL,0, - 40,-1,10,10,"Wolf Pack", "WOLF"}, - {2,{2,0,0,0,0,0}, - 6,6,0, - 0,0,2, - NULL,0, - 250,-1,10,3,"Grizzly Bears", "GRIZ"}, - {3,{3,3,3,3,0,0}, - 1,1,0, - 1,1,1, - NULL,0, - 50,-1,10,6,"Crocodiles", "CROC"}, - {3,{3,3,3,3,2,0}, - 1,1,0, - 2,2,0, - NULL,0, - 50,-1,10,5,"Anacondas", "ANAC"}, - {2,{2,2,2,2,2,0}, - 2,2,0, - 2,3,0, - NULL,0, - 80,-1,10,8,"Giant Scorpions", "SCOR"}, - {2,{2,2,0,2,0,0}, - 6,6,0, - 0,0,2, - NULL,0, - 250,-1,10,3,"Polar Bears", "POLA"}, - {1,{1,1,1,1,1,0}, - 1,1,0, - 0,2,0, - NULL,0, - 20,-1,10,30,"Pack of Rats", "GRAT"}, - {4,{4,2,0,2,2,0}, - 2,2,0, - 0,2,2, - NULL,0, - 200,-1,10,4,"Giant Spiders", "GSPI"}, - {3,{3,3,0,3,1,0}, - 5,5,0, - 0,0,0, - NULL,0, - 400,-1,25,3,"Giant Lizards", "GLIZ"}, - {2,{2,3,3,3,0,0}, - 10,10,0, - 2,3,1, - NULL,0, - 500,IT_ADVANCED,25,7,"Living Trees", "TREN"}, - {4,{4,3,0,3,4,0}, - 15,15,0, - 4,2,4, - NULL,0, - 1500,IT_ADVANCED,25,2,"Giant Birds", "ROC"}, - {4,{4,3,0,3,0,0}, - 20,20,0, - 3,1,3, - NULL,0, - 2000,IT_ADVANCED,25,2,"Swamp Creatures", "BOGT"}, - {4,{4,3,0,3,1,0}, - 25,25,0, - 0,2,2, - NULL,0, - 2500,IT_ADVANCED,25,2,"Great Apes", "KONG"}, - {4,{4,4,4,4,3,0}, - 50,50,0, - 0,0,4, - NULL,0, - 5000,IT_ADVANCED,25,1,"Sphinx", "SPHI"}, - {3,{3,3,3,3,3,0}, - 6,6,0, - 2,4,1, - NULL,0, - 500,IT_ADVANCED,25,8,"Ice Wurms", "ICEW"}, - {6,{6,4,4,4,5,0}, - 50,50,0, - 5,0,5, - "firebreath", 2, - 10000,IT_MAGIC,50,1,"Baby Dragon", "BDRG"}, - {6,{6,6,6,6,5,0}, - 50,50,0, - 4,0,3, - "firebreath", 6, - 10000,IT_MAGIC,50,1,"Dragon", "DRAG"}, - {6,{6,4,4,4,5,0}, - 40,40,0, - 4,2,5, - NULL, 0, - 10000,IT_MAGIC,50,1,"Gryffin", "GRYF"}, - {4,{4,0,0,0,3,0}, - 2,2,0, - 0,1,1, - NULL,0, - 150,IT_NORMAL,10,8,"Tribe of Centaurs", "CENT"}, - {2,{2,0,0,0,0,0}, - 1,1,0, - 0,1,0, - NULL,0, - 40,IT_NORMAL,10,20,"Kobold Pack", "KOBO"}, - {3,{3,2,0,2,0,0}, - 10,10,0, - 0,0,0, - NULL,0, - 600,IT_NORMAL,10,2,"Family of Ogres", "OGRE"}, - {3,{3,3,0,3,0,0}, - 1,1,0, - 0,0,1, - NULL,0, - 50,IT_NORMAL,10,10,"Lizard Men", "LMAN"}, - {3,{3,0,0,0,0,0}, - 1,1,0, - 0,2,0, - NULL,0, - 50,IT_NORMAL,10,10,"Clan of Wild Men", "WMAN"}, - {3,{3,3,0,3,2,0}, - 1,1,0, - 1,2,1, - NULL,0, - 50,IT_NORMAL,10,10,"Sandlings", "SAND"}, - {4,{4,3,0,3,3,0}, - 2,2,0, - 0,3,1, - NULL,0, - 150,IT_NORMAL,10,5,"Yeti", "YETI"}, - {2,{2,0,0,0,0,0}, - 1,1,0, - 0,0,0, - NULL,0, - 40,IT_NORMAL,10,40,"Goblin Horde", "GOBL"}, - {3,{3,3,0,3,0,0}, - 4,4,0, - 1,0,2, - NULL,0, - 250,IT_NORMAL,10,8,"Troll Pack", "TROL"}, - {2,{2,2,0,2,0,0}, - 32,32,0, - 2,0,0, - NULL,0, - 1200,IT_NORMAL,10,2,"Ettins", "ETTI"}, - {2,{2,5,5,3,0,0}, - 1,1,0, - 0,0,0, - NULL,0, - 50,IT_NORMAL,10,100,"Skeletons", "SKEL"}, - {3,{3,2,3,2,0,0}, - 6,6,0, - 0,0,0, - NULL,0, - 400,IT_ADVANCED,25,10,"Undead", "UNDE"}, - {4,{4,4,4,4,0,0}, - 40,40,0, - 3,0,3, - "fear", 4, - 4000,IT_MAGIC,50,1,"Lich", "LICH"}, - {3,{3,3,3,3,0,0}, - 1,1,0, - 0,3,0, - NULL,0, - 50,IT_NORMAL,10,50,"Imp", "IMP"}, - {4,{4,4,4,4,3,0}, - 10,10,0, - 0,0,0, - NULL,0, - 1000,IT_ADVANCED,25,10,"Demon", "DEMO"}, - {6,{6,6,6,6,5,0}, - 200,200,0, - 5,5,5, - "hellfire", 6, - 50000,IT_MAGIC,100,1,"Balrog", "BALR"}, - {2,{2,0,3,2,5,0}, - 1,1,0, - 2,3,3, - NULL,0, - 20,-1,10,1,"Eagle", "EAGL"}, - {3,{3,0,0,0,0,0}, - 1,1,0, - 1,1,1, - NULL,0, - 500,IT_ADVANCED,50,20,"Pirates", "PIRA"}, - {5,{5,5,5,5,3,0}, - 50,50,0, - 1,1,2, - "fear", 5, - 1000,IT_MAGIC,50,1,"Kraken", "KRAK"}, - {2,{2,0,0,2,0,0}, - 1,1,0, - 2,2,3, - NULL,0, - 200,IT_NORMAL,10,100,"Merfolk", "MERF"}, - {2,{2,3,3,3,2,0}, - 10,10,0, - 2,3,1, - NULL,0, - 700,IT_ADVANCED,25,7,"Living Water", "ELEM"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Giant Rats", "iGRAT"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Wolves", "iWOLF"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Eagles", "iEAGL"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Gryffins", "iGRYF"}, - {-5,{-5,0,0,0,-5,-5}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Dragons", "iDRAG"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Illusionary Skeletons", "iSKEL"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Illusionary Undead", "iUNDE"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Lich", "iLICH"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Imps", "iIMP"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Illusionary Demons", "iDEMO"}, - {-5,{-5,0,0,0,-5,0}, - 0,0,0, - 0,5,0, - NULL,0, - 0,-1,0,0,"Phantom Balrog", "iBALR"}, - // Ceran new monsters - {2,{2,2,0,0,2,0}, - 2,2,0, - 1,2,0, - NULL,0, - 20,-1,20,30,"Rad Rats", "RRAT"}, - {5,{5,5,10,3,5,0}, - 50,50,0, - 6,3,2, - "fireball", 5, - 2000,IT_MAGIC,100,2,"Noogle", "NOOG"}, - {3,{3,3,3,3,0,0}, - 3,3,0, - 1,2,1, - NULL,0, - 400,IT_NORMAL,10,10,"Mutants", "MUTA"}, - // Tzargs new monsters - {3,{3,3,3,3,0,0}, - 1,1,0, - 1,3,2, - NULL,0, - 70,IT_NORMAL,50,100,"Drow Warriors", "DROW"}, - {2,{5,3,0,0,0,0}, - 30,60,0, - 1,0,1, - "firebreath", 3, - 7500,IT_MAGIC,50,1,"Hydra", "HYDR"}, - {6,{6,6,6,6,0,0}, - 50,50,0, - 4,0,4, - "storm", 6, - 10000,IT_MAGIC,50,1,"Storm Giant", "STGI"}, - {5,{5,5,5,5,0,0}, - 30,50,0, - 4,0,4, - "lightning", 5, - 15000,IT_MAGIC,50,1,"Cloud Giant", "CLGI"}, - {0,{0,5,5,5,0,0}, - 1,20,0, - 5,0,5, - "mindblast", 5, - 10000,IT_MAGIC,50,1,"Illyrthid", "ILLY"}, - {1,{1,0,0,0,0,0}, - 1,1,0, - 3,0,3, - "fireball", 3, - 200,IT_ADVANCED,50,5,"Evil Sorcerers", "SORC"}, - {1,{1,0,0,0,0,0}, - 1,1,0, - 3,0,3, - "lightning", 3, - 200,IT_ADVANCED,50,2,"Evil Magicians", "MAGI"}, - {1,{1,0,0,0,0,0}, - 1,1,0, - 5,0,3, - "black_wind", 3, - 1000,IT_MAGIC,50,1,"Dark Mage", "DMAG"}, - {3,{3,0,0,0,0,0}, - 1,1,0, - 0,0,0, - NULL,0, - 50,IT_NORMAL,50,20,"Evil Warriors", "WARR"}, - {4,{4,4,4,4,3,0}, - 50,50,0, - 2,0,3, - "icebreath", 4, - 8000,IT_MAGIC,50,1,"Ice Dragon", "IDRA"}, -}; - -MonType *MonDefs = md; -int NUMMONSTERS = sizeof(md) / sizeof(md[0]); - -// -// Table of weapons. -// -// item abbr, -// flags, -// baseSkill, orSkill, -// weapClass, attackType, numAttacks -// attackBonus, defenseBonus, mountBonus -// -WeaponType wepd[] = { - // WEAPON_NONE - {NULL, - 0, - NULL, NULL, - 0, 0, 0, - 0, 0, 0}, - // WEAPON_SUPERBOW - {"SBOW", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "LBOW", "XBOW", - ARMORPIERCING, ATTACK_RANGED, WeaponType::NUM_ATTACKS_SKILL, - 2, 0, 0}, - // WEAPON_STAFFOFY - {"STAY", - WeaponType::NOMOUNT, - "COMB", NULL, - CRUSHING, ATTACK_COMBAT, 1, - 4, 4, 0}, - // WEAPON_RUNESWORD - {"RUNE", - WeaponType::RIDINGBONUS, - "COMB", NULL, - SLASHING, ATTACK_COMBAT, 1, - 4, 4, 0}, - // WEAPON_DOUBLEBOW - {"DBOW", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "LBOW", "XBOW", - ARMORPIERCING, ATTACK_RANGED, WeaponType::NUM_ATTACKS_SKILL, - 0, 0, 0}, - // WEAPON_MCROSSBOW - {"MXBO", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "XBOW", NULL, - ARMORPIERCING, ATTACK_RANGED, 1, - 0, 0, 0}, - // WEAPON_LONGBOW - {"LBOW", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "LBOW", NULL, - PIERCING, ATTACK_RANGED, 1, - -2, 0, 0}, - // WEAPON_HEAVYCROSSBOW - {"HXBO", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "XBOW", NULL, - ARMORPIERCING, ATTACK_RANGED, -3, - 3, 0, 0}, - // WEAPON_BOW - {"BOW", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "LBOW", NULL, - PIERCING, ATTACK_RANGED, 2, - -3, 0, 0}, - // WEAPON_SHORTBOW - {"SHBO", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "LBOW", NULL, - PIERCING, ATTACK_RANGED, 3, - -4, 0, 0}, - // WEAPON_CROSSBOW - {"XBOW", - WeaponType::NEEDSKILL | WeaponType::RANGED | WeaponType::NOATTACKERSKILL, - "XBOW", NULL, - ARMORPIERCING, ATTACK_RANGED, -2, - 0, 0, 0}, - // WEAPON_JAVELIN - {"JAVE", - WeaponType::RANGED|WeaponType::RIDINGBONUSDEFENSE, - "COMB", NULL, - PIERCING, ATTACK_RANGED, -2, - -1, 0, 0}, - // WEAPON_LANCE - {"LANC", - WeaponType::NEEDSKILL | WeaponType::NOFOOT | WeaponType::RIDINGBONUS | - WeaponType::NOATTACKERSKILL | WeaponType::LONG, - "RIDI", NULL, - PIERCING, ATTACK_RIDING, 1, - 4, 0, 0}, - // WEAPON_ABAX - {"ABAX", - WeaponType::RIDINGBONUS, - "COMB", NULL, - ARMORPIERCING, ATTACK_COMBAT, -2, - 8, 8, 0}, - // WEAPON_ASWR - {"ASWR", - WeaponType::RIDINGBONUS, - "COMB", NULL, - ARMORPIERCING, ATTACK_COMBAT,1, - 6, 6, 0}, - // WEAPON_FSWORD - {"FSWO", - WeaponType::RIDINGBONUS, - "COMB", NULL, - SLASHING, ATTACK_COMBAT, 1, - 4, 4, 0}, - // WEAPON_MBAXE - {"MBAX", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CLEAVING, ATTACK_COMBAT, -2, - 6, 6, 0}, - // WEAPON_MSWORD - {"MSWO", - WeaponType::RIDINGBONUS, - "COMB", NULL, - SLASHING, ATTACK_COMBAT, 1, - 4, 4, 0}, - // WEAPON_PIKE - {"PIKE", - WeaponType::NOMOUNT | WeaponType::LONG, - "COMB", NULL, - PIERCING, ATTACK_COMBAT, 1, - 2, 2, 3}, - // WEAPON_BAXE - {"BAXE", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CLEAVING, ATTACK_COMBAT, -2, - 4, 4, 0}, - // WEAPON_BHAMMER - {"BHAM", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CRUSHING, ATTACK_COMBAT, 1, - 3, 3, 0}, - // WEAPON_SABRE - {"SABR", - WeaponType::RIDINGBONUS, - "COMB", NULL, - SLASHING, ATTACK_COMBAT, 1, - 3, 2, 0}, - // WEAPON_MSTAR - {"MSTA", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CRUSHING, ATTACK_COMBAT, 1, - 4, 1, 0}, - // WEAPON_SWORD - {"SWOR", - WeaponType::RIDINGBONUS, - "COMB", NULL, - SLASHING, ATTACK_COMBAT, 1, - 2, 2, 0}, - // WEAPON_MACE - {"MACE", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CRUSHING, ATTACK_COMBAT, 1, - 2, 2, 0}, - // WEAPON_QSTAFF - {"QUAR", - WeaponType::NOMOUNT | WeaponType::LONG, - "COMB", NULL, - CRUSHING, ATTACK_COMBAT, 1, - 1, 3, 1}, - // WEAPON_PDAGGER - {"PDAG", - WeaponType::SHORT | WeaponType::RIDINGBONUS, - "COMB", NULL, - PIERCING, ATTACK_COMBAT, 2, - 1, 5, 0}, - // WEAPON_DAGGER - {"DAGG", - WeaponType::SHORT | WeaponType::RIDINGBONUS, - "COMB", NULL, - PIERCING, ATTACK_COMBAT, 3, - 1, 1, 0}, - // WEAPON_PICK - {"PICK", - WeaponType::RIDINGBONUS, - "COMB", NULL, - PIERCING, ATTACK_COMBAT, 1, - 1, 1, 0}, - // WEAPON_SPEAR - {"SPEA", - WeaponType::RIDINGBONUS, - "COMB", NULL, - PIERCING, ATTACK_COMBAT, 1, - 1, 1, 0}, - // WEAPON_AXE - {"AXE", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CLEAVING, ATTACK_COMBAT, 1, - 1, 1, 0}, - // WEAPON_HAMMER - {"HAMM", - WeaponType::RIDINGBONUS, - "COMB", NULL, - CRUSHING, ATTACK_COMBAT, 1, - 1, 1, 0}, -}; - -WeaponType *WeaponDefs = wepd; -int NUMWEAPONS = sizeof(wepd) / sizeof(wepd[0]); - -// -// Table of armor. -// -// abbr, flags, from, slashChance, pierceChance, crushChance, cleaveChance, -// armorpiercingChance, energyChance, spiritChance, weatherChance; -// -ArmorType armd[] = { - // ARMOR_NONE - { NULL, 0, 100, {0, 0, 0, 0, 0, 0, 0, 0}}, - // ARMOR_CLOAKOFI - { "CLOA", ArmorType::ONLYONEHIT, 80, {79, 79, 79, 79, 79, 79, 79, 79}}, - // ARMOR_ADPLATE - { "AARM", 0, 100, {95, 95, 95, 95, 90, 90, 90, 90}}, - // ARMOR_ADRING - { "ARNG", 0, 100, {90, 90, 90, 90, 80, 80, 80, 80}}, - // ARMOR_IMITHRIL - { "IMTH", 0, 100, {90, 90, 90, 90, 75, 75, 75, 75}}, - // ARMOR_MARMOR - { "MARM", 0, 24, {21, 21, 21, 21, 16, 16, 16, 16}}, // 90%/66.67% - // ARMOR_PPLATE - { "PPAR", 0, 24, {18, 18, 18, 18, 9, 20, 20, 20}}, - // ARMOR_MCHAIN - { "MCAR", 0, 300, {225, 200, 150, 225, 150, 150, 150, 150}}, - // ARMOR_PLATEARMOR - { "PARM", 0, 8, {6, 6, 6, 6, 3, 1, 1, 1}}, - // ARMOR_BPLATE - { "BPLA", 0, 300, {100, 270, 200, 75, 100, 100, 100, 100}}, - // ARMOR_CHAINARMOR - { "CARM", 0, 2, {1, 1, 1, 1, 0, 0, 0, 0}}, - // ARMOR_LEATHERARMOR - { "LARM", 0, 3, {1, 1, 1, 1, 0, 1, 1, 1}}, - // ARMOR_CLOTHARMOR - { "CLAR", ArmorType::USEINASSASSINATE, 6, {1, 1, 1, 1, 0, 0, 0, 0}}, -}; - -ArmorType *ArmorDefs = armd; -int NUMARMORS = sizeof(armd) / sizeof(armd[0]); - -// -// Table of mounts -// skill,minBonus,maxBonus,maxHamperedBonus -// -MountType mountd[] = { - // MOUNT_NONE - { NULL, NULL, 0, 0, 0, NULL, 0}, - // MOUNT_WHORSE - { "WING", "RIDI", 3, 5, 3, NULL, 0}, - // MOUNT_FDOLPHIN - { "FDOL", "RIDI", 3, 3, 3, NULL, 0}, - // MOUNT_HORSE - { "HORS", "RIDI", 1, 3, 3, NULL, 0}, - // MOUNT_DOLPHIN - { "DOLP", "RIDI", 1, 3, 3, NULL, 0}, - // MOUNT_CAMEL - { "CAME", "RIDI", 1, 2, 2, "spook_horses", 3}, - // MOUNT_MWOLF - { "MWOL", "RIDI", 1, 3, 3, NULL, 0}, - // MOUNT_MSPIDER - { "MSPI", "RIDI", 2, 3, 3, NULL, 0}, - // MOUNT_MOLE - { "MOLE", "RIDI", 2, 3, 3, NULL, 0}, - // MOUNT_CARPET - { "CARP", "RIDI", 1, 1, 0, NULL, 0}, -}; - -MountType *MountDefs = mountd; -int NUMMOUNTS = sizeof(mountd) / sizeof(mountd[0]); - -// -// Table of other battle items -// -BattleItemType bitd[] = { - // BATTLE_NONE - { NULL, 0, 0, 0 }, - // BATTLE_STAFFOFL - {"STAL", BattleItemType::MAGEONLY | BattleItemType::SPECIAL, - "lightning", 3 }, - // BATTLE_STAFFOFY - {"STAY", BattleItemType::MAGEONLY | BattleItemType::ENERGY, - NULL, 0 }, - // BATTLE_STAFFOFF - {"STAF", BattleItemType::MAGEONLY | BattleItemType::SPECIAL, - "fireball", 3 }, - // BATTLE_FSWORD - {"FSWO", BattleItemType::SPECIAL, - "fireball", 1 }, - // BATTLE_RUNESWORD - {"RUNE", BattleItemType::SPECIAL, - "fear", 2 }, - // BATTLE_AOFI - {"XXXX", BattleItemType::SHIELD, - "invulnerable", 5 }, - // BATTLE_AMULETOFP - {"AMPR", BattleItemType::SHIELD, - "shield_spirit", 3 }, - // BATTLE_SHIELDSTONE - {"SHST", BattleItemType::SHIELD, - "energy_shield", 3 }, -}; - -BattleItemType *BattleItemDefs = bitd; -int NUMBATTLEITEMS = sizeof(bitd) / sizeof(bitd[0]); - -// -// Table of skills. -// -// -// name, abbr, cost, -// flags -// special, rangeindex -// skill dependancy array -// cast_cost, combat_first, combat_cost (energy costs for ARCADIA_MAGIC) -// -static SkillType sd[] = { - {"leadership","LEAD",50, - SkillType::UPGRADE, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"heroship","HERO",100, - SkillType::UPGRADE, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"mining","MINI",10, - 0, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"lumberjack","LUMB",10, - 0, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"quarrying","QUAR",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"hunting","HUNT",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"fishing","FISH",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"herb lore","HERB",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"horse training","HORS",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"dolphin training","DOLP",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"weaponsmith","WEAP",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"armourer","ARMO",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"carpenter","CARP",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"building","BUIL",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"shipbuilding","SHIP",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"entertainment","ENTE",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"tactics","TACT",50, - SkillType::BATTLEREP, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"combat","COMB",10, - SkillType::BATTLEREP, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"riding","RIDI",10, - SkillType::BATTLEREP, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"crossbow","XBOW",10, - SkillType::BATTLEREP, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"longbow","LBOW",10, - SkillType::BATTLEREP, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"stealth","STEA",50, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"observation","OBSE",50, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"healing","HEAL",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"sailing","SAIL",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"farming","FARM",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"ranching","RANC",10, - 0, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"force","FORC",100, - SkillType::MAGIC | SkillType::FOUNDATION, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"pattern","PATT",100, - SkillType::MAGIC | SkillType::FOUNDATION, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"spirit","SPIR",100, - SkillType::MAGIC | SkillType::FOUNDATION, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"fire","FIRE",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DAMAGE, - "fireball",NULL, S_BASE_WINDKEY, - {{"FORC",1},{NULL,0},{NULL,0}}, - 0, 1, 1}, // - {"earthquake","EQUA",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DAMAGE, - "earthquake",NULL, S_BASE_PATTERNING, - {{"FORC",1},{"PATT",1},{NULL,0}}, - 0, 4, 2}, // - {"force shield","FSHI",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::MAGEOTHER, - "force_shield",NULL, S_BASE_WINDKEY, - {{"FORC",1},{NULL,0},{NULL,0}}, - 0, 3, 1}, // - {"energy shield","ESHI",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::MAGEOTHER, - "energy_shield",NULL, S_BASE_PATTERNING, - {{"FORC",1},{NULL,0},{NULL,0}}, - 0, 2, 1}, // - {"spirit shield","SSHI",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::MAGEOTHER, - "shield_spirit",NULL, S_BASE_SUMMONING, - {{"SPIR",1},{"FORC",1},{NULL,0}}, - 0, 2, 1}, // - {"magical healing","MHEA",100, - SkillType::MAGIC, - NULL,NULL, S_BASE_PATTERNING, - {{"PATT",1},{NULL,0},{NULL,0}}, - 0, 0, 20}, // combat cost per 120 corpses - {"gate lore","GATE",100, - SkillType::MAGIC | SkillType::CAST, - NULL,NULL, S_BASE_PATTERNING, - {{"PATT",1},{"SPIR",1},{NULL,0}}, - 6, 0, 0}, // energy to transfer 18 weight units at level 1 (wgt*=skill^2). ie 3 weight per energy. - {"farsight","FARS",100, - SkillType::MAGIC | SkillType::CAST, - NULL, "rng_farsight", S_BASE_PATTERNING, - {{"PATT",1},{"SPIR",1},{NULL,0}}, - 3, 0, 0}, // cost for nrmal, *4 for large - {"teleportation","TELE",100, - SkillType::MAGIC | SkillType::CAST, - NULL, "rng_teleport", S_BASE_MYSTICISM, - {{"GATE",1},{"FARS",3},{NULL,0}}, - 8, 0, 0}, // cost per 50*level weight - {"portal lore","PORT",100, - SkillType::MAGIC | SkillType::CAST, - NULL, "rng_portal", -1, - {{"GATE",3},{"FARS",1},{NULL,0}}, - 0, 0, 0}, - {"mind reading","MIND",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, S_BASE_ILLUSION, - {{"PATT",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, // ?? - {"weather lore","WEAT",100, - SkillType::MAGIC | SkillType::CAST | SkillType::NOTIFY, - NULL, "rng_weather", -1, - {{"FORC",1},{"PATT",1},{NULL,0}}, - 0, 0, 0}, // - {"summon wind","SWIN",100, - SkillType::MAGIC, - NULL, NULL, S_BASE_WINDKEY, - {{"WEAT",1},{NULL,0},{NULL,0}}, - 2, 0, 0}, //cast cost is cost required to speed a small ship. x2 for clipper, x3 for galleon. - {"summon storm","SSTO",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::FEAR, // XXX-hack - "storm", NULL, S_BASE_WINDKEY, - {{"WEAT",1},{NULL,0},{NULL,0}}, - 0, 2, 1}, // now not a permanent spell, so needs to be cast for longer than eg fear. - {"summon tornado","STOR",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DAMAGE, - "tornado", NULL, S_BASE_WINDKEY, - {{"WEAT",3},{NULL,0},{NULL,0}}, - 0, 4, 2}, // - {"call lightning","CALL",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DAMAGE, - "lightning", NULL, S_BASE_WINDKEY, - {{"WEAT",5},{NULL,0},{NULL,0}}, - 0, 5, 3}, // - {"clear skies","CLEA",100, - SkillType::MAGIC|SkillType::COMBAT|SkillType::CAST | SkillType::MAGEOTHER, - "clear_skies", NULL, S_BASE_WINDKEY, - {{"WEAT",1},{NULL,0},{NULL,0}}, - 8, 2, 1}, // cost for normal, *4 for large - {"earth lore","EART",100, - SkillType::MAGIC | SkillType::CAST | SkillType::NOTIFY, - NULL, NULL, S_BASE_PATTERNING, - {{"PATT",1},{NULL,0},{NULL,0}}, - 4, 0, 0}, // cost for normal cast, *4 large - {"wolf lore","WOLF",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_PATTERNING, - {{"EART",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, // cost per 10 wolves summoned - ArcIV free! - {"bird lore","BIRD",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_PATTERNING, - {{"EART",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, // cost per bird summoned or double neighbour sight - ArcIV free! - {"dragon lore","DRAG",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"BIRD",3},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"necromancy","NECR",100, - SkillType::MAGIC | SkillType::NOTIFY, - NULL, NULL, S_BASE_SUMMONING, - {{"FORC",1},{"SPIR",1},{NULL,0}}, - 0, 0, 10}, // cost per 120 corpses - {"summon skeletons","SUSK",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"NECR",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"raise undead","RAIS",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_SUMMONING, - {{"NECR",3},{NULL,0},{NULL,0}}, - 50, 0, 0}, // cost per 10 undead - {"summon lich","SULI",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_SUMMONING, - {{"NECR",5},{NULL,0},{NULL,0}}, - 50, 0, 0}, // - {"create aura of fear","FEAR",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::FEAR, - "fear", NULL, S_BASE_SUMMONING, - {{"NECR",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, // - {"summon black wind","SBLA",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DAMAGE, - "black_wind", NULL, S_BASE_SUMMONING, - {{"NECR",5},{NULL,0},{NULL,0}}, - 0, 6, 6}, // - {"banish undead","BUND",100, - SkillType::MAGIC | SkillType::COMBAT, - "banish_undead", NULL, S_BASE_SUMMONING, - {{"NECR",1},{NULL,0},{NULL,0}}, - 0, 2, 2}, // - {"demon lore","DEMO",100, - SkillType::MAGIC | SkillType::NOTIFY, - NULL, NULL, -1, - {{"FORC",1},{"SPIR",1},{NULL,0}}, - 0, 0, 0}, - {"summon imps","SUIM",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_SUMMONING, - {{"DEMO",1},{NULL,0},{NULL,0}}, - 5, 0, 0}, // cost per 10 imps - {"summon demon","SUDE",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_SUMMONING, - {{"SUIM",3},{NULL,0},{NULL,0}}, - 70, 0, 0}, // cost per 10 demons - {"summon balrog","SUBA",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_SUMMONING, - {{"SUDE",3},{NULL,0},{NULL,0}}, - 60, 0, 0}, // - {"banish demons","BDEM",100, - SkillType::MAGIC | SkillType::COMBAT, - "banish_demon", NULL, S_BASE_SUMMONING, - {{"DEMO",1},{NULL,0},{NULL,0}}, - 0, 2, 2}, // - {"illusion","ILLU",100, - SkillType::MAGIC | SkillType::NOTIFY, - NULL, NULL, -1, - {{"FORC",1},{"PATT",1},{NULL,0}}, - 0, 0, 0}, - {"phantasmal entertainment","PHEN",100, - SkillType::MAGIC, - NULL, NULL, S_BASE_ILLUSION, - {{"ILLU",1},{NULL,0},{NULL,0}}, - 2, 0, 0}, //cost to cast with ARCADIA_MAGIC - {"create phantasmal beasts","PHBE",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"ILLU",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"create phantasmal undead","PHUN",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"ILLU",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"create phantasmal demons","PHDE",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"ILLU",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"invisibility","INVI",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, S_BASE_ILLUSION, - {{"ILLU",3},{NULL,0},{NULL,0}}, - 8, 0, 0}, //cost to cast on (level) men. - {"true seeing","TRUE",100, - SkillType::MAGIC, - NULL, NULL, S_BASE_ILLUSION, - {{"ILLU",3},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"dispel illusions","DISP",100, - SkillType::MAGIC | SkillType::COMBAT, - "dispel_illusion", NULL, S_BASE_ILLUSION, - {{"ILLU",1},{NULL,0},{NULL,0}}, - 0, 2, 1}, // - {"artifact lore","ARTI",100, - SkillType::MAGIC | SkillType::NOTIFY, - NULL, NULL, S_BASE_ILLUSION, - {{"FORC",1},{"PATT",1},{"SPIR",1}}, - 3, 0, 0}, // cost for (level) AMPRs or SHSTs. - {"create ring of invisibility","CRRI",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_ILLUSION, - {{"ARTI",3},{"INVI",3},{NULL,0}}, - 60, 0, 0}, // cost for RING - {"create cloak of invulnerability","CRCL",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_ARTIFACTLORE, - {{"ARTI",4},{"FSHI",3},{NULL,0}}, - 50, 0, 0}, // cost for CLOA - {"create staff of fire","CRSF",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_ARTIFACTLORE, - {{"ARTI",3},{"FIRE",3},{NULL,0}}, - 30, 0, 0}, // cost for STAF - {"create staff of lightning","CRSL",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_WINDKEY, - {{"ARTI",5},{"CALL",3},{NULL,0}}, - 180, 0, 0}, // cost for STAL - {"create amulet of true seeing","CRTA",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_ILLUSION, - {{"ARTI",3},{"TRUE",3},{NULL,0}}, - 50, 0, 0}, // cost for AMTS - {"create amulet of protection","CRPA",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"ARTI",1},{"SSHI",3},{NULL,0}}, - 0, 0, 0}, - {"create runesword","CRRU",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_SUMMONING, - {{"ARTI",4},{"FEAR",3},{NULL,0}}, - 40, 0, 0}, // cost for RUNE - {"create shieldstone","CRSH",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"ARTI",3},{"ESHI",3},{NULL,0}}, - 0, 0, 0}, - {"create magic carpet","CRMA",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, S_BASE_WINDKEY, - {{"ARTI",2},{"WEAT",3},{NULL,0}}, - 8, 0, 0}, // cost for (level) CARPs - {"engrave runes of warding","ENGR",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, S_BASE_ARTIFACTLORE, - {{"ARTI",3},{"ESHI",3},{"SSHI",3}}, - 10, 0, 0}, // cost per building size (tower = 1). bonus = level. - {"construct gate","CGAT",100, - SkillType::MAGIC | SkillType::CAST | SkillType::COSTVARIES, - NULL, NULL, S_BASE_MYSTICISM, - {{"ARTI",3},{"GATE",3},{NULL,0}}, - 100, 0, 0}, // - {"enchant swords","ESWO",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, S_BASE_MYSTICISM, - {{"ARTI",1},{NULL,0},{NULL,0}}, - 1, 0, 0}, // cost per sword - {"enchant armour","EARM",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, S_BASE_MYSTICISM, - {{"ARTI",1},{NULL,0},{NULL,0}}, - 1, 0, 0}, // cost per armour - {"construct portal","CPOR",100, - SkillType::MAGIC | SkillType::CAST, - NULL, NULL, -1, - {{"ARTI",3},{"PORT",3},{NULL,0}}, - 0, 0, 0}, - {"manipulation","MANI",100, - SkillType::APPRENTICE | SkillType::DISABLED, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"weaponcraft","WCRA",10, - SkillType::DISABLED, - NULL, NULL, -1, - {{"WEAP",5},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"armourcraft","ACRA",10, - SkillType::DISABLED, - NULL, NULL, -1, - {{"ARMO",5},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"camel training","CAME",10, - SkillType::DISABLED, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - // Even more for Ceran - {"gemcutting", "GCUT", 50, - SkillType::DISABLED, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL, 0}}, - 0, 0, 0}, - {"monster training", "MTRA", 50, - SkillType::DISABLED, - NULL, NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"create flaming sword","CFSW",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, NULL, -1, - {{"ARTI",2},{"FIRE",3},{NULL,0}}, - 1, 0, 0}, - {"cooking","COOK",10, - SkillType::DISABLED, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"create food","CRFD",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, NULL, -1, - {{"EART",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"banking","BANK",100, - SkillType::DISABLED, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"quartermaster", "QUAM", 100, - SkillType::DISABLED, - NULL, NULL, -1, - {{NULL, 0}, {NULL, 0}, {NULL, 0}}, - 0, 0, 0}, - {"blizzard","BLIZ",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, "rng_square", S_BASE_WINDKEY, - {{"WKEY",4},{NULL,0},{NULL,0}}, - 10, 0, 0}, //cost for normal casting, *4 for large - {"fog","FOG",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::CAST | SkillType::DISABLED | SkillType::MAGEOTHER | SkillType::STUDYOR, - "fog", NULL, S_BASE_WINDKEY, - {{"WKEY",1},{"ILLN",1},{NULL,0}}, - 4, 4, 0}, //cost for normal casting, *4 for large - {"concealment","CONC",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::CAST | SkillType::DISABLED | SkillType::MAGEOTHER, - "concealment", NULL, S_BASE_ILLUSION, - {{"ILLN",2},{NULL,0},{NULL,0}}, - 0, 3, 3}, // - {"create illusory creatures","ILCR",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED | SkillType::COSTVARIES, - NULL, NULL, S_BASE_ILLUSION, - {{"ILLN",1},{NULL,0},{NULL,0}}, - 2, 0, 0}, //cost of summoning an illusionary balrog. *4 for dragon, /4 for demons, /40 for others. - {"illusory wounds","ILWO",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DISABLED | SkillType::FEAR, - "wounds", NULL, S_BASE_ILLUSION, - {{"ILCR",3},{NULL,0},{NULL,0}}, - 0, 4, 1}, // like old storm, -2 effect - {"instill courage","COUR",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DISABLED, - "courage", NULL, S_BASE_ILLUSION, - {{"ILCR",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, // +2 effect to own army. - {"summon men","SUME",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, NULL, S_BASE_SUMMONING, - {{"SUMM",1},{NULL,0},{NULL,0}}, - 2, 0, 0}, //cost per 10 men summoned - {"resurrection","RESU",100, - SkillType::MAGIC | SkillType::DISABLED, - NULL, NULL, S_BASE_SUMMONING, - {{"NECR",4},{"MHEA",3},{NULL,0}}, - 5, 0, 2}, //combat cost per 3*level corpses. Cast cost for post-assassination. - {"summon spirit of the dead","SUSP",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED | SkillType::STUDYOR, - NULL, NULL, S_BASE_SUMMONING, - {{"RESU",3},{NULL,0},{NULL,0}}, - 50, 0, 0}, //cost to summon. /5 for checking region. - {"inner strength","INNE",100, - SkillType::MAGIC | SkillType::DISABLED, - NULL, NULL, S_BASE_PATTERNING, - {{"ALTE",1},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"transmutation","TRAM",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, NULL, S_BASE_MYSTICISM, - {{"ALTE",1},{NULL,0},{NULL,0}}, - 2, 0, 0}, //cost per change of 8 items (or 2 advanced) - {"modification","MODI",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, "rng_halflinear", S_BASE_PATTERNING, - {{"EART",4},{NULL,0},{NULL,0}}, - 2, 0, 0}, //cost per change of resource (*4 for advanced) - {"rejuvenation","REJU",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, "rng_linear_surface", S_BASE_PATTERNING, - {{"MODI",5},{"MYST",4},{NULL,0}}, - 25, 0, 0}, //cost for land to land. ocean->land *2, land->ocean *3. This spell HAS to be surface only until someone changes the format of the terrain table. - {"sea ward","SWAR",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, "rng_square", S_BASE_WINDKEY, - {{"SWIN",3},{NULL,0},{NULL,0}}, - 10, 0, 0}, //cost for normal casting, *3 for large. - {"diversion","DIVE",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED | SkillType::COSTVARIES, - NULL, "rng_halflinear", S_BASE_PATTERNING, - {{"EART",4},{NULL,0},{NULL,0}}, - 25, 0, 0}, // - {"gryffin lore","GRYF",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED | SkillType::COSTVARIES, - NULL, NULL, S_BASE_PATTERNING, - {{"BIRD",4},{"WOLF",4},{NULL,0}}, - 0, 0, 0}, // cost of summoning. maintenance 3. - {"hypnosis","HYPN",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, NULL, S_BASE_MYSTICISM, - {{"MYST",2},{NULL,0},{NULL,0}}, - 6, 0, 0}, //cast_cost is cost per 10*level men hypnotised - {"binding","BIND",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DISABLED | SkillType::MAGEOTHER, - "binding", NULL, S_BASE_MYSTICISM, - {{"HYPN",4},{NULL,0},{NULL,0}}, - 0, 4, 4}, // - {"create portal","CRPO",100, - SkillType::MAGIC | SkillType::CAST | SkillType::DISABLED, - NULL, "rng_square", S_BASE_MYSTICISM, - {{"TELE",4},{NULL,0},{NULL,0}}, - 30, 0, 0}, //cast_cost is cost to create portal. Cost to transmit men is in Unit::GetEnergy() and Unit::RechargeEnergy(). - {"light","LIGT",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DISABLED, - "light", NULL, S_BASE_MYSTICISM, - {{"MYST",1},{NULL,0},{NULL,0}}, - 0, 3, 0}, // - {"darkness","DARK",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DISABLED | SkillType::MAGEOTHER, - "darkness", NULL, S_BASE_MYSTICISM, - {{"LIGT",4},{NULL,0},{NULL,0}}, - 0, 5, 1}, // - {"dragon lore","DRAL",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::CAST | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"BIND",5},{NULL,0},{NULL,0}}, - 0, 12, 12}, - {"toughness","TOUG",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"BATT",3},{NULL,0},{NULL,0}}, - 0, 15, 15}, - {"unity","UNIY",100, - SkillType::MAGIC | SkillType::COMBAT | SkillType::DISABLED, - NULL, NULL, S_BASE_MYSTICISM, - {{"CHAR",2},{"BATT",1},{NULL,0}}, - 0, 0, 0}, - {"frenzy","FREN",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"BATT",1},{NULL,0},{NULL,0}}, - 0, 15, 15}, - {"second sight","SSIG",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"BATT",2},{NULL,0},{NULL,0}}, - 0, 15, 15}, - {"swiftness","SWIF",100, - SkillType::MAGIC | SkillType::BATTLEREP | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"BATT",2},{NULL,0},{NULL,0}}, - 0, 15, 15}, - {"trading","TRAD",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"CHAR",1},{NULL,0},{NULL,0}}, - 0, 15, 15}, - {"merchantry","MERC",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::MAGEOTHER, - NULL, NULL, S_BASE_MYSTICISM, - {{"TRAD",3},{NULL,0},{NULL,0}}, - 0, 15, 15}, - {"windkey","WKEY",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::FOUNDATION, - NULL, NULL, S_BASE_WINDKEY, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"illusion","ILLN",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::FOUNDATION, - NULL, NULL, S_BASE_ILLUSION, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"summoning","SUMM",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::FOUNDATION, - NULL, NULL, S_BASE_SUMMONING, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"patterning","PTTN",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::FOUNDATION, - NULL, NULL, S_BASE_PATTERNING, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"mysticism","MYST",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::FOUNDATION, - NULL, NULL, S_BASE_MYSTICISM, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"battletraining","BATT",100, - SkillType::MAGIC | SkillType::BATTLEREP | SkillType::DISABLED, - NULL, NULL, S_BASE_BATTLETRAINING, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"charisma","CHAR",100, - SkillType::MAGIC | SkillType::DISABLED, - NULL, NULL, S_BASE_CHARISMA, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, - {"artifact lore","ARTL",100, - SkillType::MAGIC | SkillType::DISABLED | SkillType::FOUNDATION, - NULL, NULL, S_BASE_ARTIFACTLORE, - {{NULL,0},{NULL,0},{NULL,0}}, - 3, 0, 0}, // cost for (level) AMPRs or SHSTs. - {"quartermastery", "QUAT", 100, - SkillType::MAGIC | SkillType::DISABLED, - NULL, NULL, -1, - {{"TRAD", 4}, {NULL, 0}, {NULL, 0}}, - 0, 0, 0}, - {"construction","CONS",10, - SkillType::DISABLED, - NULL,NULL, -1, - {{NULL,0},{NULL,0},{NULL,0}}, - 0, 0, 0}, -}; - -SkillType *SkillDefs = sd; - -// -// Table of objects. -// -static ObjectType ot[] = -{ - // - // name, - // flags, - // protect,capacity,sailors,maxMages,speed - // item,cost,skill,level - // max maintenance, max monthly decay, maintenance factor - // monster, productionaided - // defencearray (ATTACK_COMBAT, ATTACK_ENERGY, ATTACK_SPIRIT, - // ATTACK_WEATHER, ATTACK_RIDING and ATTACK_RANGED) - // hexside, sailable, oceanbonus - {"None", - ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0, 0, 0, - -1, -1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Coracle", - ObjectType::DISABLED | ObjectType::NEVERDECAY | - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,20,3,0,4, - I_FUR,3,"SHIP",1, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,3,-3}, - {"Longboat", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 0,200,5,0,5, - I_WOOD,25,"SHIP",1, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,3,0}, - {"Junk", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 0,1800,15,0,5, - I_WOOD,75,"SHIP",1, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,2,-2}, - {"Merchant Ship", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 0,800,10,0,7, - I_WOOD,50,"SHIP",1, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,2,-3}, - {"Trireme", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 0,800,10,0,8, - I_WOOD,50,"SHIP",1, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,3,1}, - {"Armoured Trireme", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 200,1800,15,15,8, - I_IRONWOOD,75,"SHIP",3, - 0,0,0, - -1,-1, - {2,2,2,2,2,2}, - 1,3,2}, - {"Treasure Ark", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 0,10000,100,1,4, - I_IRONWOOD,75,"SHIP",3, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,2,-3}, - {"Barge", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,4000,15,0,6, - I_WOOD,75,"SHIP",1, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,1,0}, - {"Balloon", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD | ObjectType::SAILOVERLAND, - 0,800,10,0,6, - I_FLOATER,50,"SHIP",5, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 0,0,-2}, - {"Tower", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 10,0,0,10,0, - I_STONE,10,"BUIL",1, - 5,1,2, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - {"Fort", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 50,0,0,20,0, - I_STONE,40,"BUIL",1, - 20,4,3, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - {"Castle", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 250,0,0,50,0, - I_STONE,160,"BUIL",1, - 80,6,3, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - {"Citadel", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 1250,0,0,100,0, - I_STONE,640,"BUIL",1, - 400,10,4, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - {"Magical Fortress", - ObjectType::NEVERDECAY | ObjectType::CANENTER | ObjectType::CANMODIFY, - 250,0,0,60,0, - I_ROOTSTONE,160,"BUIL",3, - 0,0,0, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - {"Shaft", - ObjectType::CANENTER | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Lair", - ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_TRENT,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Ruin", - ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_CENTAUR,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Cave", - ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_DRAGON,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Demon Pit", - ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_IMP,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Crypt", - ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_SKELETON,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Mine", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"MINI",3, - 5,1,2, - -1,I_IRON, - {0,0,0,0,0,0}, - 0,0,0}, - {"Farm", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"FARM",3, - 5,1,2, - -1,I_GRAIN, - {0,0,0,0,0,0}, - 0,0,0}, - {"Ranch", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"RANC",3, - 5,1,2, - -1,I_LIVESTOCK, - {0,0,0,0,0,0}, - 0,0,0}, - {"Timber Yard", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"LUMB",3, - 5,1,2, - -1,I_WOOD, - {0,0,0,0,0,0}, - 0,0,0}, - {"Inn", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"BUIL",3, - 5,1,2, - -1,I_SILVER, - {0,0,0,0,0,0}, - 0,0,0}, - {"Quarry", - ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"QUAR",3, - 5,1,2, - -1,I_STONE, - {0,0,0,0,0,0}, - 0,0,0}, - // LLS - // Added ocean lairs. - {"Island", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_PIRATES,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Derelict Ship", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_KRAKEN,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Cavern", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_MERFOLK,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Whirlpool", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_ELEMENTAL,-1, - {0,0,0,0,0,0}, - 0,0,0}, - // AS - {"Temple", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,10,"BUIL",3, - 5,1,2, - -1,I_HERBS, - {0,0,0,0,0,0}, - 0,0,0}, - {"Mystic Quarry", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_ROOTSTONE,20,"QUAR",3, - 10,2,2, - -1,I_ROOTSTONE, - {0,0,0,0,0,0}, - 0,0,0}, - {"Arcane Mine", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_MITHRIL,20,"MINI",3, - 10,2,2, - -1,I_MITHRIL, - {0,0,0,0,0,0}, - 0,0,0}, - {"Forest Preserve", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_IRONWOOD,20,"LUMB",3, - 10,2,2, - -1,I_IRONWOOD, - {0,0,0,0,0,0}, - 0,0,0}, - {"Sacred Grove", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_YEW,30,"LUMB",5, - 15,2,2, - -1,I_YEW, - {0,0,0,0,0,0}, - 0,0,0}, - // JT - // Added Abyss Lair - {"Black Keep", - ObjectType::NOMONSTERGROWTH | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_BALROG,-1, - {0,0,0,0,0,0}, - 0,0,0}, - // Added for citadel replacement in conquest - {"Palace", - ObjectType::CANENTER | ObjectType::NEVERDECAY | ObjectType::CANMODIFY, - 1250,0,0,200,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - // Added for Ceran - {"Dragon Cliffs", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 1,0,0,0,0, - I_ROOTSTONE,100,"DRAG",3, - 50,5,2, - I_DRAGON,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Magical Tower", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 10,0,0,10,0, - I_ROOTSTONE,10,"BUIL",2, - 5,1,2, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - {"War Galleon", - ObjectType::DISABLED | ObjectType::NEVERDECAY | ObjectType::CANENTER | - ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 350,2500,15,30,8, - I_YEW,75,"SHIP",5, - 0,0,0, - -1,-1, - {2,2,2,2,2,2}, - 1,2,0}, - {"Hermits hut", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 1,0,0,1,0, - I_IRONWOOD,3,"BUIL",3, - 1,1,1, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Stockade", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 50,0,0,5,0, - I_WOOD,60,"BUIL",1, - 30,3,2, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Cloud Palace", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::NEVERDECAY, - 200,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Necromancers Guild", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::NEVERDECAY, - 10,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Artificers Guild", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::NEVERDECAY, - 10,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Ancient Temple", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::NEVERDECAY, - 8,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_SKELETON,I_HERBS, - {0,0,0,0,0,0}, - 0,0,0}, - {"Hexagonal Tower", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::NEVERDECAY | - ObjectType::CANMODIFY, - 7,0,0,2,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {2,2,2,2,2,2}, - 0,0,0}, - // Tzargs new monsters - {"Magician's Tower", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_MAGICIANS,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Dark Mage Tower", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_DARKMAGE,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Giant's Castle", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_STORMGIANT,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Lair", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_ILLYRTHID,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Ice Cave", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_ICEDRAGON,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Bog", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - I_HYDRA,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Trapping Hut", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"HUNT",3, - 10,2,2, - -1,I_FUR, - {0,0,0,0,0,0}, - 0,0,0}, - {"Stables", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"HORS",3, - 10,2,2, - -1,I_HORSE, - {0,0,0,0,0,0}, - 0,0,0}, - {"Fish Trap", -// BS Sailing Mod - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY | ObjectType::OCEANBUILD, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"FISH",3, - 10,2,2, - -1,I_FISH, - {0,0,0,0,0,0}, - 0,0,-3}, - {"Mythic Stables", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_IRONWOOD,10,"HORS",5, - 10,2,2, - -1,I_WHORSE, - {0,0,0,0,0,0}, - 0,0,0}, - {"Trapping Lodge", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_IRONWOOD,10,"HUNT",5, - 10,2,2, - -1,I_FLOATER, - {0,0,0,0,0,0}, - 0,0,0}, - {"Faerie Ring", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_MUSHROOM,10,"HERB",3, - 10,2,2, - -1,I_MUSHROOM, - {0,0,0,0,0,0}, - 0,0,0}, - {"Alchemist Lab", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_ADMANTIUM,10,"MINI",5, - 10,2,2, - -1,I_ADMANTIUM, - {0,0,0,0,0,0}, - 0,0,0}, - {"Oasis", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_YEW,10,"CAME",3, - 10,2,2, - -1,I_CAMEL, - {0,0,0,0,0,0}, - 0,0,0}, - {"Gem Appraiser", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,10,"MINI",3, - 10,2,2, - -1,I_ROUGHGEM, - {0,0,0,0,0,0}, - 0,0,0}, - {"Hexagonal Portal Tower", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 7,0,0,1,0, - I_IRONWOOD,25,NULL,0, - 25,2,3, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Bank", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_WOOD_OR_STONE,30,"BUIL",3, - 30,2,2, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Caravanserai", - ObjectType::DISABLED | ObjectType::CANENTER | - ObjectType::CANMODIFY | ObjectType::TRANSPORT, - 0, 0, 0, 0,0, - I_WOOD_OR_STONE, 20, "BUIL", 2, - 15, 3, 3, - -1, -1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Magical Portal", - ObjectType::DISABLED | ObjectType::CANENTER | - ObjectType::CANMODIFY, - 0, 0, 0, 0,1, - -1, 0, NULL, 0, - 0, 0, 0, - -1, -1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Message Stone", - ObjectType::DISABLED | ObjectType::NEVERDECAY, - 0, 0, 0, 0,1, - -1, 0, NULL, 0, - 0, 0, 0, - -1, -1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Road N", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,75,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Road NW", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,75,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Road NE", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,75,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Road SW", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,75,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Road SE", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,75,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, - {"Road S", - ObjectType::DISABLED | ObjectType::CANENTER | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,75,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 0,0,0}, -/* {"Road", - ObjectType::DISABLED | ObjectType::CANMODIFY, - 0,0,0,0,0, - I_STONE,100,"BUIL",3, - 24,6,4, - -1,-1, - {0,0,0,0,0,0}, - 1,0,-1,0,0,0,O_ROAD}, - {"River", - ObjectType::DISABLED, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,1,0,1,0,0,O_RIVER}, - {"Ravine", - ObjectType::DISABLED, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,4,0,1,0,0,O_RAVINE}, - {"Cliff", - ObjectType::DISABLED, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,4,0,1,0,0,O_CLIFF}, - {"Beach", - ObjectType::DISABLED, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,1,0,0,0,0,O_BEACH}, - {"Rocks", - ObjectType::DISABLED, - 0,0,0,0,0, - -1,0,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,4,0,1,0,0,O_ROCKS}, - {"Harbour", - ObjectType::DISABLED, - 0,0,0,0,0, - I_WOOD,100,"BUIL",3, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,3,0,1,0,0,O_HARBOUR}, - {"Bridge", - ObjectType::DISABLED, - 0,0,0,0,0, - I_WOOD_OR_STONE,100,"BUIL",5, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,0,0,2,3,2,O_BRIDGE}, - {"Wall", - ObjectType::DISABLED, - 0,0,0,0,0, - I_STONE,200,"BUIL",3, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,4,0,0,0,0,O_OWALL}, - {"Sheer Wall", - ObjectType::DISABLED, - 0,0,0,0,0, - -1,200,NULL,0, - 0,0,0, - -1,-1, - {0,0,0,0,0,0}, - 1,4,0,0,3,2,O_IWALL}, */ -}; - -ObjectType *ObjectDefs = ot; - - -// -// Table of hexside terrains -// -static HexsideType ht[] = -{ - // - // name, - // flags, - // item,cost,skill,level, - // sailable, movement multiplier, block (-1 bridge, 0 none, 1 can be bridged, 2+ cannot be bridged), stealth penalty, combat penalty - // exclusive - {"None", - 0, - -1,0,NULL,0, - 0,0,0,0,0, - 1}, - {"Rocks", - 0, - -1,0,NULL,0, - 0,0,2,0,0, - 1}, - {"Beach", - 0, - -1,0,NULL,0, - 1,0,0,0,0, - 1}, - {"Harbour", - 0, - I_WOOD_OR_STONE,200,"BUIL",5, - 3,0,0,0,0, - 1}, - {"River", - 0, - -1,0,NULL,0, - 1,0,1,0,0, - 1}, - {"Ravine", - 0, - -1,0,NULL,0, - 0,0,1,0,0, - 1}, - {"Cliff", - HexsideType::DISABLED, - -1,0,NULL,0, - 0,0,2,0,0, - 1}, - {"Road", - 0, - I_STONE,50,"BUIL",3, - 0,-1,0,0,0, - 0}, - {"Bridge", - 0, - I_WOOD_OR_STONE,40,"BUIL",3, - 0,0,-1,2,1, - 0}, -}; - -HexsideType *HexsideDefs = ht; - - - -// -// Table of terrain types. -// -static TerrainType td[] = { - // - // name, type, similar_type, - // flags, - // pop, wages, economy, movepoints, - // product array - // normal races array - // coastal races array - // wmonfreq, smallmon, bigmon, humanoid, - // lairChance, lair array - // - {"ocean", "ocean", '-', R_OCEAN, - TerrainType::FLYINGMOUNTS | TerrainType::RESTRICTEDFOOT | TerrainType::ENHANCEDRANGED, - 0,0,0,1, - {{I_FISH,100,20},{-1,0,0},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_MERMEN,-1,-1,-1}, - {-1,-1,-1}, - 1,I_PIRATES,I_KRAKEN,I_MERFOLK, - 5,{O_ISLE,O_DERELICT,O_OCAVE,O_WHIRL,-1,-1}}, - {"plain", "plain", 'p', R_PLAIN, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS, - 800,14,40,1, - {{I_HORSE,100,20},{I_WHORSE,25,5},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_NOMAD,I_HIGHELF,-1}, - {I_VIKING,I_SEAELF,-1}, - 1,I_LION,-1,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1,-1}}, - {"forest", "forest", 'f', R_FOREST, - TerrainType::RIDINGMOUNTS | TerrainType::RIDINGLIMITED | TerrainType::FLYINGMOUNTS | TerrainType::FLYINGLIMITED | TerrainType::RESTRICTEDRANGED, - 400,12,20,2, - {{I_WOOD,100,20},{I_FUR,100,10},{I_HERBS,100,10},{I_IRONWOOD,25,5}, - {I_YEW,25,5},{-1,0,0},{-1,0,0}}, - {I_WOODELF,I_VIKING,-1,-1}, - {I_SEAELF,-1,-1}, - 2,I_WOLF,I_TRENT,I_KOBOLD, - 10,{O_LAIR,O_RUIN,O_CRYPT,-1,-1,-1}}, - {"mountain", "mountain", 'm', R_MOUNTAIN, - TerrainType::FLYINGMOUNTS | TerrainType::RESTRICTEDFOOT, - 400,12,20,2, - {{I_IRON,100,20},{I_STONE,100,10},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,5,5},{-1,0,0},{-1,0,0}}, - {I_BARBARIAN,I_HILLDWARF,I_ORC,-1}, - {I_VIKING,I_SEAELF,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 15,{O_LAIR, O_RUIN, O_CAVE, O_CRYPT,O_MAGETOWER,O_GIANTCASTLE}}, - {"swamp", "swamp", 's', R_SWAMP, - TerrainType::FLYINGMOUNTS | TerrainType::FLYINGLIMITED, - 200,11,10,2, - {{I_WOOD,100,10},{I_FLOATER,25,10},{I_HERBS,100,10},{I_MUSHROOM,10,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,-1,-1}, - {I_VIKING,I_SEAELF,-1}, - 2,I_CROCODILE,I_BTHING,I_LMEN, - 15,{O_LAIR, O_RUIN, O_CRYPT, O_BOG, -1, -1 }}, - {"jungle", "jungle", 'j', R_JUNGLE, - TerrainType::RESTRICTEDFOOT | TerrainType::RESTRICTEDRANGED, - 200,11,20,2, - {{I_WOOD,100,10},{I_HERBS,100,20},{I_MUSHROOM,25,5},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,I_WOODELF,-1}, - {I_SEAELF,-1,-1}, - 2,I_ANACONDA,I_KONG,I_WMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"desert", "desert", 'd', R_DESERT, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::ENHANCEDRANGED, - 200,11,10,1, - {{I_IRON,100,10},{I_STONE,100,10},{I_ROOTSTONE,25,5},{I_CAMEL,50,10}, - {I_ADMANTIUM,3,3},{-1,0,0},{-1,0,0}}, - {I_NOMAD,I_DESERTDWARF,-1,-1}, - {I_SEAELF,I_VIKING,-1}, - 2,I_SCORPION,I_SPHINX,I_SANDLING, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1}}, - {"tundra", "tundra", 't', R_TUNDRA, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS, - 200,11,10,2, - {{I_FUR,100,10},{I_HERBS,100,10},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_ESKIMO,I_ICEDWARF,-1,-1}, - {I_SEAELF,I_VIKING,-1}, - 2,I_PBEAR,I_IWURM,I_YETI, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_ICECAVE,-1,-1}}, - {"cavern", "cavern", 'c', R_CAVERN, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 100,11,10,1, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,10,5},{-1,0,0},{-1,0,0}}, - {I_DARKMAN,I_UNDERDWARF,I_ORC,I_GREYELF}, - {-1,-1,-1}, - 3,I_RAT,I_DRAGON,I_GOBLIN, - 20,{O_LAIR,O_RUIN,O_CAVE,O_GIANTCASTLE,O_ILAIR,O_DARKTOWER}}, - {"underforest", "uforest", 'u', R_UFOREST, - TerrainType::RIDINGMOUNTS | TerrainType::RIDINGLIMITED | TerrainType::FLYINGMOUNTS | TerrainType::FLYINGLIMITED | TerrainType::RESTRICTEDRANGED | TerrainType::DISABLED, - 100,11,10,2, - {{I_WOOD,100,10},{I_STONE,100,10},{I_IRON,100,10},{I_MUSHROOM,20,10}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_DARKMAN,I_UNDERDWARF,I_ORC,I_GREYELF}, - {-1,-1,-1}, - 3,I_SPIDER,I_DRAGON,I_TROLL, - 20,{O_LAIR,O_RUIN,O_CAVE,O_MAGETOWER,O_ILAIR,O_DARKTOWER}}, - {"tunnels", "tunnels", 't', R_TUNNELS, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 0,0,0,2, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_MUSHROOM,10,5},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 5,I_LIZARD,I_DRAGON,I_ETTIN, - 20,{O_LAIR,O_RUIN,O_CAVE,O_DEMONPIT,O_MAGETOWER,O_GIANTCASTLE}}, - {"grotto", "grotto", 'g', R_GROTTO, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 100,11,12,2, - {{I_MUSHROOM,25,10},{I_ROOTSTONE,25,10},{I_ADMANTIUM,30,10},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_MINOTAUR,I_UNDERDWARF,I_ORC,I_GREYELF}, - {I_DROWMAN,-1,-1}, - 15,I_DEMON,I_DRAGON,I_ETTIN, - 25,{O_LAIR,O_RUIN,O_CAVE,O_GIANTCASTLE,O_ILAIR,O_DARKTOWER}}, - {"deepforest", "deepforest", 'd', R_DFOREST, - TerrainType::RESTRICTEDFOOT | TerrainType::RESTRICTEDRANGED | TerrainType::DISABLED, - 100,11,12,3, - {{I_WOOD,100,10},{I_STONE,100,10},{I_IRON,100,10},{I_MUSHROOM,100,20}, - {I_ROUGHGEM,10,10},{-1,0,0},{-1,0,0}}, - {I_DROWMAN,I_UNDERDWARF,I_ORC,I_GREYELF}, - {-1,-1,-1}, - 15,I_DEMON,I_DRAGON,I_TROLL, - 25,{O_RUIN,O_CAVE,O_DEMONPIT,O_MAGETOWER,O_ILAIR,O_DARKTOWER}}, - {"chasm", "chasm", 'c', R_CHASM, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 0,0,0,3, - {{I_ROUGHGEM,10,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_MUSHROOM,10,10}, - {I_ROOTSTONE,25,5},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 25,I_DEMON,I_DRAGON,I_ETTIN, - 25,{O_LAIR,O_RUIN,O_CAVE,O_DEMONPIT,O_MAGETOWER,O_GIANTCASTLE}}, - {"nexus", "nexus", 'x', R_NEXUS, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS, - 0,0,0,1, - {{-1,0,0},{-1,0,0},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 0,-1,-1,-1, - 0,{-1,-1,-1,-1,-1,-1}}, - {"paradise", "paradise", 'x', R_PARADISE, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS, - 800,14,40,1, - {{I_HORSE,100,20},{I_WHORSE,25,5},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_NOMAD,I_HIGHELF,-1}, - {I_VIKING,I_SEAELF,-1}, - 1,I_LION,-1,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1,-1}}, - // Terrain types for the conquest islands - {"plain", "island_plain", 'a', R_PLAIN, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 800,14,40,1, - {{I_HORSE,100,20},{I_WHORSE,25,5},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_NOMAD,I_HIGHELF,-1}, - {I_VIKING,I_SEAELF,-1}, - 1,I_LION,-1,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1,-1}}, - {"swamp", "island_swamp", 'w', R_SWAMP, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,2, - {{I_WOOD,100,10},{I_FLOATER,25,10},{I_HERBS,100,10},{I_MUSHROOM,10,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,-1,-1}, - {I_VIKING,I_SEAELF,-1}, - 2,I_CROCODILE,I_BTHING,I_LMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"mountain", "island_mountain", 'n', R_MOUNTAIN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_IRON,100,20}, {I_STONE,100,10},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,5,5},{-1,0,0},{-1,0,0}}, - {I_BARBARIAN,I_HILLDWARF,I_ORC,-1}, - {I_VIKING,I_SEAELF,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 15,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,O_GIANTCASTLE}}, - // Additional terrains for Ceran - // Only races differ. Everything else is done in ceran/extra.cpp - {"plain", "ceran_plain1", 'p', R_PLAIN, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 800,14,40,1, - {{I_HORSE,100,20},{I_WHORSE,25,5},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_NOMAD,I_GNOME,I_GOBLINMAN}, - {I_VIKING,I_HOBBIT,-1}, - 1,I_LION,-1,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1,-1}}, - {"plain", "ceran_plain2", 'p', R_PLAIN, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 800,14,40,1, - {{I_HORSE,100,20},{I_WHORSE,25,5},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_NOMAD,I_HIGHELF,I_GNOME}, - {I_SEAELF,I_HOBBIT,-1}, - 1,I_LION,-1,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1,-1}}, - {"plain", "ceran_plain3", 'p', R_PLAIN, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 800,14,40,1, - {{I_HORSE,100,20},{I_WHORSE,25,5},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_NOMAD,I_HIGHELF,I_GOBLINMAN}, - {I_VIKING,I_HOBBIT,-1}, - 1,I_LION,I_RAT,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1,-1}}, - {"forest", "ceran_forest1", 'f', R_FOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_WOOD,100,20},{I_FUR,100,10},{I_HERBS,100,10},{I_IRONWOOD,25,5}, - {I_YEW,25,5},{-1,0,0},{-1,0,0}}, - {I_WOODELF,I_VIKING,I_HIGHELF,I_GOBLINMAN}, - {I_HIGHELF,I_WOODELF,-1}, - 2,I_WOLF,I_TRENT,I_KOBOLD, - 10,{O_LAIR,O_RUIN,O_CRYPT,-1,-1,-1}}, - {"forest", "ceran_forest2", 'f', R_FOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_WOOD,100,20},{I_FUR,100,10},{I_HERBS,100,10},{I_IRONWOOD,25,5}, - {I_YEW,25,5},{-1,0,0},{-1,0,0}}, - {I_WOODELF,I_VIKING,I_HIGHELF,-1}, - {I_SEAELF,I_VIKING,-1}, - 2,I_WOLF,I_TRENT,I_KOBOLD, - 10,{O_LAIR,O_RUIN,O_CRYPT,-1,-1,-1}}, - {"forest", "ceran_forest3", 'f', R_FOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_WOOD,100,20},{I_FUR,100,10},{I_HERBS,100,10},{I_IRONWOOD,25,5}, - {I_YEW,25,5},{-1,0,0},{-1,0,0}}, - {I_WOODELF,I_GNOLL,I_HIGHELF,-1}, - {I_SEAELF,I_WOODELF,-1}, - 8,I_WOLF,I_TRENT,I_KOBOLD, - 10,{O_LAIR,O_RUIN,O_CRYPT,-1,-1,-1}}, - {"mystforest", "ceran_mforest", 'y', R_CERAN_MYSTFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_WOOD,100,20},{I_FUR,50,15},{I_HERBS,50,20},{I_IRONWOOD,50,10}, - {I_YEW,50,10},{-1,0,0},{-1,0,0}}, - {I_WOODELF,-1,-1,-1}, - {I_WOODELF,I_SEAELF,-1}, - 8,I_WOLF,I_TRENT,I_KOBOLD, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_CAVE,O_MAGETOWER,-1}}, - {"mystforest", "ceran_mforest1", 'y', R_CERAN_MYSTFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 1000,12,20,2, - {{I_WOOD,100,20},{I_FUR,50,15},{I_HERBS,50,20},{I_IRONWOOD,50,10}, - {I_YEW,50,10},{-1,0,0},{-1,0,0}}, - {I_WOODELF,I_WOODELF,I_HIGHELF,I_WOODELF}, - {I_WOODELF,I_SEAELF,-1}, - 8,I_TRENT,I_TRENT,I_KOBOLD, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_CAVE,O_MAGETOWER,-1}}, - {"mystforest", "ceran_mforest2", 'y', R_CERAN_MYSTFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 2000,15,20,2, - {{I_WOOD,100,20},{I_FUR,50,15},{I_HERBS,50,20},{I_IRONWOOD,50,10}, - {I_YEW,50,10},{-1,0,0},{-1,0,0}}, - {I_TITAN,I_WOODELF,-1,-1}, - {-1,-1,-1}, - 20,I_ETTIN,I_TRENT,I_ETTIN, - 20,{O_LAIR,O_RUIN,O_CRYPT,O_CAVE,O_MAGETOWER,-1}}, - {"mountain", "ceran_mountain1", 'm', R_MOUNTAIN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_IRON,100,20},{I_STONE,100,10},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,5,5},{-1,0,0},{-1,0,0}}, - {I_BARBARIAN,I_HILLDWARF,I_ICEDWARF,I_HIGHLANDER}, - {I_GNOLL,I_MINOTAUR,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 15,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,O_GIANTCASTLE}}, - {"mountain", "ceran_mountain2", 'm', R_MOUNTAIN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_IRON,100,20},{I_STONE,100,10},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,5,5},{-1,0,0},{-1,0,0}}, - {I_HIGHLANDER,I_HILLDWARF,I_ORC,I_GOBLINMAN}, - {I_GNOLL,I_HIGHLANDER,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 15,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,O_GIANTCASTLE}}, - {"mountain", "ceran_mountain3", 'm', R_MOUNTAIN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 500,12,20,2, - {{I_IRON,100,20},{I_STONE,100,10},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,5,5},{-1,0,0},{-1,0,0}}, - {I_BARBARIAN,I_HILLDWARF,I_ORC,I_GOBLINMAN}, - {I_URUK,I_GNOLL,-1}, - 4,I_GBEAR,I_ROC,I_OGRE, - 18,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,O_GIANTCASTLE}}, - {"hill", "ceran_hill", 'h', R_CERAN_HILL, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_IRON,80,15},{I_STONE,100,30},{I_MITHRIL,10,5},{I_ROOTSTONE,25,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_HOBBIT,I_HIGHLANDER,I_GOBLINMAN,I_OGREMAN}, - {I_HOBBIT, I_GNOLL,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 12,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,-1}}, - {"hill", "ceran_hill1", 'h', R_CERAN_HILL, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_IRON,80,15},{I_STONE,100,30},{I_MITHRIL,10,5},{I_ROOTSTONE,25,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_OGREMAN,I_HILLDWARF,I_GOBLINMAN,-1}, - {I_HOBBIT, I_GNOLL,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 12,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,-1}}, - {"hill", "ceran_hill2", 'h', R_CERAN_HILL, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 400,12,20,2, - {{I_IRON,80,15},{I_STONE,100,30},{I_MITHRIL,10,5},{I_ROOTSTONE,25,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_HOBBIT,I_HILLDWARF,I_GOBLINMAN,-1}, - {I_HOBBIT,I_GNOLL,-1}, - 2,I_GBEAR,I_ROC,I_OGRE, - 12,{O_LAIR,O_RUIN,O_CAVE,O_CRYPT,O_MAGETOWER,-1}}, - {"swamp", "ceran_swamp1", 's', R_SWAMP, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,2, - {{I_WOOD,100,10},{I_FLOATER,25,10},{I_HERBS,100,10},{I_MUSHROOM,10,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,I_LIZARDMAN,I_AMAZON}, - {I_LIZARDMAN,-1,-1}, - 2,I_CROCODILE,I_BTHING,I_LMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"swamp", "ceran_swamp2", 's', R_SWAMP, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 300,11,10,2, - {{I_WOOD,100,10},{I_FLOATER,25,10},{I_HERBS,100,10},{I_MUSHROOM,10,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,I_LIZARDMAN,I_GOBLINMAN}, - {I_LIZARDMAN,-1,-1}, - 2,I_CROCODILE,I_BTHING,I_LMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"swamp", "ceran_swamp3", 's', R_SWAMP, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,2, - {{I_WOOD,100,10},{I_FLOATER,25,10},{I_HERBS,100,10},{I_MUSHROOM,10,5}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,I_OGREMAN,I_GOBLINMAN}, - {I_VIKING,-1,-1}, - 2,I_CROCODILE,I_BTHING,I_LMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"jungle", "ceran_jungle1", 'j', R_JUNGLE, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,20,2, - {{I_WOOD,100,10},{I_HERBS,100,20},{I_MUSHROOM,25,5},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_TRIBALELF,I_AMAZON,I_WOODELF}, - {I_LIZARDMAN,I_AMAZON,-1}, - 6,I_ANACONDA,I_KONG,I_WMEN, - 18,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"jungle", "ceran_jungle2", 'j', R_JUNGLE, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,20,2, - {{I_WOOD,100,10},{I_HERBS,100,20},{I_MUSHROOM,25,5},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_AMAZON,I_TRIBALELF,I_WOODELF,I_GOBLINMAN}, - {I_SEAELF,I_AMAZON,-1}, - 2,I_ANACONDA,I_KONG,I_WMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"jungle", "ceran_jungle3", 'j', R_JUNGLE, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,20,2, - {{I_WOOD,100,10},{I_HERBS,100,20},{I_MUSHROOM,25,5},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_TRIBESMAN,I_AMAZON,I_WOODELF,I_TRIBALELF}, - {I_SEAELF,I_AMAZON,-1}, - 2,I_ANACONDA,I_KONG,I_WMEN, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_BOG,-1,-1}}, - {"desert", "ceran_desert1", 'd', R_DESERT, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,1, - {{I_IRON,100,15},{I_STONE,100,5},{I_ROOTSTONE,25,5},{I_CAMEL,50,10}, - {I_ADMANTIUM,3,3},{-1,0,0},{-1,0,0}}, - {I_NOMAD,I_DESERTDWARF,I_GOBLINMAN,-1}, - {I_URUK,I_VIKING,-1}, - 2,I_SCORPION,I_DEMON,I_SANDLING, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1}}, - {"desert", "ceran_desert2", 'd', R_DESERT, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,1, - {{I_IRON,100,5},{I_STONE,100,15},{I_ROOTSTONE,25,5},{I_CAMEL,50,10}, - {I_ADMANTIUM,3,3},{-1,0,0},{-1,0,0}}, - {I_NOMAD,I_DESERTDWARF,I_GOBLINMAN,-1}, - {I_VIKING,-1,-1}, - 2,I_SCORPION,I_DEMON,I_SANDLING, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1}}, - {"desert", "ceran_desert3", 'd', R_DESERT, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,1, - {{I_IRON,100,10},{I_STONE,100,10},{I_ROOTSTONE,25,10},{I_CAMEL,50,10}, - {I_ADMANTIUM,3,3},{-1,0,0},{-1,0,0}}, - {I_NOMAD,I_DESERTDWARF,-1,-1}, - {I_VIKING,I_URUK,-1}, - 4,I_SCORPION,I_DRAGON,I_SANDLING, - 18,{O_LAIR,O_RUIN,O_CRYPT,O_MAGETOWER,-1,-1}}, - {"wasteland", "ceran_waste", 'z', R_CERAN_WASTELAND, - TerrainType::RIDINGMOUNTS | TerrainType::DISABLED, - 100,11,10,1, - {{I_IRON,20,10},{I_STONE,20,10},{I_ROOTSTONE,20,5},{I_MITHRIL,10,20}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_DESERTDWARF,-1,-1,-1}, - {I_URUK,-1,-1}, - 5,I_RRAT,I_NOOGLE,I_MUTANT, - 10,{O_LAIR,O_RUIN,O_CRYPT,O_DEMONPIT,O_DARKTOWER,O_MAGETOWER}}, - {"wasteland", "ceran_waste1", 'z', R_CERAN_WASTELAND, - TerrainType::RIDINGMOUNTS | TerrainType::DISABLED, - 100,11,10,1, - {{I_IRON,20,10},{I_STONE,20,10},{I_ROOTSTONE,20,5},{I_MITHRIL,10,20}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_DESERTDWARF,I_URUK,-1,-1}, - {I_URUK,-1,-1}, - 10,I_RRAT,I_NOOGLE,I_MUTANT, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_DEMONPIT,O_DARKTOWER,O_MAGETOWER}}, - {"lake", "ceran_lake", 'l', R_CERAN_LAKE, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 800,18,50,1, - {{I_HORSE,100,10},{I_WHORSE,45,5},{I_FISH,100,10},{I_MUSHROOM,10,10}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_PLAINSMAN,I_HOBBIT,I_HIGHELF,I_GNOME}, - {I_VIKING,I_HOBBIT,I_FAIRY}, - 4,I_LION,I_ETTIN,I_CENTAUR, - 10,{O_RUIN,O_CRYPT,O_LAIR,-1,-1,-1}}, - {"tundra", "ceran_tundra1", 't', R_TUNDRA, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,2, - {{I_FUR,100,10},{I_HERBS,100,10},{I_WOOD,10,4},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_ESKIMO,I_ICEDWARF,I_GNOLL,-1}, - {I_ESKIMO,I_VIKING,-1}, - 2,I_PBEAR,I_IWURM,I_YETI, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_ICECAVE,-1,-1}}, - {"tundra", "ceran_tundra2", 't', R_TUNDRA, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,2, - {{I_FUR,100,10},{I_HERBS,100,10},{I_STONE,10,4},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_ESKIMO,I_ICEDWARF,I_GNOLL,-1}, - {I_ICEDWARF,I_VIKING,-1}, - 2,I_PBEAR,I_IWURM,I_YETI, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_ICECAVE,-1,-1}}, - {"tundra", "ceran_tundra3", 't', R_TUNDRA, - TerrainType::RIDINGMOUNTS | TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,11,10,2, - {{I_FUR,100,10},{I_HERBS,100,10},{I_IRON,10,4},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_ESKIMO,I_GNOLL,I_MINOTAUR,-1}, - {I_GNOLL,I_MINOTAUR,-1}, - 2,I_PBEAR,I_IWURM,I_YETI, - 15,{O_LAIR,O_RUIN,O_CRYPT,O_ICECAVE,-1,-1}}, - {"cavern", "ceran_cavern1", 'c', R_CAVERN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 100,12,10,1, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,10,5},{-1,0,0},{-1,0,0}}, - {I_DARKMAN,I_OGREMAN,I_ORC,I_GREYELF}, - {-1,-1,-1}, - 4,I_RAT,I_DRAGON,I_GOBLIN, - 15,{O_LAIR,O_RUIN,O_CAVE,O_GIANTCASTLE,O_ILAIR,O_DARKTOWER}}, - {"cavern", "ceran_cavern2", 'c', R_CAVERN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 150,13,10,1, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,10},{I_ROOTSTONE,25,10}, - {I_ADMANTIUM,10,5},{-1,0,0},{-1,0,0}}, - {I_MINOTAUR,I_UNDERDWARF,-1,-1}, - {-1,-1,-1}, - 5,I_RAT,I_DRAGON,I_GOBLIN, - 15,{O_LAIR,O_RUIN,O_CAVE,O_GIANTCASTLE,O_ILAIR,O_DARKTOWER}}, - {"cavern", "ceran_cavern3", 'c', R_CAVERN, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 500,13,10,1, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,10,5},{-1,0,0},{-1,0,0}}, - {I_DROWMAN,I_GREYELF,-1,-1}, - {-1,-1,-1}, - 6,I_RAT,I_DRAGON,I_GOBLIN, - 20,{O_LAIR,O_RUIN,O_CAVE,O_GIANTCASTLE,O_ILAIR,O_DARKTOWER}}, - {"underforest", "ceran_uforest1", 'u', R_UFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 100,12,10,2, - {{I_WOOD,100,10},{I_STONE,100,10},{I_IRON,100,10},{I_MUSHROOM,20,10}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_DROWMAN,I_ORC,I_GREYELF,-1}, - {-1,-1,-1}, - 3,I_SPIDER,I_DRAGON,I_TROLL, - 20,{O_LAIR,O_RUIN,O_CAVE,O_MAGETOWER,O_ILAIR,O_DARKTOWER}}, - {"underforest", "ceran_uforest2", 'u', R_UFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,12,10,2, - {{I_WOOD,100,10},{I_STONE,100,10},{I_IRON,100,10},{I_MUSHROOM,20,10}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_UNDERDWARF,I_ORC,I_DROWMAN,I_GREYELF}, - {-1,-1,-1}, - 6,I_SPIDER,I_DRAGON,I_TROLL, - 20,{O_LAIR,O_RUIN,O_CAVE,O_MAGETOWER,O_ILAIR,O_DARKTOWER}}, - {"underforest", "ceran_uforest3", 'u', R_UFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 500,11,10,2, - {{I_WOOD,100,10},{I_STONE,100,10},{I_IRON,100,10},{I_MUSHROOM,20,10}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_DROWMAN,I_GREYELF,-1,-1}, - {-1,-1,-1}, - 9,I_SPIDER,I_DRAGON,I_TROLL, - 25,{O_LAIR,O_RUIN,O_CAVE,O_MAGETOWER,O_ILAIR,O_DARKTOWER}}, - {"tunnels", "ceran_tunnel1", 't', R_TUNNELS, - TerrainType::DISABLED, - 0,0,0,2, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_MUSHROOM,10,5},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 7,I_LIZARD,I_DRAGON,I_ETTIN, - 20,{O_LAIR,O_RUIN,O_CAVE,O_DEMONPIT,O_MAGETOWER,O_GIANTCASTLE}}, - {"tunnels", "ceran_tunnel2", 't', R_TUNNELS, - TerrainType::DISABLED, - 0,0,0,2, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_MUSHROOM,10,5},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 10,I_LIZARD,I_DRAGON,I_ETTIN, - 20,{O_LAIR,O_RUIN,O_CAVE,O_DEMONPIT,O_MAGETOWER,O_GIANTCASTLE}}, - {"grotto", "grotto1", 'g', R_GROTTO, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,12,14,2, - {{I_ROUGHGEM,25,25},{I_MUSHROOM,10,25},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ADMANTIUM,30,10},{-1,0,0},{-1,0,0}}, - {I_MINOTAUR,I_UNDERDWARF,I_ORC,I_DROWMAN}, - {-1,-1,-1}, - 15,I_DEMON,I_DRAGON,I_TROLL, - 30,{O_LAIR,O_RUIN,O_CAVE,O_GIANTCASTLE,O_ILAIR,O_DARKTOWER}}, - {"deepforest", "deepforest1", 'd', R_DFOREST, - TerrainType::FLYINGMOUNTS | TerrainType::DISABLED, - 200,12,14,3, - {{I_WOOD,100,10},{I_STONE,100,10},{I_IRON,100,10},{I_MUSHROOM,100,20}, - {I_ROUGHGEM,20,20},{-1,0,0},{-1,0,0}}, - {I_DROWMAN,I_UNDERDWARF,I_ORC,I_GREYELF}, - {-1,-1,-1}, - 15,I_DEMON,I_DRAGON,I_TROLL, - 30,{O_DEMONPIT,O_RUIN,O_CAVE,O_MAGETOWER,O_ILAIR,O_DARKTOWER}}, - {"chasm", "chasm1", 'c', R_CHASM, - TerrainType::DISABLED, - 0,0,0,3, - {{I_IRON,100,20},{I_STONE,100,20},{I_MITHRIL,25,5},{I_ROOTSTONE,25,5}, - {I_ROUGHGEM,50,20},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 5,I_DEMON,I_DRAGON,I_ETTIN, - 30,{O_LAIR,O_RUIN,O_CAVE,O_DEMONPIT,O_MAGETOWER,O_GIANTCASTLE}}, - {"volcano", "volcano", 'v', R_MOUNTAIN, - TerrainType::RIDINGMOUNTS | TerrainType::DISABLED, - 0,0,0,6, - {{I_STONE,100,15},{I_MITHRIL,30,10},{I_ROOTSTONE,15,10}, - {I_ADMANTIUM,40,15},{I_ROUGHGEM,70,25},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 15,I_ROC,I_HYDRA,I_GOBLIN, - 20,{O_CAVE,O_GIANTCASTLE,-1,-1,-1,-1}}, - {"lake", "lake", '-', R_OCEAN, - 0, - 0,0,0,1, - {{I_FISH,100,20},{-1,0,0},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {I_MERMEN,-1,-1,-1}, - {-1,-1,-1}, - 1,I_PIRATES,-1,-1, - 5,{O_ISLE,-1,O_OCAVE,-1,-1,-1}}, - {"unknown", "unknown", '~', R_FAKE, - 0, - 0,0,0,1, - {{-1,0,0},{-1,0,0},{-1,0,0},{-1,0,0}, - {-1,0,0},{-1,0,0},{-1,0,0}}, - {-1,-1,-1,-1}, - {-1,-1,-1}, - 0,-1,-1,-1, - 0,{-1,-1,-1,-1,-1,-1}}, -}; - -TerrainType *TerrainDefs = td; - -static HealType hd[] = { - {0, 0}, - {10, 40}, // this 40/50% controls the chance for non-magic healers - {20, 50}, // {10, 50}, - {30, 60}, // {25, 75}, - {50, 70}, // {25, 75}, - {80, 80}, // {100, 90}, - {130, 90} -}; -HealType *HealDefs = hd; - -/* key, name - targflags - int buildings[3] - int targets[7] - char effects[3] - effectflags - int shield[4] used with FX_SHIELD - type of shield cast. used with FX_TACSPELL - type of tac penalty/bonus. Should not be used for both. - Defence Mod *defs[4] used with FX_DEFBONUS - type of defence lifted and by how much (per skill level if USE_LEV) - shielddesc - DamageType *damage[4] - spelldesc,spelldesc2,spelltarget -*/ - - -static SpecialType spd[] = { - // NONE - {NULL, "an unknown attack", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - 0, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts something that is not a spell", "annoying ", ""}, - // SPECIAL_FIREBALL - {"fireball", "a fireball", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_ENERGY,2,5, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "shoots a Fireball", "killing ", ""}, - // SPECIAL_HELLFIRE - {"hellfire", "hellfire", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_ENERGY,2,25, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "blasts the enemy with Hellfire", "killing ", ""}, - // SPECIAL_CAUSEFEAR - {"fear", "cause fear", - SpecialType::HIT_EFFECTEXCEPT|SpecialType::HIT_NOMONSTER, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {"fear", NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_SPIRIT,2,20, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_SPIRIT, "fear"}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}}, - "strikes fear into the enemy", "causing ", " men to cower in terror"}, - // SPECIAL_COURAGE - {"courage", "instill courage", - SpecialType::HIT_EFFECTEXCEPT|SpecialType::HIT_NOMONSTER|SpecialType::HIT_OWN_ARMY, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {"courage", NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{NUM_ATTACK_TYPES,2,20, - WeaponType::ALWAYSREADY|WeaponType::RANGED,NUM_WEAPON_CLASSES, "courage"}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}}, - "casts courage amongst his army", "boosting the strength of ", " men"}, - // SPECIAL_LSTRIKE - {"lightning", "a lightning strike", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_WEATHER,2,30, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_WEATHER,0}, - {ATTACK_ENERGY,2,30, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "unleashes a mighty lightning strike", "killing ", ""}, - // SPECIAL_MINDBLAST - {"mindblast", "a mindblast", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_SPIRIT,2,125, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_SPIRIT,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "blasts the minds of the enemy", "killing ", " troops"}, - // SPECIAL_EARTHQUAKE - {"earthquake", "an earthquake", - SpecialType::HIT_BUILDINGEXCEPT, - {O_MFORTRESS, O_MTOWER, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV|SpecialType::FX_NOBUILDING, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_COMBAT,2,50, - WeaponType::ALWAYSREADY|WeaponType::RANGED,ARMORPIERCING,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "invokes a mighty Earthquake", "killing ", ""}, - // SPECIAL_FORCE_SHIELD - {"force_shield", "a force shield", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_SHIELD|SpecialType::FX_USE_LEV|SpecialType::FX_DEFBONUS, - {ATTACK_RANGED, -1, -1, -1}, - {{ATTACK_COMBAT, 1}, {-1, 0}, {-1, 0}, {-1, 0}}, - "Force Shield", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts something that is not a spell", "annoying ", ""}, - // SPECIAL_ENERGY_SHIELD - {"energy_shield", "an energy shield", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_SHIELD, - {ATTACK_ENERGY, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "Energy Shield", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts something that is not a spell", "annoying ", ""}, - // SPECIAL_SPIRIT_SHIELD - {"shield_spirit", "a spirit shield", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_SHIELD, - {ATTACK_SPIRIT, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "Spirit Shield", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts something that is not a spell", "annoying ", ""}, - // SPECIAL_DISPEL_ILLUSIONS - {"dispel_illusion", "dispel illusion", - SpecialType::HIT_ILLUSION, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV|SpecialType::FX_FOG, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{NUM_ATTACK_TYPES,2,50, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts Dispel Illusions", "dispelling ", " illusions"}, - // SPECIAL_SUMMON_STORM - {"storm", "summon storm", - SpecialType::HIT_EFFECTEXCEPT, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {"storm", NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_WEATHER,2,20, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_WEATHER,"storm"}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}}, - "summons a terrible storm", "reducing the effectiveness of ", " troops"}, - // SPECIAL_ILLUSORY_WOUNDS - {"wounds", "illusory wounds", - SpecialType::HIT_EFFECTEXCEPT, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {"wounds", NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_SPIRIT,2,20, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,"wounds"}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}}, - "creates illusionary wounds", "reducing the effectiveness of ", " troops"}, - // SPECIAL_TORNADO - {"tornado", "summon tornado", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_WEATHER,2,25, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_WEATHER, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "summons a wild tornado", "killing ", ""}, - // SPECIAL_CLEAR_SKIES - {"clear_skies", "clear skies", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_SHIELD|SpecialType::FX_FOG, - {ATTACK_WEATHER, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "Clear Skies", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts something that is not a spell", "annoying ", ""}, - // SPECIAL_BLACK_WIND, - {"black_wind", "a black wind", - SpecialType::HIT_SOLDIEREXCEPT, - {-1, -1, -1}, - {I_SKELETON, I_UNDEAD, I_LICH, I_IMP, I_DEMON, I_BALROG, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_SPIRIT,2,100, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_SPIRIT,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "summons the black wind", "killing ", ""}, - // SPECIAL_BANISH_UNDEAD, - {"banish_undead", "banish undead", - SpecialType::HIT_SOLDIERIF, - {-1, -1, -1}, - {I_SKELETON, I_UNDEAD, I_LICH, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{NUM_ATTACK_TYPES,2,25, - WeaponType::ALWAYSREADY|WeaponType::RANGED|WeaponType::RESTINPEACE,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts Banish Undead", "banishing ", " undead"}, - // SPECIAL_BANISH_DEMONS, - {"banish_demon", "banish demons", - SpecialType::HIT_SOLDIERIF, - {-1, -1, -1}, - {I_IMP, I_DEMON, I_BALROG, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{NUM_ATTACK_TYPES,2,25, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_SPIRIT,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts Banish Demons", "banishing ", " demons"}, - // SPECIAL_FIREBREATH, - {"firebreath", "fiery breath", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_ENERGY,2,5, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "breathes Fire", "killing ", ""}, - // SPECIAL_ICEBREATH, - {"icebreath", "icy breath", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_ENERGY,2,5, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "breathes Ice", "killing ", ""}, - // SPECIAL_CAMEL_FEAR - {"spook_horses", "terrify horses", - SpecialType::HIT_EFFECTEXCEPT|SpecialType::HIT_MOUNTIF, - {-1, -1, -1}, - {I_HORSE, -1, -1, -1, -1, -1, -1}, - {"fear", NULL, NULL}, - SpecialType::FX_DAMAGE, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_RIDING,1,0, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_SPIRIT,"fear"}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}, - {-1, 0, 0, 0, 0, NULL}}, - "strikes fear into enemy mounts", "causing ", " mounts to panic"}, - // SPECIAL_INVULNERABILITY - {"invulnerable", "invulnerability", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_SHIELD, - {NUM_ATTACK_TYPES, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "invulnerability", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "casts something that is not a spell", "annoying ", ""}, - // SPECIAL_FOG - {"fog", "fog", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_FOG|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "Fog over the enemy", "annoying ", ""}, - // SPECIAL_DARKNESS - {"darkness", "darkness", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_FOG|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "Darkness over the battlefield", "annoying ", ""}, - // SPECIAL_LIGHT - {"light", "light", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_DAMAGE|SpecialType::FX_FOG|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{ATTACK_ENERGY,2,5, - WeaponType::ALWAYSREADY|WeaponType::RANGED,MAGIC_ENERGY,0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "Summons burning light", "killing ", ""}, - // SPECIAL_CONCEALMENT - {"concealment", "concealment", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_FOG|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "a spell concealing his cavalry", "annoying ", ""}, - {"binding", "binding", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_FOG|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "binds ", "annoying ", ""}, - {"dragon_binding", "dragon binding", - 0, - {-1, -1, -1}, - {-1, -1, -1, -1, -1, -1, -1}, - {NULL, NULL, NULL}, - SpecialType::FX_FOG|SpecialType::FX_USE_LEV, - {-1, -1, -1, -1}, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - "a non-shield spell", - {{-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}, - {-1, 0, 0, 0, 0, 0}}, - "binds ", "annoying ", ""}, -}; - -SpecialType *SpecialDefs = spd; -int NUMSPECIALS = sizeof(spd) / sizeof(spd[0]); - -static EffectType efd[] = { - // EFFECT_COURAGE - {0, "courage", 2, - {{ATTACK_COMBAT, 2}, {ATTACK_RIDING, 2}, {ATTACK_RANGED, 1}, {-1, 0}}, - "fear", 0, -1}, - // EFFECT_FEAR - {1, "fear", -2, - {{ATTACK_COMBAT, -2}, {ATTACK_RIDING, -2}, {-1, 0}, {-1, 0}}, - "courage", 0, -1}, - // EFFECT_STORM - {2, "storm", -2, - {{ATTACK_COMBAT, -2}, {-1, 0}, {-1, 0}, {-1, 0}}, - NULL, 0, -1}, - // EFFECT_WOUNDS - {3, "wounds", -2, - {{ATTACK_COMBAT, -2}, {-1, 0}, {-1, 0}, {-1, 0}}, - NULL, 0, -1}, - // EFFECT_TRANSFIGURE - {4, "transfigure", 0, - {{-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}}, - NULL, EffectType::EFF_ONESHOT | EffectType::EFF_TRANSFIGURE, I_RAT}, -}; - -EffectType *EffectDefs = efd; -int NUMEFFECTS = sizeof(efd) / sizeof(efd[0]); - -// Range definitions -// flags, rangeclass, rangemult, crosslevelpenalty -static RangeType rtd[] = { - {"rng_teleport", 0, RangeType::RNG_LEVEL2, 2, 4}, - {"rng_portal", 0, RangeType::RNG_LEVEL2, 2, 4}, - {"rng_farsight", 0, RangeType::RNG_LEVEL2, 2, 4}, - {"rng_weather", 0, RangeType::RNG_LEVEL2, 4, 4}, - {"rng_clearsky", 0, RangeType::RNG_LEVEL2, 2, 4}, - {"rng_one", 0, RangeType::RNG_ABSOLUTE, 1, 4}, - {"rng_halflinear", 0, RangeType::RNG_LEVEL, 1, 4}, - {"rng_linear", 0, RangeType::RNG_LEVEL, 2, 4}, - {"rng_linear_surface", RangeType::RNG_SURFACE_ONLY, RangeType::RNG_LEVEL, 2, 8}, - {"rng_square", 0, RangeType::RNG_LEVEL2, 1, 4}, -}; - -RangeType *RangeDefs = rtd; -int NUMRANGES = sizeof(rtd) / sizeof(rtd[0]); - -static AttribModType atd[] = { - {"tactics", AttribModType::CHECK_MONSTERS, - {{AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "TACT", AttribModItem::UNIT_LEVEL, 1 }, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}}}, - {"combat", 0, - {{AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "COMB", AttribModItem::UNIT_LEVEL, 1 }, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}}}, - {"stealth", AttribModType::CHECK_MONSTERS | AttribModType::USE_WORST, - {{AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "STEA", AttribModItem::UNIT_LEVEL, 1 }, //takes only the best bonus from the non-cumulative bonuses. - {AttribModItem::ITEM | AttribModItem::PERMAN, - "RING", AttribModItem::CONSTANT, 3}, - {AttribModItem::FLAGGED, - "invis", AttribModItem::CONSTANT, 3}, - {AttribModItem::FLAGGED, - "guard", AttribModItem::FORCECONSTANT, 0}, - {AttribModItem::FLAGGED | AttribModItem::CUMULATIVE, - "visib", AttribModItem::CONSTANT, -2}, - {0, - NULL, 0, 0}}}, - {"observation", AttribModType::CHECK_MONSTERS, - {{AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "OBSE", AttribModItem::UNIT_LEVEL, 1 }, - {AttribModItem::SKILL, - "TRUE", AttribModItem::UNIT_LEVEL_HALF, 1}, - {AttribModItem::ITEM, - "AMTS", AttribModItem::CONSTANT, 2}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}}}, - {"flying", 0, - {{AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "SWIN", AttribModItem::CONSTANT, 2}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}}}, - {"entertainment", 0, - {{AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "PHEN", AttribModItem::UNIT_LEVEL, 10}, - {AttribModItem::SKILL | AttribModItem::CUMULATIVE, - "ENTE", AttribModItem::UNIT_LEVEL, 1}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}, - {0, - NULL, 0, 0}}}, -}; - -AttribModType *AttribDefs = atd; -int NUMATTRIBMODS = sizeof(atd) / sizeof(atd[0]); - diff --git a/arcadia/gamedata.h b/arcadia/gamedata.h deleted file mode 100644 index 2595cec2d..000000000 --- a/arcadia/gamedata.h +++ /dev/null @@ -1,578 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef RULES_H -#define RULES_H - -// -// The items -// -enum { - I_LEADERS, - I_VIKING, - I_BARBARIAN, - I_ESKIMO, - I_NOMAD, - I_TRIBESMAN, - I_DARKMAN, - I_WOODELF, - I_SEAELF, - I_HIGHELF, - I_TRIBALELF, //10 - I_PLAINSMAN, - I_ICEDWARF, - I_HILLDWARF, - I_UNDERDWARF, - I_DESERTDWARF, - I_MERMEN, - I_ORC, - I_GNOME, - I_SILVER, - I_GRAIN, - I_LIVESTOCK, //21 - I_IRON, - I_WOOD, - I_STONE, - I_FUR, - I_FISH, - I_HERBS, - I_HORSE, - I_DOLPHIN, - I_SWORD, - I_CROSSBOW, - I_LONGBOW, //31 - I_CHAINARMOR, - I_PLATEARMOR, - I_WAGON, - I_MITHRIL, - I_IRONWOOD, - I_WHORSE, - I_FDOLPHIN, - I_FLOATER, - I_ROOTSTONE, - I_YEW, - I_MSWORD, - I_MPLATE, - I_PPLATE, - I_DOUBLEBOW, - I_PEARL, - I_WINE, - I_WOOL, - I_ROSES, - I_CAVIAR, - I_SILK, - I_PERFUME, - I_CHOCOLATE, - I_CASHMERE, - I_JEWELRY, - I_FIGURINES, - I_DYES, - I_TRUFFLES, - I_VELVET, - I_MINK, - I_SPICES, - I_VODKA, - I_COTTON, - I_IVORY, - I_TAROTCARDS, - I_LION, - I_WOLF, - I_GBEAR, - I_CROCODILE, - I_ANACONDA, - I_SCORPION, - I_PBEAR, - I_RAT, - I_SPIDER, - I_LIZARD, - I_TRENT, - I_ROC, - I_BTHING, - I_KONG, - I_SPHINX, - I_IWURM, - I_BABYDRAGON, - I_DRAGON, - I_GRYFFIN, - I_CENTAUR, - I_KOBOLD, - I_OGRE, - I_LMEN, - I_WMEN, - I_SANDLING, - I_YETI, - I_GOBLIN, - I_TROLL, - I_ETTIN, - I_SKELETON, - I_UNDEAD, - I_LICH, - I_IMP, - I_DEMON, - I_BALROG, - I_EAGLE, - I_AMULETOFI, - I_RINGOFI, - I_CLOAKOFI, - I_STAFFOFF, - I_STAFFOFL, - I_STAFFOFY, - I_AMULETOFTS, - I_AMULETOFP, - I_RUNESWORD, - I_SHIELDSTONE, - I_MCARPET, - I_IRAT, - I_IWOLF, - I_IEAGLE, - I_IGRYFFIN, - I_IDRAGON, - I_ISKELETON, - I_IUNDEAD, - I_ILICH, - I_IIMP, - I_IDEMON, - I_IBALROG, //121 - I_PORTAL, - I_PEASANT, - // LLS - I_PICK, - I_SPEAR, - I_AXE, - I_HAMMER, - I_MCROSSBOW, - I_MWAGON, - I_GLIDER, - I_NET, //131 - I_LASSO, - I_BAG, - I_SPINNING, - I_LEATHERARMOR, - I_CLOTHARMOR, - I_BOOTS, - I_PIRATES, - I_KRAKEN, - I_MERFOLK, - I_ELEMENTAL, //141 - I_MAN, - /* Additional items for Ceran */ - I_FAIRY, - I_LIZARDMAN, - I_URUK, - I_GOBLINMAN, - I_HOBBIT, - I_GNOLL, - I_DROWMAN, - I_MERC, - I_TITAN, //151 - I_AMAZON, - I_OGREMAN, - I_HIGHLANDER, - I_MINOTAUR, - I_LANCE, - I_MUSHROOM, - I_RRAT, - I_NOOGLE, - I_MUTANT, - // Items from Tzarg - I_BAXE, //161 - I_MBAXE, - I_ADMANTIUM, - I_ADSWORD, - I_ADBAXE, - I_IMARM, - I_ADRING, - I_ADPLATE, - I_SUPERBOW, - I_CAMEL, - I_GREYELF, - I_DROW, - I_HYDRA, - I_STORMGIANT, - I_CLOUDGIANT, - I_ILLYRTHID, - I_SORCERERS, - I_MAGICIANS, - I_DARKMAGE, - I_WARRIORS, - I_ICEDRAGON, - I_HEALPOTION, - I_ROUGHGEM, - I_GEMS, - I_JAVELIN, - I_PIKE, - I_MWOLF, - I_MSPIDER, - I_MOLE, - I_BPLATE, - I_MCHAIN, - I_FSWORD, - I_QSTAFF, - I_SABRE, - I_MACE, - I_MSTAR, - I_DAGGER, - I_PDAGGER, - I_BHAMMER, - I_BOW, - I_SHORTBOW, //201 - I_HEAVYCROSSBOW, - I_HARP, - // Generic processed food - I_FOOD, - NITEMS -}; - -// -// Types of skills. -// -enum { - S_LEADERSHIP, - S_HEROSHIP, - S_MINING, //0 - S_LUMBERJACK, - S_QUARRYING, - S_HUNTING, - S_FISHING, - S_HERBLORE, - S_HORSETRAINING, - S_DOLPHINTRAINING, - S_WEAPONSMITH, - S_ARMORER, - S_CARPENTER, - S_BUILDING, //10 - S_SHIPBUILDING, - S_ENTERTAINMENT, - S_TACTICS, - S_COMBAT, - S_RIDING, - S_CROSSBOW, - S_LONGBOW, - S_STEALTH, - S_OBSERVATION, - S_HEALING, //20 - S_SAILING, - S_FARMING, - S_RANCHING, - S_FORCE, - S_PATTERN, - S_SPIRIT, - S_FIRE, - S_EARTHQUAKE, - S_FORCE_SHIELD, - S_ENERGY_SHIELD, //30 - S_SPIRIT_SHIELD, - S_MAGICAL_HEALING, - S_GATE_LORE, - S_FARSIGHT, - S_TELEPORTATION, - S_PORTAL_LORE, - S_MIND_READING, - S_WEATHER_LORE, - S_SUMMON_WIND, - S_SUMMON_STORM, //40 - S_SUMMON_TORNADO, - S_CALL_LIGHTNING, - S_CLEAR_SKIES, - S_EARTH_LORE, - S_WOLF_LORE, - S_BIRD_LORE, - S_DRAGON_LORE, - S_NECROMANCY, - S_SUMMON_SKELETONS, - S_RAISE_UNDEAD, //50 - S_SUMMON_LICH, - S_CREATE_AURA_OF_FEAR, - S_SUMMON_BLACK_WIND, - S_BANISH_UNDEAD, - S_DEMON_LORE, - S_SUMMON_IMPS, - S_SUMMON_DEMON, - S_SUMMON_BALROG, - S_BANISH_DEMONS, - S_ILLUSION, //60 - S_PHANTASMAL_ENTERTAINMENT, - S_CREATE_PHANTASMAL_BEASTS, - S_CREATE_PHANTASMAL_UNDEAD, - S_CREATE_PHANTASMAL_DEMONS, - S_INVISIBILITY, - S_TRUE_SEEING, - S_DISPEL_ILLUSIONS, - S_ARTIFACT_LORE, - S_CREATE_RING_OF_INVISIBILITY, - S_CREATE_CLOAK_OF_INVULNERABILITY, //70 - S_CREATE_STAFF_OF_FIRE, - S_CREATE_STAFF_OF_LIGHTNING, - S_CREATE_AMULET_OF_TRUE_SEEING, - S_CREATE_AMULET_OF_PROTECTION, - S_CREATE_RUNESWORD, - S_CREATE_SHIELDSTONE, - S_CREATE_MAGIC_CARPET, - S_ENGRAVE_RUNES_OF_WARDING, - S_CONSTRUCT_GATE, - S_ENCHANT_SWORDS, //80 - S_ENCHANT_ARMOR, - S_CONSTRUCT_PORTAL, - S_MANIPULATE, - // Skills for Ceran - S_WEAPONCRAFT, - S_ARMORCRAFT, - S_CAMELTRAINING, - S_GEMCUTTING, - S_MONSTERTRAINING, - S_CREATE_FLAMING_SWORD, - // Food related skills - S_COOKING, //90 - S_CREATE_FOOD, - S_BANKING, - S_QUARTERMASTER, - S_BLIZZARD, - S_FOG, //95 - S_CONCEALMENT, - S_ILLUSORY_CREATURES, - S_ILLUSORY_WOUNDS, - S_INSTILL_COURAGE, - S_SUMMON_MEN, - S_RESURRECTION, //101 - S_SPIRIT_OF_DEAD, - S_INNER_STRENGTH, - S_TRANSMUTATION, - S_MODIFICATION, - S_REJUVENATION, - S_SEAWARD, - S_DIVERSION, - S_GRYFFIN_LORE, - S_HYPNOSIS, - S_BINDING, - S_CREATE_PORTAL, - S_LIGHT, - S_DARKNESS, - S_DRAGON_TALK, - S_TOUGHNESS, - S_UNITY, - S_FRENZY, - S_SECSIGHT, - S_SWIFTNESS, - S_TRADING, - S_MERCHANTRY, - S_BASE_WINDKEY, - S_BASE_ILLUSION, - S_BASE_SUMMONING, - S_BASE_PATTERNING, - S_BASE_MYSTICISM, - S_BASE_BATTLETRAINING, - S_BASE_CHARISMA, - S_BASE_ARTIFACTLORE, - S_ARCADIA_QUARTERMASTERY, - S_CONSTRUCTION, - NSKILLS -}; - -// -// Types of objects. -// -enum { - O_DUMMY, - O_CORACLE, - O_LONGBOAT, - O_JUNK, - O_MERCHANT, - O_TRIREME, - O_ATRIREME, - O_TREASUREARK, - O_BARGE, - O_BALLOON, - O_TOWER, - O_FORT, - O_CASTLE, - O_CITADEL, - O_MFORTRESS, - O_SHAFT, - O_LAIR, - O_RUIN, - O_CAVE, - O_DEMONPIT, - O_CRYPT, - O_MINE, - O_FARM, - O_RANCH, - O_TIMBERYARD, - O_INN, - O_QUARRY, - // LLS - // New ocean lairs - O_ISLE, - O_DERELICT, - O_OCAVE, - O_WHIRL, - // AS - O_TEMPLE, - O_MQUARRY, - O_AMINE, - O_PRESERVE, - O_SACGROVE, - // JT - // Abyss Lair - O_BKEEP, - O_PALACE, - // For Ceran - O_DCLIFFS, - O_MTOWER, - O_WGALLEON, - O_HUT, - O_STOCKADE, - O_CPALACE, - O_NGUILD, - O_AGUILD, - O_ATEMPLE, - O_HTOWER, - // Tzargs monster lairs - O_MAGETOWER, - O_DARKTOWER, - O_GIANTCASTLE, - O_ILAIR, - O_ICECAVE, - O_BOG, - O_TRAPPINGHUT, - O_STABLE, - O_FISHTRAP, - O_MSTABLE, - O_TRAPPINGLODGE, - O_FAERIERING, - O_ALCHEMISTLAB, - O_OASIS, - O_GEMAPPRAISER, - O_HPTOWER, - O_OBANK, - O_CARAVANSERAI, - O_ESEAPORTAL, - O_MESSAGESTONE, - O_ROADN, - O_ROADNW, - O_ROADNE, - O_ROADSW, - O_ROADSE, - O_ROADS, -/* O_ROAD, - O_RIVER, - O_RAVINE, - O_CLIFF, - O_BEACH, - O_ROCKS, - O_HARBOUR, - O_BRIDGE, - O_IWALL, - O_OWALL,*/ - NOBJECTS -}; - -// -// Types of hexside terrain. -// -enum { - H_DUMMY, - H_ROCKS, - H_BEACH, - H_HARBOUR, - H_RIVER, - H_RAVINE, - H_CLIFF, - H_ROAD, - H_BRIDGE, - NHEXSIDES -}; - -// -// Types of terrain -// -/* ARegion Types */ -enum { - R_OCEAN, - R_PLAIN, - R_FOREST, - R_MOUNTAIN, - R_SWAMP, - R_JUNGLE, - R_DESERT, - R_TUNDRA, - R_CAVERN, - R_UFOREST, - R_TUNNELS, - R_GROTTO, - R_DFOREST, - R_CHASM, - R_NEXUS, - R_PARADISE, - R_ISLAND_PLAIN, - R_ISLAND_SWAMP, - R_ISLAND_MOUNTAIN, - R_CERAN_PLAIN1, - R_CERAN_PLAIN2, - R_CERAN_PLAIN3, - R_CERAN_FOREST1, - R_CERAN_FOREST2, - R_CERAN_FOREST3, - R_CERAN_MYSTFOREST, - R_CERAN_MYSTFOREST1, - R_CERAN_MYSTFOREST2, - R_CERAN_MOUNTAIN1, - R_CERAN_MOUNTAIN2, - R_CERAN_MOUNTAIN3, - R_CERAN_HILL, - R_CERAN_HILL1, - R_CERAN_HILL2, - R_CERAN_SWAMP1, - R_CERAN_SWAMP2, - R_CERAN_SWAMP3, - R_CERAN_JUNGLE1, - R_CERAN_JUNGLE2, - R_CERAN_JUNGLE3, - R_CERAN_DESERT1, - R_CERAN_DESERT2, - R_CERAN_DESERT3, - R_CERAN_WASTELAND, - R_CERAN_WASTELAND1, - R_CERAN_LAKE, - R_CERAN_TUNDRA1, - R_CERAN_TUNDRA2, - R_CERAN_TUNDRA3, - R_CERAN_CAVERN1, - R_CERAN_CAVERN2, - R_CERAN_CAVERN3, - R_CERAN_UFOREST1, - R_CERAN_UFOREST2, - R_CERAN_UFOREST3, - R_CERAN_TUNNELS1, - R_CERAN_TUNNELS2, - R_CERAN_GROTTO1, - R_CERAN_DFOREST1, - R_CERAN_CHASM1, - R_VOLCANO, - R_LAKE, - R_FAKE, - R_NUM -}; - -#endif diff --git a/arcadia/gamedefs.cpp b/arcadia/gamedefs.cpp deleted file mode 100644 index c5e3ea588..000000000 --- a/arcadia/gamedefs.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "gamedefs.h" - -char *dr[] = { - "North", - "Northeast", - "Southeast", - "South", - "Southwest", - "Northwest" -}; - -char ** DirectionStrs = dr; - -char *da[] = { - "N", - "NE", - "SE", - "S", - "SW", - "NW" -}; - -char ** DirectionAbrs = da; - -char *mn[] = { - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December" -}; - -char ** MonthNames = mn; - -char *weath[] = { - "clear", - "winter", - "monsoon season", - "blizzard" -}; - -char ** SeasonNames = weath; diff --git a/arcadia/gamedefs.h b/arcadia/gamedefs.h deleted file mode 100644 index 17dda150a..000000000 --- a/arcadia/gamedefs.h +++ /dev/null @@ -1,763 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef GAME_DEFS -#define GAME_DEFS - -#include "helper.h" - -/* Directions */ -enum { - D_NORTH, - D_NORTHEAST, - D_SOUTHEAST, - D_SOUTH, - D_SOUTHWEST, - D_NORTHWEST, - NDIRS -}; - -extern char **DirectionStrs; -extern char **DirectionAbrs; - -extern char **MonthNames; - -extern char **SeasonNames; - -extern int *allowedMages; -extern int allowedMagesSize; -extern int *allowedApprentices; -extern int allowedApprenticesSize; -extern int *allowedTaxes; -extern int allowedTaxesSize; -extern int *allowedTrades; -extern int allowedTradesSize; -extern int *allowedQuartermasters; -extern int allowedQuartermastersSize; -extern int *allowedTacticians; -extern int allowedTacticiansSize; - -extern int NUMBATTLEITEMS; -extern int NUMARMORS; -extern int NUMWEAPONS; -extern int NUMMOUNTS; -extern int NUMMONSTERS; -extern int NUMMAN; - -class GameDefs { -public: - char *RULESET_NAME; - ATL_VER RULESET_VERSION; - - int FOOT_SPEED; - int HORSE_SPEED; - int SHIP_SPEED; - int FLY_SPEED; - int MAX_SPEED; - - int STUDENTS_PER_TEACHER; - - int MAINTENANCE_COST; - int LEADER_COST; - - // If we use skill level multiplier then no units, all units, leaders, - // or just mages pay X per level of skill they have per man. The - // first value (MAINTENCE_MULTIPLIER) is how much is payed per skill - // level. The second value (MULTIPLIER_USE) is set to one of the - // values in the given enumeration. - // The costs listed above are used for any units NOT covered by the - // multiplier use - int MAINTENANCE_MULTIPLIER; - - enum { - MULT_NONE, - MULT_MAGES, - MULT_LEADERS, - MULT_ALL, - }; - int MULTIPLIER_USE; - - int STARVE_PERCENT; - - enum { - STARVE_NONE, - STARVE_MAGES, - STARVE_LEADERS, - STARVE_ALL, - }; - - // Instead of dying, lose skill levels, but only for the types of - // units listed below. Any unit which should lose a skill level and - // is unable to will die, period. - int SKILL_STARVATION; - - int START_MONEY; - int WORK_FRACTION; - int ENTERTAIN_FRACTION; - int ENTERTAIN_INCOME; - - // base tax income for ANY eligible taxer - // AND for pillaging - int TAX_BASE_INCOME; - // bonus for useable weapons - int TAX_BONUS_WEAPON; - // bonus for armor (only in conjunction with a weapon) - int TAX_BONUS_ARMOR; - // bonus for manning a fortification - int TAX_BONUS_FORT; - - // Options to control who is able to tax - enum { - TAX_ANYONE = 0x00001, - TAX_COMBAT_SKILL = 0x00002, - TAX_BOW_SKILL = 0x00004, - TAX_RIDING_SKILL = 0x00008, - TAX_USABLE_WEAPON = 0x00010, // no requirement or has required skill - TAX_ANY_WEAPON = 0x00020, // Pay up lest I beat thee with my longbow! - TAX_HORSE = 0x00040, // someone who HAS a horse, not the horse itself - // Usually a weapon that requires no skill, plus COMB, but also - // LANC (which requires RIDI) and RIDI - TAX_MELEE_WEAPON_AND_MATCHING_SKILL = 0x00080, - TAX_BOW_SKILL_AND_MATCHING_WEAPON = 0x00100, - TAX_HORSE_AND_RIDING_SKILL = 0x00200, //BS: Modified it to be Horse & riding skill & melee weapon - // Probably more petty theft than tax, but then there are those - // who argue that taxation IS theft ;-> - TAX_STEALTH_SKILL = 0x00400, - // Should mages be able to tax? I'd give my tax to someone who - // was aiming the black wind at me... - TAX_MAGE_DAMAGE = 0x00800, - TAX_MAGE_FEAR = 0x01000, // or able to flatten my barn? - TAX_MAGE_OTHER = 0x02000, // or able to create magical armour? - TAX_ANY_MAGE = 0x04000, // or who just has an impressive pointy hat? - // Wasn't sure whether mages should be judged on whether they - // know the spell, or their current combat spell (he's ordered - // to cast shield in combat, but still knows how to fireball - // unruly peasants). Setting this uses only the current - // spell set with the COMBAT order. - TAX_MAGE_COMBAT_SPELL = 0x08000, - TAX_BATTLE_ITEM = 0x10000, // Has a staff of lightning? - TAX_USABLE_BATTLE_ITEM = 0x20000, - TAX_CREATURES = 0x40000, // Do magical critters help to tax? - TAX_ILLUSIONS = 0x80000, // What if they're not really there? - - TAX_HORSE_AND_RIDING_SKILL_AND_MELEE_WEAPON = 0x100000, //like tax_horse_and_riding_skill, but also needs a spare skill-less weapon - - // Abbreviation for "the usual" - TAX_NORMAL = TAX_COMBAT_SKILL | TAX_USABLE_WEAPON, - }; - int WHO_CAN_TAX; - // Are taxing and pillaging month-long actions? - int TAX_PILLAGE_MONTH_LONG; - - int HEALS_PER_MAN; - - int GUARD_REGEN; /* percent chance of regenerating per turn */ - int CITY_GUARD; - int GUARD_DEPENDS_ON_TAX; - int GUARD_MONEY; - int CITY_POP; - - int WMON_FREQUENCY; - int LAIR_FREQUENCY; - - int FACTION_POINTS; - - int TIMES_REWARD; - - //should the order templates go into template. or report. ? - int SEPERATE_TEMPLATES; - - int TOWNS_EXIST; - int LEADERS_EXIST; - int SKILL_LIMIT_NONLEADERS; - int MAGE_NONLEADERS; - int RACES_EXIST; - int GATES_EXIST; - int FOOD_ITEMS_EXIST; - int COASTAL_FISH; - int CITY_MONSTERS_EXIST; // ie Guardsmen - int WANDERING_MONSTERS_EXIST; - int LAIR_MONSTERS_EXIST; - int WEATHER_EXISTS; - int OPEN_ENDED; - int NEXUS_EXISTS; - int CONQUEST_GAME; // effects genrules and map only - - // - // RANDOM_ECONOMY determines whether the economy for different regions - // is randomized, or is always the same. - // - int RANDOM_ECONOMY; - - // - // If VARIABLE_ECONOMY is set, the economy of a region is altered after - // each turn. - // - int VARIABLE_ECONOMY; - - // - // Some economy figures. - // - int CITY_MARKET_NORMAL_AMT; - int CITY_MARKET_ADVANCED_AMT; - int CITY_MARKET_TRADE_AMT; - // If any magic items are not set NOMARKET, how many are allowed? - int CITY_MARKET_MAGIC_AMT; - // JLT -- Allow higher margins on trade goods. - int MORE_PROFITABLE_TRADE_GOODS; - - // JLT -- Allow races to have differing base costs - int BASE_MAN_COST; - - // Are the lastorders values maintained by external scripts? - int LASTORDERS_MAINTAINED_BY_SCRIPTS; - - // How many turns to allow a faction to be inactive. - // Set to -1 if you don't want this check performed. - int MAX_INACTIVE_TURNS; - - // Is it easier to deal with the underworld (allows teleport and - // farsight into the underworld) - int EASIER_UNDERWORLD; - - // Should units with no orders perform a default 'work' order - int DEFAULT_WORK_ORDER; - - // - // The type of faction limits that are in effect in this game. - // - enum { - FACLIM_MAGE_COUNT, - FACLIM_FACTION_TYPES, - FACLIM_UNLIMITED, - }; - int FACTION_LIMIT_TYPE; - - // - // The type of flight over water that is available. - // - enum { - WFLIGHT_NONE, - WFLIGHT_MUST_LAND, - WFLIGHT_UNLIMITED, - }; - int FLIGHT_OVER_WATER; - - // Do starting cities exist? - int START_CITIES_EXIST; - - // - // Are starting cities safe regions? Also controls if guards in - // the starting cities get amulets of invulnerability. - // - int SAFE_START_CITIES; - - // - // How many guards in starting cities? - // - int AMT_START_CITY_GUARDS; - - // - // Should starting city guards be made tougher than normal city guards? - // (this means giving them plate armor) - // - int START_CITY_GUARDS_PLATE; - - // - // Do starting cities have a fire mages. (0 for no mages, otherwise - // this is the level of their fire skill) - // - // - int START_CITY_MAGES; - - // Do the starting city guards also have tactician skill (0 for - // no tactician, otherwise this is their level of tactician) - int START_CITY_TACTICS; - - // - // Are we allowing apprentices? - // - int APPRENTICES_EXIST; - - // What is the name of the world? - char *WORLD_NAME; - - // Does the nexus allow gating out of it - int NEXUS_GATE_OUT; - - // Is the nexus also a city? - int NEXUS_IS_CITY; - - // Do battle reports show factions if ANY unit on the opposing side - // could see it. Non-involved observers will ALSO see this - // information. - int BATTLE_FACTION_INFO; - - // Is the withdraw order enabled - int ALLOW_WITHDRAW; - - // Cost of sending goods (-1 if SEND is disabled) - int SEND_COST; - - // Is the BANK order enabled ? - enum { - // Do we allow banking in this game ? - BANK_ENABLED = 0x01, - // if Banks are enabled, can the bank be built if units are - // on guard? units can use the bank anyhow if it's there - // already if Banks are disabled, can units BANK if region - // is guarded? - BANK_NOTONGUARD = 0x02, - // if Banks are enabled, can the bank be built in settlements - // only? units can use the bank anyhow if it's there already - // if Banks are disabled, can units BANK in settlements only? - BANK_INSETTLEMENT = 0x04, - // Do Trade factions get interest in deposits ? - BANK_TRADEINTEREST = 0x08, - // If banks are enabled, is BANKING 1 required in addition to - // BUILDING ? FIXME: ignored - BANK_SKILLTOBUILD = 0x10, - // Do operations require money ? (only if banks are enabled) - BANK_FEES = 0x20, - }; - int ALLOW_BANK; - int BANK_FEE; // percentage if enabled. - int BANK_MAXUNSKILLED; // max silver if banks and/or skill disabled, or - // if unskilled and skill disabled or - // if banke enabled and not in bank - int BANK_MAXSKILLPERLEVEL; // if skill is enabled, how much can be withdrawn deposited per skill level - // if disabled, skill is presumed to be 5, so if you have 1000 here, - // max would be 5000. - - // Do cities have a cost to rename them? If this value is set, - // the cost is the city size (1, 2, 3) * this value - int CITY_RENAME_COST; - - // Are we allowing a multi-hex nexus - int MULTI_HEX_NEXUS; - - // How many levels of the underworld do we want? - int UNDERWORLD_LEVELS; - - // How many levels of the underdeep do we want? - int UNDERDEEP_LEVELS; - - // Is there an abyss level? - int ABYSS_LEVEL; - - //Is the world flat or cylindrical? Atlantis was developed for cylindrical worlds, - //and this gamedef has only been done briefly for non-icosohedral map generation - //and spell range costs. It may not work in all cases. - int FLAT_WORLD; - - // Town probability; 100 = default - int TOWN_PROBABILITY; - - // Raising this value will lessen the effects - // of a region type's economy on the chance - // for creating towns. At 100% chances will - // be exactly equal for all types of regions, - // at 0 the chance will be directly proportional - // to the economy value. - int TOWN_SPREAD; - - // Reduction (in %) of the chance for towns forming adjacent - // to each other (0 = normal chance, 100 = no chance of towns - // forming adjacent to each other) - int TOWNS_NOT_ADJACENT; - - // Make settlements near the arctic less likely and smaller - // Higher values decrease likeliness of settlements - // suggested: 0-5 - int LESS_ARCTIC_TOWNS; - - // Percent of surface level covered with ocean. - int OCEAN; - - // Size factor for continent creation. - int CONTINENT_SIZE; - - // Granularity of terrain - default setting is 0. - // A value of 1 means maximum variability, - // higher values = more regular terrain spread - int TERRAIN_GRANULARITY; - - // Relative frequency of LAKE terrain - int LAKES; - - // Enable Archipelago Creation - // = chance of creating archipelagos vs continents - // (note that archipelagos are smaller so that - // the overall contribution of archipelagos to - // land mass will be much lower than this percentage) - // suggested value: 10, 25, 50+ it's really a matter of taste - int ARCHIPELAGO; - - // Reduce/Sever Land Bridges: this is the base chance - // that thin strips of land will be 'cut'. This chance is - // doubled when a region has exactly four adjacent sea - // areas. (default is 30, 0 means no removal) - int SEVER_LAND_BRIDGES; - - // Maximum Size of inland seas to fill in. WARNING: game - // creation time will rise exponentially with this value. - // Recommended: 8-12 - int SEA_LIMIT; - - // Lake Effect on Wages Options - // Lakes will add one to adjacent regions wages if set - enum { - NO_EFFECT = 0x00, - ALL = 0x01, - TOWNS = 0x02, - NONPLAINS = 0x04, - NONPLAINS_TOWNS_ONLY=0x08, - DESERT_ONLY = 0x10, - }; - - // LAKE_WAGE_EFFECT: effect on surrounding wages - int LAKE_WAGE_EFFECT; - - // LAKESIDE_IS_COASTAL: lakeside regions count as - // coastal for all purposes - races and such - int LAKESIDE_IS_COASTAL; - - // ODD_TERRAIN: chance (x 0.1%) for single-hex terrain oddities - // suggested: between 5 and 40 - int ODD_TERRAIN; - - // Does farsight make use of a mages other skills - int IMPROVED_FARSIGHT; - - // Should the GM get a full world report every turn - int GM_REPORT; - - // Do we allow objects to decay according to the parameters in the object - // definition table - // If using hexside objects, they will not decay. - int DECAY; - - // Do we limit the number of mages which can study inside of certain - // buildings. - // If using the Earthsea mod, it is assumed you will set this to zero. - int LIMITED_MAGES_PER_BUILDING; - - // Transit report options - enum { - REPORT_NOTHING = 0x0000, - // Various things which can be shown - REPORT_SHOW_PEASANTS = 0x0001, - REPORT_SHOW_REGION_MONEY = 0x0002, - REPORT_SHOW_WAGES = 0x0004, - REPORT_SHOW_MARKETS = 0x0008, - REPORT_SHOW_RESOURCES = 0x0010, - REPORT_SHOW_ENTERTAINMENT = 0x0020, - // Collection of the the above - REPORT_SHOW_ECONOMY = (REPORT_SHOW_PEASANTS | - REPORT_SHOW_REGION_MONEY | - REPORT_SHOW_WAGES | - REPORT_SHOW_MARKETS | - REPORT_SHOW_RESOURCES | - REPORT_SHOW_ENTERTAINMENT), - // Which type of exits to show - REPORT_SHOW_USED_EXITS = 0x0040, - REPORT_SHOW_ALL_EXITS = 0x0080, - // Which types of units to show - REPORT_SHOW_GUARDS = 0x0100, - REPORT_SHOW_INDOOR_UNITS = 0x0200, - REPORT_SHOW_OUTDOOR_UNITS = 0x0400, - // Collection of the above - REPORT_SHOW_UNITS = (REPORT_SHOW_GUARDS | REPORT_SHOW_INDOOR_UNITS | - REPORT_SHOW_OUTDOOR_UNITS), - // Various types of buildings - REPORT_SHOW_BUILDINGS = 0x0800, - REPORT_SHOW_ROADS = 0x1000, - REPORT_SHOW_SHIPS = 0x2000, - // Collection of the above - REPORT_SHOW_STRUCTURES = (REPORT_SHOW_BUILDINGS | - REPORT_SHOW_ROADS | - REPORT_SHOW_SHIPS), - // Should the unit get to use their advanced skills? - REPORT_USE_UNIT_SKILLS = 0x8000, - - // Some common collections - REPORT_SHOW_REGION = (REPORT_SHOW_ECONOMY | REPORT_SHOW_ALL_EXITS), - REPORT_SHOW_EVERYTHING = (REPORT_SHOW_REGION | - REPORT_SHOW_UNITS | - REPORT_SHOW_STRUCTURES), - }; - - // What sort of information should be shown to a unit just passing - // through a hex? - int TRANSIT_REPORT; - - // Should advanced items be shown in markets at all times. - int MARKETS_SHOW_ADVANCED_ITEMS; - - // Do we require the 'ready' command to set up battle items - // If prepare is strict, then the READY command MUST be used - // and there will be no automatic selection of battle items. - enum { - PREPARE_NONE = 0, - PREPARE_NORMAL = 1, - PREPARE_STRICT = 2, - }; - int USE_PREPARE_COMMAND; - - // Monsters have the option of advancing occasionally instead of just - // using move. - // There are two values which control this. - // MONSTER_ADVANCE_MIN_PERCENT is the minimum amount which monsters - // should advance. - // MONSTER_ADVANCE_HOSTILE_PERCENT is the percent of their hostile - // rating which should be used to determine if they advance. - // If you don't want monsters to EVER advance, use 0 for both. - // If you want a flat percent, use MIN_PERCENT and set HOSTILE_PERCENT - // to 0. If you only want it based on the HOSTILE value, set MIN_PERCENT - // to 0 and HOSTILE_PERCENT to what you want. - int MONSTER_ADVANCE_MIN_PERCENT; - int MONSTER_ADVANCE_HOSTILE_PERCENT; - - // Set this to 1 if your scripts can handle the following commands - // #create, #resend, #times, #rumor, #remind, #email - int HAVE_EMAIL_SPECIAL_COMMANDS; - - // Should starting cities begin with unlimited markets at world - // generation time. - int START_CITIES_START_UNLIMITED; - - // If this is enabled, then when a unit has more men than Amulets of - // True Seeing, and it is targetted by an assassin, then there is a - // chance that the target picked will be one of the men carrying - // the amulet and the attempt will be foiled. If not enabled, the - // attempt always succeeds. - int PROPORTIONAL_AMTS_USAGE; - - // If this is enabled, then the ARMOR and WEAPON commands for selecting - // armor/weapon priorities for a unit are enabled. If a preferred weapon - // or armor isn't available, then the code will fall back to the internal - // list. - int USE_WEAPON_ARMOR_COMMAND; - - // Set MONSTER_NO_SPOILS > 0 to disable spoils from released monsters - // for that many months. - int MONSTER_NO_SPOILS; - // Set MONSTER_SPOILS_RECOVERY > 0 to set a time in months over which - // monster spoils are slowly regained. - // This has no effect unles MONSTER_NO_SPOILS is also set. - int MONSTER_SPOILS_RECOVERY; - - // Use this to limit the number of attacks an assassin gets in the free - // round. - int MAX_ASSASSIN_FREE_ATTACKS; - - // Set to 1 to allow 'GIVE 0 ' for summoned monsters - // (dragons, wolves, eagles currently) - int RELEASE_MONSTERS; - - // Set to 1 to check for demons breaking free and undead decaying before - // movemeent rather than at the end of the turn. This prevents 'balrog - // missiles' - int CHECK_MONSTER_CONTROL_MID_TURN; - - // Set to 1 if CAST GATE DETECT shows the actual gate numbers. - int DETECT_GATE_NUMBERS; - - // Should army routes be basd on the number of hits lost rather than the - // number of figures lost. - enum { - // Default -- rout if half of the total figures die. All figures are - // treated equally. - ARMY_ROUT_FIGURES = 0, - // Rout if half the total hits die, all hits are counted independantly - // This means you could rout even if none of your men are dead but - // you have just taken a lot of hits and are getting clobbered - ARMY_ROUT_HITS_INDIVIDUAL, - // Rout if half of the total hits die, but figures hits only stop - // counting toward the total when the figure is fully dead. - ARMY_ROUT_HITS_FIGURE, - }; - - int ARMY_ROUT; - - // How are fortification bonuses handled? - // Setting this flag will enable fort bonuses to be treated as a - // modifier to the attack chance rather than a flat bonus to the - // defence skill. This will make forts much better, especially - // against skilled/well-equipped attackers. - // Chance will depend on the fort protection level: - // 1 : 25%, 2: 25%, 3: 20%, 4: 20%, 5: 16% and so on. - int ADVANCED_FORTS; - - // If this is set to 0 then a mage gets his TRUE_SEEING skill/2 - // rounded up as a bonus to observation. Lacandon (and perhaps others) - // should set this to 1. - int FULL_TRUESEEING_BONUS; - - // If this is set to 1 then an AMTS will give 3 bonus to OBSE rather - // than 2. This was added for Lacandon - int IMPROVED_AMTS; - - // If this is set to 1 then a mage automatically gets his INVISIBILITY - // skill added to his stealth. I only recommend setting this if you - // also set the FULL_TRUESEEING_BONUS above. This was added for - // Lacandon. - int FULL_INVIS_ON_SELF; - - // Do monsters regenerate during battle? - int MONSTER_BATTLE_REGEN; - - // Amount of skill improvement when a skill is used - int SKILL_PRACTICE_AMOUNT; - - // Options on using food for upkeep - // Note that all these values are in silver equivalents! - int UPKEEP_MINIMUM_FOOD; - // MAXIMUM_FOOD is the maximum contribution of food to upkeep - // per man, and therefore CAN be lower than MINIMUM_FOOD - // (although this seems a silly thing to do). - // A negative value for this def indicates no maximum. - int UPKEEP_MAXIMUM_FOOD; - int UPKEEP_FOOD_VALUE; - - // Should ships be prevented from sailing through single hex landmasses - // during the same turn. (does not prevent them from stopping in a - // single hex one turn and sailing on through the next turn. - // This has no affect if hexside terrain is enabled. - int PREVENT_SAIL_THROUGH; - - // If we are preventing sail through, should we also prevent the 'easy - // portage' that the above allows by default? - int ALLOW_TRIVIAL_PORTAGE; - - // Non-Perennial Gates: setting this between 1 and 11 will cause gates - // to open and close. Gates will be open this number of months per year. - // Each gate will have a different period of opening (although they are - // somewhat related to gate index). A gate will not be detectable or - // useable while closed; EXCEPTION: a closed gate may be the TARGET for - // a random jump (stranding the jumper until the gate opens). Nexus - // gates (and optionally, starting city gates) are open all the time. - int GATES_NOT_PERENNIAL; - - // Are gates in starting cities open all year round? Need only be set - // if GATES_NOT_PERENNIAL is selected. - int START_GATES_OPEN; - - // Should a message appear in the report that a closed gate exists when - // a that is closed would normally be detected (this might affect some - // clients with unflexible parsers badly...) - int SHOW_CLOSED_GATES; - - // Transport and related settings - enum { - ALLOW_TRANSPORT = 0x01, // Do we allow transport/distribute? - QM_AFFECT_COST = 0x02, // QM level affect shipping cost? - QM_AFFECT_DIST = 0x04, // QM level affect longrange dist? - }; - int TRANSPORT; - - // Base hexes for local transport and distribute (0 to disable) - int LOCAL_TRANSPORT; - - // Base hexes for long range transport and distribute (-1 to disable) - // (0 to allow instant transport between structures anywhere in world) - int NONLOCAL_TRANSPORT; - - // Base cost per weight unit to ship items. (QM skill can affect - // this as a multiplier at lower skill levels. - // Function is 4-(level+1)/2), which means that the cost will be from - // 1 (at level 5) to 3 (at level 1) times this value per weight unit. - int SHIPPING_COST; - - // Will 0 weight items have a fractional weight so that large - // quantities actually have some heft? - // Leave 0 for no fractional weight. Otherwise, X items weigh 1. - int FRACTIONAL_WEIGHT; - - // Use grow algorithm for races? - int GROW_RACES; - - /* Player-Run Economy */ - // Does the game use the player-run economy rules? - int PLAYER_ECONOMY; - - // Population growth rate modifier (100 = standard). - int POP_GROWTH; - - // Mortality delay - in months. Minimum = 2 months. Suggested are THREE - // months - int DELAY_MORTALITY; - - // Growth effects delay - in months. Minimum = 2 months. Suggested are - // SIX months. - int DELAY_GROWTH; - - // How developed pre-existing towns are at the start of the game - // (100 = standard). - int TOWN_DEVELOPMENT; - - // Whether you need to be a war faction to have tact-5 leaders - //Note this is currently incompatible with the real_experience gamedef. - int TACTICS_NEEDS_WAR; - - // Whether allies should aid you if you're set to noaid - int ALLIES_NOAID; - - // Whether hexside terrain objects are enabled - int HEXSIDE_TERRAIN; - - // Whether the Arcadia magic system should be used - int ARCADIA_MAGIC; - - //Whether the Earthsea victory system should be used. This is not fully gamedef'd yet. - int EARTHSEA_VICTORY; - - //Whether experience and study are seperate entities. - //Note this is currently incompatible with the tactics_needs_war gamedef and will - //not behave properly with non-leader mages (see unit::adjustskills). - int REAL_EXPERIENCE; - - int TESTGAME_ENABLED; - - int POP_LEVEL; - - int FORM_TEMPLATES; - enum { - DONT_SUPPRES, - SUPPRESS_ALL, - SHOW_AS_EVENTS, - }; - int SUPPRESS_ERRORS; - int LATE_TAX; - //this is a value of 0 to 100, specifiying the % chance of undead to self-resurrect - int MAGE_UNDEAD_INVINCIBLE; - // value of zero means magic CAN be taught: - int CANT_TEACH_MAGIC; - int ARCADIAN_CHECKER; -}; - -extern GameDefs *Globals; - -#endif diff --git a/arcadia/gameio.cpp b/arcadia/gameio.cpp deleted file mode 100644 index 404b75bb1..000000000 --- a/arcadia/gameio.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include -#include - -using namespace std; - -#include "gameio.h" -#include "gamedefs.h" -#include -#include -#include - -#include "i_rand.h" - -static randctx isaac_ctx; - -#define ENDLINE '\n' -char buf[256]; - -void cleartoendl() -{ - char ch = ' '; - while (!(cin.eof()) && (ch != ENDLINE)) - { - ch = cin.get(); - } -} - -void initIO() -{ - seedrandom( 1783 ); -} - -void doneIO() -{ -} - -int getrandom(int range) -{ - int neg = (range < 0); - if (!range) return 0; - int ret = 0; - if (neg) range = -range; - unsigned long i = isaac_rand( &isaac_ctx ); - i = i % range; - if (neg) ret = (int)(i*-1); - else ret = (int)i; - return ret; -} - -void seedrandom(int num) -{ - ub4 i; - isaac_ctx.randa = isaac_ctx.randb = isaac_ctx.randc = (ub4)0; - for (i=0; i<256; ++i) - { - isaac_ctx.randrsl[i]=(ub4)num+i; - } - randinit( &isaac_ctx, TRUE ); -} - -void seedrandomrandom() -{ - seedrandom( time( 0 ) ); -} - -int Agetint() -{ - int x; - cin >> x; - cleartoendl(); - return x; -} - -void Awrite(const AString & s) -{ - cout << s << ENDLINE; -} - -void Adot() -{ - cout << "."; -} - -void message(char * c) -{ - cout << c << ENDLINE; - morewait(); -} - -void morewait() -{ - cout << ENDLINE; - cin.getline(buf,256,ENDLINE); - cout << ENDLINE; -} - - -AString * getfilename(const AString & s) -{ - cout << s; - return( AGetString() ); -} - -AString *AGetString() -{ - cin.getline( buf, 256, ENDLINE ); - return( new AString( buf )); -} diff --git a/arcadia/gameio.h b/arcadia/gameio.h deleted file mode 100644 index 4260d9972..000000000 --- a/arcadia/gameio.h +++ /dev/null @@ -1,53 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef GAME_IO -#define GAME_IO - -#include "astring.h" - -void initIO(); -void doneIO(); - -/* Get a random number from 0 to (int-1) */ -int getrandom(int); -/* Seed the random number generator */ -void seedrandom(int); -void seedrandomrandom(); - -int Agetint(); - -void Awrite(const AString &); - -void Adot(); - -void message(char *); - -void morewait(); - -AString * getfilename(const AString &); -AString *AGetString(); - -#endif - diff --git a/arcadia/genrules.cpp b/arcadia/genrules.cpp deleted file mode 100644 index 399654b28..000000000 --- a/arcadia/genrules.cpp +++ /dev/null @@ -1,8300 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include - -#include "game.h" -#include "gamedata.h" -#include "fileio.h" - -AString NumToWord(int n) -{ - if(n > 20) return AString(n); - switch(n) { - case 0: return AString("zero"); - case 1: return AString("one"); - case 2: return AString("two"); - case 3: return AString("three"); - case 4: return AString("four"); - case 5: return AString("five"); - case 6: return AString("six"); - case 7: return AString("seven"); - case 8: return AString("eight"); - case 9: return AString("nine"); - case 10: return AString("ten"); - case 11: return AString("eleven"); - case 12: return AString("twelve"); - case 13: return AString("thirteen"); - case 14: return AString("fourteen"); - case 15: return AString("fifteen"); - case 16: return AString("sixteen"); - case 17: return AString("seventeen"); - case 18: return AString("eighteen"); - case 19: return AString("nineteen"); - case 20: return AString("twenty"); - } - return AString("error"); -} - -// LLS - converted HTML tags to lowercase -int Game::GenRules(const AString &rules, const AString &css, - const AString &intro) -{ - Ainfile introf; - Arules f; - AString temp, temp2; - int cap; - int i, j, k, l; - int last = -1; - AString skname; - SkillType *pS; - - if(f.OpenByName(rules) == -1) { - return 0; - } - - if(introf.OpenByName(intro) == -1) { - return 0; - } - - int qm_exist = (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT); - if (qm_exist) { - /* Make sure the S_QUARTERMASTER skill is enabled */ - if (SkillDefs[S_QUARTERMASTER].flags & SkillType::DISABLED) - qm_exist = 0; - } - int found = 0; - if (qm_exist) { - /* Make there is an enabled building with transport set */ - for(i = 0; i < NOBJECTS; i++) { - if (ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if (ObjectDefs[i].flags & ObjectType::TRANSPORT) { - found = 1; - break; - } - } - if (!found) qm_exist = 0; - } - - f.PutStr(""); - f.Enclose(1, "html"); - f.Enclose(1, "head"); - f.PutStr(""); - f.PutStr(AString(""); - temp = AString(Globals->RULESET_NAME) + " " + - ATL_VER_STR(Globals->RULESET_VERSION); - temp2 = temp + " Rules"; - f.TagText("title", temp2); - f.Enclose(0, "head"); - f.Enclose(1, "body"); - f.Enclose(1, "center"); - f.TagText("h1", AString("Rules for ") + temp); - f.TagText("h1", AString("Based on Atlantis v") + - ATL_VER_STR(CURRENT_ATL_VER)); - f.TagText("h2", AString("Copyright 1996 by Geoff Dunbar")); - f.TagText("h2", AString("Based on Russell Wallace's Draft Rules")); - f.TagText("h2", AString("Copyright 1993 by Russell Wallace")); - char buf[500]; - time_t tval = time(NULL); - struct tm *ltval = localtime(&tval); - strftime(buf, 500, "%B %d, %Y", ltval); - f.TagText("h3", AString("Last Change: ")+buf); - f.Enclose(0, "center"); - f.ClassTagText("div", "rule", ""); - temp = "Note: This document is subject to change, as errors are found " - "and corrected, and rules sometimes change. Be sure you have the " - "latest available copy."; - f.Paragraph(temp); - f.LinkRef("table_of_contents"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Table of Contents"); - f.Paragraph(""); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#intro", "Introduction")); - f.Enclose(1, "li"); - f.PutStr(f.Link("#playing", "Playing Atlantis")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#playing_factions", "Factions")); - f.TagText("li", f.Link("#playing_units", "Units")); - f.TagText("li", f.Link("#playing_turns", "Turns")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#world", "The World")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#world_regions", "Regions")); - f.TagText("li", f.Link("#world_structures", "Structures")); - if(Globals->NEXUS_EXISTS) { - temp = "Atlantis Nexus"; - f.TagText("li", f.Link("#world_nexus", temp)); - } - if(Globals->CONQUEST_GAME) { - temp = "The World of Atlantis Conquest"; - f.TagText("li", f.Link("#world_conquest", temp)); - } - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#movement", "Movement")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#movement_normal", "Normal Movement")); - if(!(SkillDefs[S_SAILING].flags & SkillType::DISABLED)) - f.TagText("li", f.Link("#movement_sailing", "Sailing")); - f.TagText("li", f.Link("#movement_order", "Order of Movement")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#skills", "Skills")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#skills_limitations", "Limitations")); - f.TagText("li", f.Link("#skills_studying", "Studying")); - f.TagText("li", f.Link("#skills_teaching", "Teaching")); - if(Globals->REAL_EXPERIENCE) { - f.TagText("li", f.Link("#skills_experience", "Experience")); - f.TagText("li", f.Link("#skills_overflow", "Overflow")); - } - f.TagText("li", f.Link("#skills_skillreports", "Skill Reports")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#economy", "The Economy")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#economy_maintenance", "Maintenance Costs")); - f.TagText("li", f.Link("#economy_recruiting", "Recruiting")); - f.TagText("li", f.Link("#economy_items", "Items")); - if(Globals->TOWNS_EXIST) - f.TagText("li", f.Link("#economy_towns", "Villages, Towns, Cities")); - f.TagText("li", f.Link("#economy_buildings", - "Buildings and Trade Structures")); - if(!(ObjectDefs[O_ROADN].flags & ObjectType::DISABLED)) - f.TagText("li", f.Link("#economy_roads", "Roads")); - if(Globals->DECAY) - f.TagText("li", f.Link("#economy_builddecay", "Building Decay")); - int may_sail = (!(SkillDefs[S_SAILING].flags & SkillType::DISABLED)) && - (!(SkillDefs[S_SHIPBUILDING].flags & SkillType::DISABLED) || !(SkillDefs[S_CONSTRUCTION].flags & SkillType::DISABLED)); - if(may_sail) - f.TagText("li", f.Link("#economy_ships", "Ships")); - f.TagText("li", f.Link("#economy_advanceditems", "Advanced Items")); - f.TagText("li", f.Link("#economy_income", "Income")); - if(!(SkillDefs[S_ENTERTAINMENT].flags & SkillType::DISABLED)) - f.TagText("li", f.Link("#economy_entertainment", "Entertainment")); - f.TagText("li", f.Link("#economy_taxingpillaging", "Taxing/Pillaging")); - if (qm_exist) - f.TagText("li", f.Link("#economy_transport", "Transporting goods")); - if(Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) - f.TagText("li", f.Link("#economy_banking", "Banking")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#com", "Combat")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#com_attitudes", "Attitudes")); - f.TagText("li", f.Link("#com_attacking", "Attacking")); - f.TagText("li", f.Link("#com_muster", "The Muster")); - f.TagText("li", f.Link("#com_thebattle", "The Battle")); - f.TagText("li", f.Link("#com_report", "The Battle Report")); - f.TagText("li", f.Link("#com_victory", "Victory!")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - - int has_stea = !(SkillDefs[S_STEALTH].flags & SkillType::DISABLED); - int has_obse = !(SkillDefs[S_OBSERVATION].flags & SkillType::DISABLED); - if(has_stea || has_obse) { - if(has_stea) temp = "Stealth"; - else temp = ""; - if(has_obse) { - if(has_stea) temp += " and "; - temp += "Observation"; - } - f.Enclose(1, "li"); - f.PutStr(f.Link("#stealthobs", temp)); - if(has_stea) { - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#stealthobs_stealing", "Stealing")); - f.TagText("li", f.Link("#stealthobs_assassination", - "Assassination")); - f.Enclose(0, "ul"); - } - f.Enclose(0, "li"); - } - - f.Enclose(1, "li"); - f.PutStr(f.Link("#magic", "Heroes and Magic")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#magic_skills", "Hero Skills")); - f.TagText("li", f.Link("#magic_foundations", "Foundations")); - f.TagText("li", f.Link("#magic_furtherstudy", "Further Hero Study")); - f.TagText("li", f.Link("#magic_usingmagic", "Using Hero Skills")); - f.TagText("li", f.Link("#magic_energy", "Magical Energy")); - f.TagText("li", f.Link("#magic_incombat", "Heroes In Combat")); - f.TagText("li", f.Link("#magic_miscellaneous", "Miscellaneous Hero Rules")); - if(Globals->EARTHSEA_VICTORY) f.TagText("li", f.Link("#magic_mastery", "Mage Masteries")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - - f.Enclose(1, "li"); - f.PutStr(f.Link("#nonplayers", "Non-Player Units")); - f.Enclose(1, "ul"); - if(Globals->TOWNS_EXIST && Globals->CITY_MONSTERS_EXIST) { - f.TagText("li", f.Link("#nonplayers_guards", - "City and Town Guardsmen")); - } - if(Globals->WANDERING_MONSTERS_EXIST) { - f.TagText("li", f.Link("#nonplayers_monsters", "Wandering Monsters")); - } - f.TagText("li", f.Link("#nonplayers_controlled", "Controlled Monsters")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#orders", "Orders")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#orders_abbreviations", "Abbreviations")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr(f.Link("#ordersummary", "Order Summary")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#address", "address")); - f.TagText("li", f.Link("#advance", "advance")); - f.TagText("li", f.Link("#all", "all")); - if(Globals->USE_WEAPON_ARMOR_COMMAND) - f.TagText("li", f.Link("#armour", "armour")); - if(has_stea) - f.TagText("li", f.Link("#assassinate", "assassinate")); - f.TagText("li", f.Link("#attack", "attack")); - f.TagText("li", f.Link("#autotax", "autotax")); - f.TagText("li", f.Link("#avoid", "avoid")); - if(Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) - f.TagText("LI", f.Link("#bank", "bank")); - f.TagText("li", f.Link("#behind", "behind")); - f.TagText("li", f.Link("#build", "build")); - f.TagText("li", f.Link("#buy", "buy")); - f.TagText("li", f.Link("#cast", "cast")); - f.TagText("li", f.Link("#claim", "claim")); - f.TagText("li", f.Link("#combat", "combat")); - f.TagText("li", f.Link("#command", "command")); - if (Globals->FOOD_ITEMS_EXIST) - f.TagText("li", f.Link("#consume", "consume")); - f.TagText("li", f.Link("#declare", "declare")); - f.TagText("li", f.Link("#describe", "describe")); - f.TagText("li", f.Link("#destroy", "destroy")); - f.TagText("li", f.Link("#disable", "disable")); - if (qm_exist) - f.TagText("li", f.Link("#distribute", "distribute")); - f.TagText("li", f.Link("#enter", "enter")); - if(!(SkillDefs[S_ENTERTAINMENT].flags & SkillType::DISABLED)) - f.TagText("li", f.Link("#entertain", "entertain")); - f.TagText("li", f.Link("#evict", "evict")); - f.TagText("li", f.Link("#exchange", "exchange")); - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) - f.TagText("li", f.Link("#faction", "faction")); - f.TagText("li", f.Link("#fightas", "fightas")); - f.TagText("li", f.Link("#find", "find")); - f.TagText("li", f.Link("#follow", "follow")); - f.TagText("li", f.Link("#forget", "forget")); - f.TagText("li", f.Link("#form", "form")); - f.TagText("li", f.Link("#give", "give")); - f.TagText("li", f.Link("#guard", "guard")); - f.TagText("li", f.Link("#hold", "hold")); - f.TagText("li", f.Link("#label", "label")); - f.TagText("li", f.Link("#leave", "leave")); - if(Globals->EARTHSEA_VICTORY) f.TagText("li", f.Link("#master", "master")); - f.TagText("li", f.Link("#move", "move")); - f.TagText("li", f.Link("#name", "name")); - f.TagText("li", f.Link("#noaid", "noaid")); - int move_over_water = 0; - if(Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) - move_over_water = 1; - if(!move_over_water) { - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(ItemDefs[i].swim > 0) move_over_water = 1; - } - } - if(move_over_water) - f.TagText("li", f.Link("#nocross", "nocross")); - f.TagText("li", f.Link("#option", "option")); - f.TagText("li", f.Link("#password", "password")); - f.TagText("li", f.Link("#pillage", "pillage")); - if(Globals->USE_PREPARE_COMMAND) - f.TagText("li", f.Link("#prepare", "prepare")); - f.TagText("li", f.Link("#produce", "produce")); - f.TagText("li", f.Link("#promote", "promote")); - f.TagText("li", f.Link("#quit", "quit")); - f.TagText("li", f.Link("#restart", "restart")); - f.TagText("li", f.Link("#reveal", "reveal")); - if (!(SkillDefs[S_SAILING].flags & SkillType::DISABLED)) - f.TagText("li", f.Link("#sail", "sail")); - if(Globals->TOWNS_EXIST) - f.TagText("li", f.Link("#sell", "sell")); - f.TagText("li", f.Link("#share", "share")); - if(Globals->SEND_COST >= 0) - f.TagText("li", f.Link("#send", "send")); - f.TagText("li", f.Link("#show", "show")); - f.TagText("li", f.Link("#spoils", "spoils")); - if(has_stea) - f.TagText("li", f.Link("#steal", "steal")); - f.TagText("li", f.Link("#study", "study")); - f.TagText("li", f.Link("#tactics", "tactics")); - f.TagText("li", f.Link("#tax", "tax")); - f.TagText("li", f.Link("#teach", "teach")); - f.TagText("li", f.Link("#template", "template")); - if (qm_exist) - f.TagText("li", f.Link("#transport", "transport")); - f.TagText("li", f.Link("#turn", "turn")); - f.TagText("li", f.Link("#type", "type")); - if(Globals->USE_WEAPON_ARMOR_COMMAND) - f.TagText("li", f.Link("#weapon", "weapon")); - if (Globals->ALLOW_WITHDRAW) { - f.TagText("li", f.Link("#withdraw", "withdraw")); - if(Globals->TESTGAME_ENABLED) { - f.TagText("li", f.Link("#wishdraw", "wishdraw")); - f.TagText("li", f.Link("#wishskill", "wishskill")); - } - } - f.TagText("li", f.Link("#work", "work")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.TagText("li", f.Link("#sequenceofevents", "Sequence of Events")); - f.TagText("li", f.Link("#reportformat", "Report Format")); - f.TagText("li", f.Link("#hintsfornew", "Hints for New Players")); - if(Globals->HAVE_EMAIL_SPECIAL_COMMANDS) { - f.Enclose(1, "li"); - f.PutStr(f.Link("#specialcommands", "Special Commands")); - f.Enclose(1, "ul"); - f.TagText("li", f.Link("#_create", "#Create")); - f.TagText("li", f.Link("#_resend", "#Resend")); - f.TagText("li", f.Link("#_times", "#Times")); - f.TagText("li", f.Link("#_rumor", "#Rumor")); - f.TagText("li", f.Link("#_remind", "#Remind")); - f.TagText("li", f.Link("#_email", "#Email")); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - f.TagText("li", f.Link("#credits", "Credits")); - f.TagText("li", f.Link("#appendixa", "Appendix A: FAQ")); - f.TagText("li", f.Link("#appendixb", "Appendix B: Monsters")); - f.TagText("li", f.Link("#appendixc", "Appendix C: Items")); - f.TagText("li", f.Link("#appendixd", "Appendix D: Weapons")); - f.TagText("li", f.Link("#appendixe", "Appendix E: Armour")); - f.TagText("li", f.Link("#appendixf", "Appendix F: Terrain")); - f.TagText("li", f.Link("#appendixg", "Appendix G: Guards")); - f.TagText("li", f.Link("#appendixh", "Appendix H: Skills")); - f.TagText("li", f.Link("#appendixi", "Appendix I: Combat Spells")); - f.Enclose(0, "ul"); - f.Paragraph("Index of Tables"); - f.Paragraph(""); - f.Enclose(1, "ul"); - if (Globals->FACTION_LIMIT_TYPE==GameDefs::FACLIM_FACTION_TYPES) - f.TagText("li", f.Link("#tablefactionpoints", - "Table of Faction Points")); - f.TagText("li", f.Link("#tableitemweights", "Table of Item Weights")); - if(Globals->HEXSIDE_TERRAIN) f.TagText("li", f.Link("#tablehexsideterrain", - "Table of Terrain Features")); - if(may_sail) - f.TagText("li", f.Link("#tableshipcapacities", - "Table of Ship Capacities")); - if(Globals->RACES_EXIST) - f.TagText("li", f.Link("#tableraces", "Table of Races")); - f.TagText("li", f.Link("#tableunittypes", "Table of Unit Types")); - f.TagText("li", f.Link("#tableiteminfo", "Table of Item Information")); - f.TagText("li", f.Link("#tablebuildings", "Table of Buildings")); - f.TagText("li", f.Link("#tabletradestructures", - "Table of Trade Structures")); - if(!(ObjectDefs[O_ROADN].flags & ObjectType::DISABLED)) - f.TagText("li", f.Link("#tableroadstructures", - "Table of Road Structures")); - if(may_sail) - f.TagText("li", f.Link("#tableshipinfo", "Table of Ship Information")); - f.TagText("li", f.Link("#tablebattleterrain", "Table of Battle Terrains")); - if(Globals->LIMITED_MAGES_PER_BUILDING) { - f.TagText("li", - f.Link("#tablemagebuildings", "Table of Mages/Building")); - } - f.Enclose(0, "ul"); - - f.LinkRef("intro"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Introduction"); - AString *in; - while((in = introf.GetStr()) != NULL) { - f.PutStr(*in); - delete in; - } - f.LinkRef("playing"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Playing Atlantis"); - temp = "Atlantis (as you undoubtedly already know) is a play by email " - "game. When you sign up for Atlantis, you will be sent a turn " - "report (via email). Your report completely details your position " - "in the game. After going over this report, and possibly " - "communicating with other players in the game, you determine your " - "course of action, and create a file of \"orders\", which you then " - "send back to the Atlantis server. Then, at a regular interval " - "(often one week), Atlantis collects all the orders, runs another " - "turn (covering one month in game time), and sends all the players " - "another report."; - f.Paragraph(temp); - temp = "This rules document outlines the rules of Nylandor, a game based " - "on the Atlantis engine. Because it includes all the rules for the game, it can " - "be a bit daunting to read through if you are new to Atlantis games " - "(and may be just another ruleset if you have played many). A good " - "guide about what the start of Atlantis is like - and covering most " - "of the basics for new players - can be found at http://www.voidspace.org.uk/voidspace/intro_atlantis.shtml. " - "This guide was written for Echelon, a similar game with " - "slightly different rules, so it may be wise to check back here " - "after reading it. For experienced players, the menu section 'Arcadia III specific changes' " - "outlines which sections of the rules have been changed from standard " - "Atlantis v5.0, and which you thus need to read in order to understand " - "the engine changes in Nylandor. Some items and monsters have also " - "been changed, details of these should be available in different files."; - f.Paragraph(temp); - - f.LinkRef("playing_factions"); - f.TagText("h3", "Factions:"); - temp = "A player's position is called a \"faction\". Each faction has " - "a name and a number (the number is assigned by the computer, and " - "used for entering orders). Each player is allowed to play one and " - "ONLY one faction at any given time. Each faction is composed of a " - "number of \"units\", each unit being a group of one or more people " - "loyal to the faction. You start the game with a single unit " - "consisting of one character, plus a sum of money. More people can " - "be hired during the course of the game, and formed into more " - "units. (In these rules, the word \"character\" generally refers " - "either to a unit consisting of only one person, or to a person " - "within a larger unit.)"; - f.Paragraph(temp); - temp = "A faction is considered destroyed, and the player knocked out " - "of the game, if ever all its people are killed or disbanded (i.e. " - "the faction has no units left). The program does not consider " - "your starting character to be special; if your starting character " - "gets killed, you will probably have been thinking of that character " - "as the leader of your faction, so some other character can be " - "regarded as having taken the dead leader's place (assuming of " - "course that you have at least one surviving unit!). As far as the " - "computer is concerned, as long as any unit of the faction " - "survives, the faction is not wiped out. (If your faction is " - "wiped out, you can rejoin the game with a new starting " - "character.)"; - f.Paragraph(temp); - Faction fac; - int app_exist = (Globals->APPRENTICES_EXIST); - if (app_exist) { - found = 0; - /* Make sure we have a skill with the APPRENTICE flag */ - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - if(SkillDefs[i].flags & SkillType::APPRENTICE) { - found = 1; - break; - } - } - if (!found) app_exist = 0; - } - - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) { - temp = "A faction has one pre-set limit; it may not contain more than "; - temp += AString(AllowedMages(&fac)) + " heroes"; - if(app_exist) { - temp += AString("and ") + AllowedApprentices(&fac) + " apprentices"; - } - temp += ". Heroes are rare, and only a few in the world have the abilities " - "to become heroes. Aside from that, there is no limit to the number " - "of units a faction may contain, nor to how many items can be " - "produced or regions taxed."; - f.Paragraph(temp); - } else if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp = "Each faction has a type; this is decided by the player, " - "and determines what the faction may do. The faction has "; - temp += Globals->FACTION_POINTS; - temp += " Faction Points, which may be spent on any of the 3 " - "Faction Areas, War, Trade, and Heroes. The faction type may " - "be changed at the beginning of each turn, so a faction can " - "change and adapt to the conditions around it. Faction Points " - "spent on War determine the number of regions in which factions " - "can obtain income by taxing or pillaging"; - if (Globals->TACTICS_NEEDS_WAR) { - temp += ", and also determines the number of level 5 tactics " - "leaders (tacticians) that a faction can train"; - } - temp += ". Faction Points spent " - "on Trade determine the number of regions in which a faction " - "may conduct trade activity. Trade activity includes producing " - "goods, building ships and buildings, and buying trade items. "; - if (qm_exist) { - temp += "Faction points spent on Trade also determine the " - "of quartermaster units a trade faction can have. "; - } - temp += "Faction Points spent on Heroes determine the number of heroes "; - if(app_exist) - temp += "and apprentices "; - temp += "the faction may have. (More information on all of the " - "faction activities is in further sections of the rules). Here " - "is a chart detailing the limits on factions by Faction Points."; - f.Paragraph(temp); - f.LinkRef("tablefactionpoints"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Faction Points"); - temp = "War (max tax regions"; - if(Globals->TACTICS_NEEDS_WAR) - temp += "/tacticians"; - temp += ")"; - f.TagText("th", temp); - temp = "Trade (max trade regions"; - if (qm_exist) - temp += "/quartermasters"; - temp += ")"; - f.TagText("th", temp); - temp = "Heroes (max heroes"; - if(app_exist) - temp += "/apprentices"; - temp += ")"; - f.TagText("th", temp); - f.Enclose(0, "tr"); - int i; - for(i = 0; i <= Globals->FACTION_POINTS; i++) { - fac.type[F_WAR]=i; - fac.type[F_TRADE]=i; - fac.type[F_MAGIC]=i; - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"center\" nowrap"); - f.PutStr(i); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - temp = AllowedTaxes(&fac); - if (Globals->TACTICS_NEEDS_WAR) - temp+= AString("/") + AllowedTacticians(&fac); - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - temp = AllowedTrades(&fac); - if (qm_exist) - temp += AString("/") + AllowedQuarterMasters(&fac); - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - temp = AllowedMages(&fac); - if(app_exist) - temp += AString("/") + AllowedApprentices(&fac); - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - f.PutStr("

"); - int m,w,t; - fac.type[F_WAR] = w = (Globals->FACTION_POINTS+1)/3; - fac.type[F_TRADE] = t = Globals->FACTION_POINTS/3; - fac.type[F_MAGIC] = m = (Globals->FACTION_POINTS+2)/3; - int nm, na, nw, nt, nq; - nm = AllowedMages(&fac); - na = AllowedApprentices(&fac); - nq = AllowedQuarterMasters(&fac); - nt = AllowedTrades(&fac); - nw = AllowedTaxes(&fac); - temp = "For example, a well rounded faction might spend "; - temp += AString(w) + " point" + (w==1?"":"s") + " on War, "; - temp += AString(t) + " point" + (t==1?"":"s") + " on Trade, and "; - temp += AString(m) + " point" + (m==1?"":"s") + " on Heroes. "; - temp += "This faction's type would appear as \"War "; - temp += AString(w) + " Trade " + t + " Heroes " + m; - temp += "\", and would be able to tax "; - temp += AString(nw) + " region" + (nw==1?"":"s") + ", "; - temp += "perform trade in "; - temp += AString(nt) + " region" + (nt==1?"":"s") + ", and have "; - temp += AString(nm) + " hero" + (nm==1?"":"es"); - if(app_exist) { - temp += " as well as "; - temp += AString(na) + " apprentice" + (na==1?"":"s"); - } - if (qm_exist) { - temp += " and "; - temp += AString(nq) + " quartermaster" + (nq==1?"":"s"); - } - temp += "."; - f.Paragraph(temp); - - fac.type[F_WAR] = w = Globals->FACTION_POINTS; - fac.type[F_MAGIC] = m = 0; - fac.type[F_TRADE] = t = 0; - nw = AllowedTaxes(&fac); - nq = AllowedQuarterMasters(&fac); - nt = AllowedTrades(&fac); - nm = AllowedMages(&fac); - na = AllowedApprentices(&fac); - temp = "As another example, a specialized faction might spend all "; - temp += AString(w) + " point" + (w==1?"":"s") + " on War. "; - temp += "This faction's type would appear as \"War "; - temp += AString(w) + "\", and it would be able to tax " + nw; - temp += AString(" region") + (nw==1?"":"s") + ", but could "; - if(nt == 0) - temp += "not perform trade in any regions"; - else - temp += AString("only perform trade in ") + nt + " region" + - (nt == 1?"":"s"); - temp += ", "; - if(!app_exist) - temp += "and "; - if(nm == 0) - temp += "could not possess any heroes"; - else - temp += AString("could only possess ") + nm + " hero" + - (nm == 1?"":"es"); - if(app_exist) { - temp += ", and "; - if(na == 0) - temp += "could not possess any apprentices"; - else - temp += AString("could only possess ") + na + " apprentice" + - (na == 1?"":"s"); - } - if (qm_exist) { - temp += ", and "; - if (nq == 0) - temp += "count not possess any quartermasters"; - else - temp += AString("could only possess ") + nq + - "quartermaster" + (nq == 1?"":"s"); - } - temp += "."; - f.Paragraph(temp); - if (Globals->FACTION_POINTS>3) { - int rem=Globals->FACTION_POINTS-3; - temp = "Note that it is possible to have a faction type with " - "less than "; - temp += Globals->FACTION_POINTS; - temp += " points spent. In fact, a starting faction has one " - "point spent on each of War, Trade, and Heroes, leaving "; - temp += AString(rem) + " point" + (rem==1?"":"s") + " unspent."; - f.Paragraph(temp); - } - } - - temp = "Each faction also has an ethnicity. This is determined by the " - "ethnicity of the hero commanding your faction, as set with the "; - temp += f.Link("#command", "COMMAND") + " order. The ethnicity of your " - "faction determines how expensive it is to keep units; for example " - "a dwarvish faction will pay only half as much to employ a dwarf as " - "to employ an elf, human or orc. To change your faction's " - "ethnicity, you must have a hero of the ethnicity you wish your " - "faction to become, and use the "; - temp += f.Link("#command", "COMMAND") + " order to get him or her to take " - "command of your faction."; - f.Paragraph(temp); - - temp = "When a faction starts the game, it is given a one-man unit and "; - temp += Globals->START_MONEY; - temp += " silver in unclaimed money. Unclaimed money is cash that your " - "whole faction has access to, but cannot be taken away in battle (" - "silver in a unit's possessions can be taken in battle). This allows " - "a faction to get started without presenting an enticing target for " - "other factions. Units in your faction may use the "; - temp += f.Link("#claim", "CLAIM") + " order to take this silver, and use " - "it to buy goods or recruit men"; - if(Globals->ALLOW_WITHDRAW) { - temp += ", or use the "; - temp += f.Link("#withdraw", "WITHDRAW"); - temp += " order to withdraw goods directly"; - } - temp += "."; - f.Paragraph(temp); - temp = "An example faction is shown below, consisting of a starting " - "character, Merlin the Magician, who has formed two more units, " - "Merlin's Guards and Merlin's Workers. Each unit is assigned a " - "unit number by the computer (completely independent of the " - "faction number); this is used for entering orders. Here, the " - "player has chosen to give his faction the same name (\"Merlin " - "the Magician\") as his starting character. Alternatively, you " - "can call your faction something like \"The Great Northern " - "Mining Company\" or whatever."; - f.Paragraph(temp); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.ClearWrapTab(); - if(Globals->LEADERS_EXIST) { - f.WrapStr("* Merlin the Magician (17), Merlin (27), leader [LEAD]. " - "Skills: none."); - } else { - f.WrapStr("* Merlin the Magician (17), Merlin (27), wood elf [WELF]. " - "Skills: none."); - } - if(Globals->RACES_EXIST) { - f.WrapStr("* Merlin's Guards (33), Merlin (27), 20 vikings [VIKI], " - "20 swords [SWOR]. Skills: none."); - f.WrapStr("* Merlin's Workers (34), Merlin (27), 50 vikings " - "[VIKI]. Skills: none."); - } else { - f.WrapStr("* Merlin's Guards (33), Merlin (27), 20 men [MAN], " - "20 swords [SWOR]. Skills: none."); - f.WrapStr("* Merlin's Workers (34), Merlin (27), 50 men [MAN]. " - "Skills: none."); - } - f.Enclose(0, "pre"); - f.LinkRef("playing_units"); - f.TagText("h3", "Units:"); - temp = "A unit is a grouping together of people, all loyal to the " - "same faction. The people in a unit share skills and possessions, " - "and execute the same orders each month. The reason for having " - "units of many people, rather than keeping track of individuals, " - "is to simplify the game play. The computer does not keep track of " - "individual names, possessions, or skills for people in the same " - "unit, and all the people in a particular unit must be in the same " - "place at all times. If you want to send people in the same unit " - "to different places, you must split up the unit. Apart from " - "this, there is no difference between having one unit of 50 people, " - "or 50 units of one person each, except that the former is very " - "much easier to handle."; - f.Paragraph(temp); - if(Globals->RACES_EXIST) { - temp = "There are different races that make up the population of " - "Atlantis. (See the section on skills for a list of these.)"; - if(Globals->LEADERS_EXIST) { - temp += " In addition, there are \"leaders\", who are presumed " - "to be of one of the other races, but are all the same " - "in game terms."; - } - } else { - temp = "Units are made of of ordinary people"; - if(Globals->LEADERS_EXIST) { - temp += "as well as leaders"; - } - temp += "."; - } - if (Globals->LEADERS_EXIST&&Globals->SKILL_LIMIT_NONLEADERS) { - temp += " Units made up of normal people may only know one skill, " - "and cannot teach other units. Units made up of leaders " - "may know as many skills as desired, and may teach other " - "units to speed the learning process."; - } - if (Globals->LEADERS_EXIST) { - temp += " Leaders and normal people may not be mixed in the same " - "unit. However, leaders are more expensive to recruit and " - "maintain. (More information is in the section on skills.)"; - } - if (Globals->RACES_EXIST) { - temp += " A unit is treated as the least common denominator of " - "the people within it, so a unit made up of two races with " - "different strengths and weaknesses will have all the " - "weaknesses, and none of the strengths of either race."; - } - f.Paragraph(temp); - f.LinkRef("playing_turns"); - f.TagText("h3", "Turns:"); - temp = "Each turn, the Atlantis server takes the orders file that " - "you mailed to it, and assigns the orders to the respective units. " - "All units in your faction are completely loyal to you, and will " - "execute the orders to the best of their ability. If the unit does " - "something unintended, it is generally because of incorrect orders; " - "a unit will not purposefully betray you."; - f.Paragraph(temp); - temp = "A turn is equal to one game month. A unit can do many actions " - "at the start of the month, that only take a matter of hours, such " - "as buying and selling commodities, or fighting an opposing " - "faction. Each unit can also do exactly one action that takes up " - "the entire month, such as harvesting resources or moving from one " - "region to another. The orders which take an entire month are "; - temp += f.Link("#advance", "ADVANCE") + ", "; - temp += f.Link("#build", "BUILD") + ", "; - if(!(SkillDefs[S_ENTERTAINMENT].flags & SkillType::DISABLED)) - temp += f.Link("#entertain", "ENTERTAIN") + ", "; - temp += f.Link("#move", "MOVE") + ", "; - if (Globals->TAX_PILLAGE_MONTH_LONG) - temp += f.Link("#pillage", "PILLAGE") + ", "; - temp += f.Link("#produce", "PRODUCE") + ", "; - if(!(SkillDefs[S_SAILING].flags & SkillType::DISABLED)) - temp += f.Link("#sail", "SAIL") + ", "; - temp += f.Link("#study", "STUDY") + ", "; - if (Globals->TAX_PILLAGE_MONTH_LONG) - temp += f.Link("#tax", "TAX") + ", "; - temp += f.Link("#teach", "TEACH") + " and "; - temp += f.Link("#work", "WORK") + "."; - f.Paragraph(temp); - f.LinkRef("world"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "The World"); - temp = "The Atlantis world is divided for game purposes into " - "hexagonal regions. Each region has a name, and " - "a type, such as: Ocean, Plain, Forest, Mountain, "; - if(Globals->CONQUEST_GAME) - temp += "or "; - temp += "Swamp"; - if(!Globals->CONQUEST_GAME) - temp += ", Jungle, Desert, or Tundra"; - temp += ". (There may be other types of terrain to be discovered as the " - "game progresses.) Regions can contain units belonging to players; " - "they can also contain structures such as buildings"; - if(may_sail) - temp += " and ships"; - temp += ". Two units in the same region can normally interact, unless " - "one of them is concealed in some way. Two units in different " - "regions cannot normally interact. NOTE: Combat is an exception " - "to this."; - f.Paragraph(temp); - f.LinkRef("world_regions"); - f.TagText("h3", "Regions:"); - temp = "Here is a sample region, as it might appear on your turn report:"; - f.Paragraph(temp); - f.Paragraph(""); - - int manidx = -1; - int leadidx = -1; - - for (i = 0; i < NITEMS; i++) { - if (!(ItemDefs[i].type & IT_MAN)) continue; - if (ItemDefs[i].type & IT_LEADER) { - if (leadidx == -1) leadidx = i; - } else { - if (manidx == -1) manidx = i; - } - } - - f.Enclose(1, "pre"); - f.ClearWrapTab(); - temp = "plain (172,110) in Turia, 500 peasants"; - if(Globals->RACES_EXIST) - temp += AString(" (") + ItemDefs[manidx].names + ")"; - int money = (500 * (15 - Globals->MAINTENANCE_COST)); - temp += AString(", $") + money + "."; - f.WrapStr(temp); - f.WrapStr("------------------------------------------------------"); - f.AddWrapTab(); - if (Globals->WEATHER_EXISTS) - f.WrapStr("The weather was clear last month; it will be clear next " - "month."); - temp = AString("Wages: $15 (Max: $") + (money/Globals->WORK_FRACTION) + - ")."; - f.WrapStr(temp); - f.WrapStr("Wanted: none."); - temp = "For Sale: 50 "; - temp += AString(ItemDefs[manidx].names) + " [" + ItemDefs[manidx].abr + "]"; - temp += " at $"; - float ratio = ItemDefs[(Globals->RACES_EXIST?I_NOMAD:I_MAN)].baseprice/ - (float)Globals->BASE_MAN_COST; - temp += (int)(60*ratio); - if(Globals->LEADERS_EXIST) { - ratio = ItemDefs[leadidx].baseprice/(float)Globals->BASE_MAN_COST; - temp += AString(", 10 ") + ItemDefs[leadidx].names + " [" + - ItemDefs[leadidx].abr + "] at $"; - temp += (int)(60*ratio); - } - temp += "."; - f.WrapStr(temp); - temp = AString("Entertainment available: $") + - (money/Globals->ENTERTAIN_FRACTION) + "."; - f.WrapStr(temp); - temp = "Products: "; - if(Globals->FOOD_ITEMS_EXIST) - temp += "23 grain [GRAI], "; - temp += "37 horses [HORS]."; - f.WrapStr(temp); - f.PutNoFormat(""); - f.PutNoFormat("Exits:"); - if(Globals->HEXSIDE_TERRAIN) { - f.WrapStr("North : ocean (172,108) in Atlantis Ocean. Beach."); - f.WrapStr("Northeast : ocean (173,109) in Atlantis Ocean. Beach."); - f.WrapStr("Southeast : ocean (173,111) in Atlantis Ocean. Rocks."); - f.WrapStr("South : plain (172,112) in Turia. River, Bridge."); - f.WrapStr("Southwest : plain (171,111) in Turia."); - f.WrapStr("Northwest : plain (171,109) in Turia. Ravine."); - } else { - f.WrapStr("North : ocean (172,108) in Atlantis Ocean."); - f.WrapStr("Northeast : ocean (173,109) in Atlantis Ocean."); - f.WrapStr("Southeast : ocean (173,111) in Atlantis Ocean."); - f.WrapStr("South : plain (172,112) in Turia."); - f.WrapStr("Southwest : plain (171,111) in Turia."); - f.WrapStr("Northwest : plain (171,109) in Turia."); - } - f.PutNoFormat(""); - f.DropWrapTab(); - temp = "* Hans Shadowspawn (15), Merry Pranksters (14), "; - if(Globals->LEADERS_EXIST) - temp2 = "leader [LEAD]"; - else if(Globals->RACES_EXIST) - temp2 = "nomad [NOMA]"; - else - temp2 = "man [MAN]"; - temp += temp2 + ", 500 silver [SILV]. Skills: none."; - f.WrapStr(temp); - temp = AString("- Vox Populi (13), ") + temp2 + "."; - f.WrapStr(temp); - f.Enclose(0, "pre"); - temp = "This report gives all of the available information on this " - "region. The region type is plain, the name of the surrounding area " - "is Turia, and the coordinates of this region are (172,110). The " - "population of this region is 500 "; - if(Globals->RACES_EXIST) - temp += "nomads"; - else - temp += "peasants"; - temp += AString(", and there is $") + money + " of taxable income "; - temp += "currently in this region. Then, under the dashed line, are " - "various details about items for sale, wages, etc. "; - if (Globals->HEXSIDE_TERRAIN) temp += "Below this is " - "a list of exits, detailing which hexes a unit can travel to from " - "this one, as well as any terrain (eg rivers, beaches) which is between " - "here and there. Finally, " - "there is a list of all visible units. Units that belong to your " - "faction will be so denoted by a '*', whereas other faction's " - "units are preceded by a '-'."; - f.Paragraph(temp); - temp = "Since Atlantis is made up of hexagonal regions, the coordinate " - "system is not always exactly intuitive. Here is the layout of " - "Atlantis regions:"; - f.Paragraph(temp); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.PutNoFormat(" ____ ____"); - f.PutNoFormat(" / \\ / \\"); - f.PutNoFormat(" /(0,0) \\____/(2,0) \\____/"); - f.PutNoFormat(" \\ / \\ / \\ N"); - f.PutNoFormat(" \\____/(1,1) \\____/(3,1) \\_ |"); - f.PutNoFormat(" / \\ / \\ / |"); - f.PutNoFormat(" /(0,2) \\____/(2,2) \\____/ |"); - f.PutNoFormat(" \\ / \\ / \\ W-O-E"); - f.PutNoFormat(" \\____/(1,3) \\____/(3,3) \\_ |"); - f.PutNoFormat(" / \\ / \\ / S"); - f.PutNoFormat(" /(0,4) \\____/(2,4) \\____/"); - f.PutNoFormat(" \\ / \\ / \\"); - f.PutNoFormat(" \\____/ \\____/"); - f.PutNoFormat(" / \\ / \\"); - f.Enclose(0, "pre"); - temp = "Note that the are \"holes\" in the coordinate system; there " - "is no region (1,2), for instance. This is due to the hexagonal " - "system of regions."; - f.Paragraph(temp); - temp = "Most regions are similar to the region shown above, but the " - "are certain exceptions. Oceans, not surprisingly, have no " - "population."; - if (Globals->TOWNS_EXIST) - temp += " Some regions will contain villages, towns, and cities. " - "More information on these is available in the section on the " - "ecomony."; - f.Paragraph(temp); - f.LinkRef("world_structures"); - f.TagText("h3", "Structures:"); - temp = "Regions may also contain structures, such as buildings"; - if(may_sail) - temp += " or ships"; - temp += ". These will appear directly below the list of units. Here is " - "a sample structure:"; - f.Paragraph(temp); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.ClearWrapTab(); - f.WrapStr("+ Temple of Agrik [3] : Tower."); - f.AddWrapTab(); - temp = "- High Priest Chafin (9), "; - temp += temp2 + ", sword [SWOR]"; - f.WrapStr(temp); - temp = "- Rowing Doom (188), "; - if(Globals->RACES_EXIST) - temp += "10 nomads [NOMA]"; - else if(Globals->LEADERS_EXIST) - temp += "10 leaders [LEAD]"; - else - temp += "10 men [MAN]"; - temp += ", 10 swords [SWOR]."; - f.WrapStr(temp); - f.Enclose(0, "pre"); - temp = "The structure lists the name, the number, and what type of " - "structure it is. (More information of the types of structures " - "can be found in the section on the economy.) Following this " - "is a list of units inside the structure."; - if (has_stea) - temp += " Units within a structure are always visible, even if " - "they would otherwise not be seen."; - f.Paragraph(temp); - temp = "Units inside structures are still considered to be in the " - "region, and other units can interact with them; however, they " - "may gain benefits, such as defensive bonuses in combat from being " - "inside a building. The first unit to enter an object is " - "considered to be the owner; only this unit can do things such as " - "renaming the object, or permitting other units to enter. The owner " - "of an object can be identified on the turn report, as it is the " - "first unit listed under the object. Only units with men in them " - "can be structure owners, so newly created units cannot own a " - "structure until they contain men."; - f.Paragraph(temp); - if(Globals->NEXUS_EXISTS) { - f.LinkRef("world_nexus"); - temp = "Atlantis Nexus:"; - f.TagText("h3", temp); - temp = "Note: the following section contains some details that " - "you may wish to skip over until you have had a chance to " - "read the rest of the rules, and understand the mechanics " - "of Atlantis. However, be sure to read this section before " - "playing, as it will affect your early plans in Atlantis."; - f.Paragraph(temp); - temp = "When a faction first starts in Atlantis, it begins with " - "one unit, in a special region called the Atlantis Nexus."; - if(Globals->MULTI_HEX_NEXUS) - temp += " These regions exist "; - else - temp += " This region exists "; - if (!Globals->NEXUS_IS_CITY) { - temp += "outside of the normal world of Atlantis, and as such "; - if(Globals->MULTI_HEX_NEXUS) - temp += "have "; - else - temp += "has "; - temp += "no products or marketplaces; "; - if(Globals->MULTI_HEX_NEXUS) - temp += "they merely serve "; - else - temp += "it merely serves "; - temp += "as the magical entry into Atlantis."; - } else { - temp += "outside of the normal world of Atlantis, but "; - if(Globals->MULTI_HEX_NEXUS) - temp += "each contains "; - else - temp += "contains "; - temp += "a starting city with all its benefits"; - if(Globals->GATES_EXIST) - temp += ", including a gate"; - temp += ". "; - if(Globals->MULTI_HEX_NEXUS) - temp += "They also serve "; - else - temp += "It also serves "; - temp += "as the magical entry into "; - temp += Globals->WORLD_NAME; - temp += "."; - } - f.Paragraph(temp); - if(Globals->MULTI_HEX_NEXUS) { - temp = "From the Nexus hexes, there are exits either to other " - "Nexus hexes, or to starting cities in Atlantis. Units may " - "move through these exits as normal, but once in a starting " - "city, there is no way to regain entry to the Nexus."; - } else { - temp = "From the Atlantis Nexus, there are six exits into the " - "starting cities of Atlantis. Units may move through " - "these exits as normal, but once through an exit, there is " - "no return path to the Nexus."; - } - if(Globals->GATES_EXIST && - (Globals->NEXUS_GATE_OUT || Globals->NEXUS_IS_CITY)) { - temp += " It is also possible to use Gate Lore to get out of " - "Nexus"; - if(Globals->NEXUS_GATE_OUT && !Globals->NEXUS_IS_CITY) - temp += " (but not to return)"; - temp += "."; - } - temp += " The "; - if(!Globals->MULTI_HEX_NEXUS) - temp += "six "; - temp += "starting cities offer much to a starting faction; "; - if(Globals->START_CITIES_START_UNLIMITED) { - if (!Globals->SAFE_START_CITIES && Globals->CITY_MONSTERS_EXIST) - temp += "until someone conquers the guardsmen, "; - temp += "there are unlimited amounts of many materials and men " - "(though the prices are often quite high)."; - } else { - temp += "there are materials as well as a very large supply of " - "men (though the prices are often quite high)."; - } - if(Globals->SAFE_START_CITIES || Globals->CITY_MONSTERS_EXIST) - temp += " In addition, "; - if(Globals->SAFE_START_CITIES) - temp += "no battles are allowed in starting cities"; - if(Globals->CITY_MONSTERS_EXIST) { - if(Globals->SAFE_START_CITIES) temp += " and "; - temp += "the starting cities are guarded by strong guardsmen, " - "keeping any units within the city "; - if(!Globals->SAFE_START_CITIES) - temp += "much safer "; - else - temp += "safe "; - temp += "from attack. See the section on Non-Player Units for " - "more information on city guardsmen"; - } - temp += ". "; - temp += "As a drawback, these cities tend to be extremely crowded, " - "and most factions will wish to leave the starting cities when " - "possible."; - f.Paragraph(temp); - temp = "It is always possible to enter any starting city from the " - "nexus"; - if(!Globals->SAFE_START_CITIES) - temp += ", even if that starting city has been taken over and " - "guarded by another faction"; - temp += ". This is due to the transportation from the Nexus to the " - "starting city being magical in nature."; - if(!Globals->SAFE_START_CITIES) - temp += " Once in the starting city however, no gaurentee of " - "safety is given."; - f.Paragraph(temp); - int num_methods = 1 + (Globals->GATES_EXIST?1:0) + (may_sail?1:0); - char *methods[] = {"You must go ", "The first is ", "The second is "}; - int method = 1; - if (num_methods == 1) method = 0; - temp = AString("There ") + (num_methods == 1?"is ":"are ") + - NumToWord(num_methods) + " method" + (num_methods == 1?" ":"s ") + - "of departing the starting cities. "; - temp += methods[method++]; - temp += " by land, but keep in mind that the lands immediately " - "surrounding the starting cities will tend to be highly " - "populated, and possibly quite dangerous to travel."; - if(may_sail) { - temp += AString(" ") + methods[method]; - temp += " by sea; all of the starting cities lie against an " - "ocean, and a faction may easily purchase wood and " - "construct a ship to "; - temp += f.Link("#sail", "SAIL"); - temp += " away. Be wary of pirates seeking to prey on new " - "factions, however!"; - } - if (Globals->GATES_EXIST) { - temp += " And last, rumors of a magical Gate Lore suggest yet " - "another way to travel from the starting cities. The rumors " - "are vague, but factions wishing to travel far from the " - "starting cities, taking only a few men with them, might " - "wish to pursue this method."; - } - f.Paragraph(temp); - } - if(Globals->CONQUEST_GAME) { - f.LinkRef("world_conquest"); - f.TagText("h3", "The World of Atlantis Conquest"); - temp = "In a game of Atlantis Conquest, each player begins the " - "game on a small island of 8 regions, seperated by ocean from " - "the rest of the players. The starting islands are located " - "around the perimeter of a larger central island. Sailing from " - "the starting islands towards the center of the map should " - "lead to the central island within a few regions."; - f.Paragraph(temp); - } - - f.LinkRef("movement"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Movement"); - if(may_sail) - temp = "There are two main methods of movement in Atlantis. The " - "first "; - else - temp = "The main method of movement in Atlantis "; - temp += "is done using the "; - temp += f.Link("#move", "MOVE") + " order (or the " + - f.Link("#advance", "ADVANCE") + " or " + - f.Link("#follow", "FOLLOW"); - temp += " order), and moves units individually from one region to " - "another. "; - if(may_sail) { - temp += "The other method is done using the "; - temp += f.Link("#sail", "SAIL") + " order (or the " + - f.Link("#follow", "FOLLOW") + "order), which can sail a "; - temp += "ship and all of its occupants from one region to " - "another. "; - } - temp += "Certain powerful mages may also teleport themselves, or even " - "other units, but the knowledge of the workings of this magic is " - "carefully guarded."; - f.Paragraph(temp); - - f.LinkRef("movement_normal"); - f.TagText("h3", "Normal Movement:"); - temp = "In one month, a unit can issue a single "; - temp += f.Link("#move", "MOVE") + " order, using one or more of its " - "movement points. There are three modes of travel: walking, riding " - "and flying. Walking units have "; - temp += NumToWord(Globals->FOOT_SPEED) + " movement point" + - (Globals->FOOT_SPEED==1?"":"s") + ", riding units have "; - temp += NumToWord(Globals->HORSE_SPEED) + ", and flying units have "; - temp += NumToWord(Globals->FLY_SPEED) + ". "; - temp += "A unit will automatically use the fastest mode of travel " - "it has available. The "; - temp += f.Link("#advance", "ADVANCE") + " order is the same as " + - f.Link("#move", "MOVE") + ", except that it implies attacks on " + - "units which try to forbid access; see the section on combat for " + - "details. The "; - temp += f.Link("#follow", "FOLLOW") + " order tells a unit to move in " - "tandem with another unit, or to not move if that unit is not moving " - "or not present."; - f.Paragraph(temp); - - temp = "Flying units are not initially available to starting players. " - "A unit can ride provided that the carrying capacity of its " - "horses is at least as great as the weight of its people and " - "all other items. A unit can walk provided that the carrying " - "capacity of its people"; - if(!(ItemDefs[I_HORSE].flags & ItemType::DISABLED)) { - if(!(ItemDefs[I_WAGON].flags & ItemType::DISABLED)) temp += ", "; - else temp += " and "; - temp += "horses"; - } - if(!(ItemDefs[I_WAGON].flags & ItemType::DISABLED) && - (!(ItemDefs[I_HORSE].flags & ItemType::DISABLED))) { - temp += ", and wagons"; - } - temp += " is at least as great as the weight of all its other items"; - if(!(ItemDefs[I_WAGON].flags & ItemType::DISABLED) && - (!(ItemDefs[I_HORSE].flags & ItemType::DISABLED))) { - temp += ", and provided that it has at least as many horses as " - "wagons (otherwise the excess wagons count as weight, not " - "capacity)"; - } - temp += ". Otherwise the unit cannot issue a "; - temp += f.Link("#move", "MOVE") + " order."; - temp += " Most people weigh 10 units and have a capacity of 5 units; " - "data for items is as follows:"; - f.Paragraph(temp); - f.LinkRef("tableitemweights"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", ""); - f.TagText("th", "Weight"); - f.TagText("th", "Capacity"); - f.Enclose(0, "tr"); - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[i].type & IT_NORMAL)) continue; - pS = FindSkill(ItemDefs[i].pSkill); - if(pS && (pS->flags & SkillType::DISABLED)) continue; - last = 0; - for(j = 0; j < (int) (sizeof(ItemDefs->pInput) / - sizeof(ItemDefs->pInput[0])); j++) { - k = ItemDefs[i].pInput[j].item; - if(k != -1 && (ItemDefs[k].flags & ItemType::DISABLED)) - last = 1; - if(k != -1 && !(ItemDefs[k].type & IT_NORMAL)) last = 1; - } - if(last == 1) continue; - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].weight); - f.Enclose(0, "td"); - cap = ItemDefs[i].walk - ItemDefs[i].weight; - f.Enclose(1, "td align=\"left\" nowrap"); - if(ItemDefs[i].walk || (ItemDefs[i].hitchItem != -1)) { - if(ItemDefs[i].hitchItem == -1) - f.PutStr(cap); - else { - temp = (cap + ItemDefs[i].hitchwalk); - temp += " (with "; - temp += ItemDefs[ItemDefs[i].hitchItem].name; - temp += ")"; - f.PutStr(temp); - } - } else { - f.PutStr(" "); - } - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - if(Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) { - temp = "A unit which can fly, is capable of travelling over water."; - if(Globals->FLIGHT_OVER_WATER == GameDefs::WFLIGHT_MUST_LAND) - temp += " However, if the unit ends its turn over a water hex " - "that unit will drown."; - f.Paragraph(temp); - } - - temp = "Since regions are hexagonal, each region has six neighbouring " - "regions to the north, northeast, southeast, south, southwest and " - "northwest. Moving from one region to another takes one " - "or more movement points, depending on the type of region the unit " - "is moving into (the region it is departing does not affect movement " - "cost) and the weather. Moving into a "; - int first = 1; - for(int i=0; iWEATHER_EXISTS) { - temp += " During certain seasons (depending on the latitude " - "of the region), all units (including flying ones) have a " - "harder time and travel will take twice as many movement " - "points as normal as freezing weather makes travel difficult; " - "in the tropics, seasonal hurricane winds and torrential " - "rains have a similar effect. "; - } - temp += " Units may not move through ocean regions "; - if(may_sail) { - temp += "without using the "; - temp += f.Link("#sail", "SAIL") + " order, unless they can swim"; - } - if(Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) { - temp += " or fly"; - if (Globals->FLIGHT_OVER_WATER==GameDefs::WFLIGHT_MUST_LAND) { - temp += ", and even then, flying units must end their " - "movement on land or else drown"; - } - } - temp += "."; - f.Paragraph(temp); - - if(Globals->HEXSIDE_TERRAIN) { - temp = "There are also terrain features found " - "on the edges between regions, which may affect movement. These are " - "listed in the table below."; - f.Paragraph(temp); - - temp = "Note that the effects listed in this table do not apply to flying units."; - f.Paragraph(temp); - - f.LinkRef("tablehexsideterrain"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", " Feature "); - f.TagText("th", " Movement Effect"); - f.TagText("th", " Other Effects "); - f.TagText("th", " Cost to build"); - f.TagText("th", " Skill Required "); - f.Enclose(0, "tr"); - for(i = 1; i < NHEXSIDES; i++) { - if(HexsideDefs[i].flags & HexsideType::DISABLED) continue; - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(HexsideDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - temp = ""; - if(HexsideDefs[i].movementmultiplier != 0) { - temp += "Movement cost is "; - if(HexsideDefs[i].movementmultiplier == -1) temp += "halved"; - else if(HexsideDefs[i].movementmultiplier == 2) temp += "doubled"; - else temp += AString("multiplied by ") + (HexsideDefs[i].movementmultiplier+2) + "/" + 2; - temp += "."; - } - if(HexsideDefs[i].blockeffect != 0) { - if(HexsideDefs[i].blockeffect>0) temp += "Prevents movement."; - else { - temp += "Allows passage over "; - int done = 0; - for(j = 0; j < NHEXSIDES; j++) { - if(HexsideDefs[j].flags & HexsideType::DISABLED) continue; - if(HexsideDefs[j].blockeffect == - HexsideDefs[i].blockeffect) { - if(done) temp += ", "; - else done = 1; - temp += HexsideDefs[j].name; - temp += "s"; - } - } - if(done) temp += "."; - } - } - if (temp == "") temp = "--"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - temp = ""; - if(HexsideDefs[i].stealthpen != 0) { - temp += AString("Passage reduces unit's stealth by 2 until next CAST round. "); //value coded into stealth attributes for flag "visib" - } - if(HexsideDefs[i].advancepen != 0) { - temp += AString("Combat malus of ") + HexsideDefs[i].advancepen + " when advancing or aiding. "; - } - if(HexsideDefs[i].sailable != 0) { - temp += "Allows sailing of "; - if(HexsideDefs[i].sailable == 1) temp += "shallow water ships."; - if(HexsideDefs[i].sailable == 2) temp += "deep water ships."; - if(HexsideDefs[i].sailable == 3) temp += "all ships. Can only be built on beaches."; - } - if (temp == "") temp = "--"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - pS = FindSkill(HexsideDefs[i].skill); - if(pS != NULL) { - temp = AString(HexsideDefs[i].cost) + " "; - if(HexsideDefs[i].item != -2) temp += ItemDefs[HexsideDefs[i].item].name; - else temp += "wood or stone"; - } else temp = "--"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - if(pS != NULL) temp = AString(pS->name) + " " + HexsideDefs[i].level; - else temp = "--"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - } - - temp = "Units may also enter or exit structures while moving. Moving " - "into or out of a structure does not use any movement points at " - "all. Note that a unit can also use the "; - temp += f.Link("#enter", "ENTER") + " and " + f.Link("#leave", "LEAVE"); - temp += " orders to move in and out of structures, without issuing a "; - temp += f.Link("#move", "MOVE") + " order."; - temp += " The unit can also use the "; - temp += f.Link("#move", "MOVE") + " order to enter or leave a structure."; - f.Paragraph(temp); - if(Globals->UNDERWORLD_LEVELS || Globals->UNDERDEEP_LEVELS) { - temp = "Finally, certain structures contain interior passages to " - "other regions. The "; - temp += f.Link("#move", "MOVE") + " IN order can be used to go "; - temp += "through these passages; the movement point cost is equal " - "to the normal cost to enter the destination region."; - f.Paragraph(temp); - } - temp = "Example: One man with a horse, sword, and chain mail wants to " - "move north, then northeast. The capacity of the horse is "; - cap = ItemDefs[I_HORSE].ride - ItemDefs[I_HORSE].weight; - temp += cap; - temp += " and the weight of the man and other items is "; - int weight = ItemDefs[I_MAN].weight + ItemDefs[I_SWORD].weight + - ItemDefs[I_CHAINARMOR].weight; - temp += weight; - if(cap > weight) - temp += ", so he can ride"; - else - temp += ", so he must walk"; - if(Globals->WEATHER_EXISTS) - temp += ". The month is April, so he has "; - else - temp += " and has "; - temp += NumToWord(Globals->HORSE_SPEED); - int travel = Globals->HORSE_SPEED; - temp += " movement point"; - temp += AString((Globals->HORSE_SPEED == 1) ? "" : "s") + ". "; - temp += "He issues the order MOVE NORTH NORTHEAST. First he moves north, " - "into a plain region. This uses "; - int cost = TerrainDefs[R_PLAIN].movepoints; - temp += NumToWord(cost) + " movement point" + (cost == 1?"":"s") + "."; - travel -= cost; - if(travel > TerrainDefs[R_FOREST].movepoints) { - temp += " Then he moves northeast, into a forest region. This uses "; - cost = TerrainDefs[R_FOREST].movepoints; - temp += NumToWord(cost) + " movement point" + (cost == 1?"":"s") + ","; - travel -= cost; - temp += " so the movement is completed with "; - temp += NumToWord(travel) + " to spare."; - } else { - temp += " He does not have the "; - cost = TerrainDefs[R_FOREST].movepoints; - temp += NumToWord(cost) + " movement point" + (cost == 1?"":"s"); - temp += " needed to move into the forest region to the northeast, " - "so the movement is halted at this point. The remaining move" - "will be added to his orders for the next turn, before any"; - temp += f.Link("#turn", "TURN") + " orders are processed."; - } - f.Paragraph(temp); - - if(may_sail) { - f.LinkRef("movement_sailing"); - f.TagText("h3", "Sailing:"); - temp = "Movement by sea is in some ways similar. It does not use the "; - temp += f.Link("#move", "MOVE") + " order however. Instead, the " + - "owner of a ship must issue the " + f.Link("#sail", "SAIL") + - " order or the " + f.Link("#follow", "FOLLOW") + "order, and other units wishing to help sail the ship must " + - "issue the " + f.Link("#sail", "SAIL") + " order. "; - temp += "The ship will then, if possible, make the indicated " - "movement, carrying all units on the ship with it. Units on " - "board the ship, but not aiding in the sailing of the ship, " - "may execute other orders while the ship is sailing. A unit " - "which does not wish to travel with the ship should leave the " - "ship in a coastal region, before the "; - temp += f.Link("#sail", "SAIL") + " order is processed. (A coastal " + - "region is defined as a non-ocean region with at least one " - "adjacent ocean region.)"; - f.Paragraph(temp); - temp = AString("Note that a unit on board a ship while it is ") + - "sailing may not " + f.Link("#move", "MOVE") + - " later in the turn, even if he doesn't issue the " + - f.Link("#sail", "SAIL"); - temp += " order; sailing is considered to take the whole month. " - "Also, units may not remain on guard while on board a sailing " - "ship; they will have to reissue the "; - temp += f.Link("#guard", "GUARD") + " 1 order to guard a " + - "region after sailing."; - f.Paragraph(temp); - if(Globals->HEXSIDE_TERRAIN) { - temp = AString("When not at sea, ships are not considered to be at the ") + - "centre of land hexes. Instead, they stop at the edge of the hex, " - "provided that the edge terrain is suitable for that type of ship. " - "Some ships may sail only in shallow water - beaches and rivers - " - "while other ships may sail only in deep water - harbours or at sea." - " A few ships are able to sail in both shallow and deep water. A" - " ship may only be built in edge terrain in which it is able to sail." - " Unfortunately, at this time the " + f.Link("#follow", "FOLLOW") + - " order will only work for ships moving to and/or from ocean; it" - " will not work correctly for ships moving along beaches or rivers." - " This is a limitation of the code rather than a feature, and may" - " be corrected in the future."; - f.Paragraph(temp); - } - if(!Globals->HEXSIDE_TERRAIN) { - temp = AString("Ships get ") + NumToWord(Globals->SHIP_SPEED); - temp += AString(" movement point") + (Globals->SHIP_SPEED==1?"":"s"); - temp += " per turn. A ship can move from an ocean region to " - "another ocean region, or from a coastal region to an ocean " - "region, or from an ocean region to a coastal region."; - if (Globals->PREVENT_SAIL_THROUGH) { - temp += " Ships may not sail through single hex land masses " - "and must leave via the same side they entered or a side " - "adjacent to that one."; - if (Globals->ALLOW_TRIVIAL_PORTAGE) { - temp += " Ships ending their movement in a land hex may " - "sail out along any side connecting to water."; - } - } - } else { - temp = AString("Ships get a number of movement points which depends ") + - "on the ship type, and may be modified by spellcasting. Ships are " - "classified as being able to sail only in shallow water, only " - "in deep water, or in any water depth. Particulars for each ship " - "type are listed in the table " + f.Link("#tableshipcapacities","below") - + ". A ship which can move to any " - "terrain type may move from an ocean region to " - "another ocean region, from an ocean region to a coastal edge, " - "from a sailable edge to an ocean region, or from a sailable edge to " - "another sailable edge"; - } - f.Paragraph(temp); - if(Globals->HEXSIDE_TERRAIN) { - temp = AString("When sailing from edge terrain such as a river, a ship ") + - "will move to the first edge in the indicated direction, and will stay " - "on the same side of the edge. For instance, a ship at position A in the " - "map below would move to position B by issuing the order SAIL SE, or to " - "position C by issuing the order SAIL S. To sail to the opposite bank of a " - "river, such as from A to D, simply sail in the direction which crosses the " - "river, in this case case northeast. Although they are on the same river section, " - "a ship at position A is considered to be in the northeast of region X, " - "while a ship at position D is on the southwest edge of region Y. If a ship " - "at position A tried to sail southwest, it would not move, as ships cannot sail " - "across land."; - f.Paragraph(temp); - - f.Paragraph(""); - f.Enclose(1, "pre"); - f.PutNoFormat(" _____"); - f.PutNoFormat(" \\ / \\ "); - f.PutNoFormat(" \\ / \\ "); - f.PutNoFormat(" \\_____/ Y \\ "); - f.PutNoFormat(" / \\ / "); - f.PutNoFormat(" / A\\D / "); - f.PutNoFormat(" / X \\_____/ "); - f.PutNoFormat(" \\ / B \\ "); - f.PutNoFormat(" \\ C/ \\"); - f.PutNoFormat(" \\_____/ Z \\ "); - f.PutNoFormat(" / \\ /"); - f.PutNoFormat(" / \\ /"); - f.PutNoFormat(" / \\_____/"); - - f.Enclose(0, "pre"); - - temp = AString("If regions Y and Z were ocean, then sailing to D or B ") + - "would cause the ship to enter the ocean and return to the centre of the hex, rather than stay on the " - "edge. The ship will then follow ocean movement rules until it attempts to return " - "to land. For instance, sailing southwest from ocean region Y, the ship will return to position A." - "Note that a ship cannot sail from region Z directly to location A, it must pass through " - "either location C or region Y by issuing the order SAIL NW N or SAIL N SW."; - f.Paragraph(temp); - - temp = AString("Each direction a ship sails costs one movement points. ") + - "Because ships moving to edge terrain move only half as far, it is usually " - "faster to sail in the open ocean than by river or coast. "; - } else { - temp = AString(" Ships can only be constructed in coastal regions. For a ") + - "ship to enter any region only costs one movement point; the " - "cost of two movement points for entering, say, a forest " - "coastal region, does not apply."; - } - if(Globals->WEATHER_EXISTS) { - temp += " Ships do, however, use twice as many movement points " - "to move to ocean regions during the winter months (or monsoon months in the " - "tropical latitudes). This penalty does not apply moving to edge terrain " - "such as beaches or rivers."; - } - f.Paragraph(temp); - temp = "A ship can only move if the total weight of everything " - "aboard does not exceed the ship's capacity. (The rules do " - "not prevent an overloaded ship from staying afloat, only " - "from moving.) Also, there must be enough sailors aboard " - "(using the "; - temp += f.Link("#sail", "SAIL") + " order), to sail the ship, or "; - temp += "it will not go anywhere. Note that the sailing skill " - "increases the usefulness of a unit proportionally; thus, a " - "1 man unit with level 5 sailing skill can sail a longboat " - "alone. (See the section on skills for further details on " - "skills.) The capacities (and costs in labor units) of the " - "various basic ship types are as follows:"; - f.Paragraph(temp); - f.LinkRef("tableshipcapacities"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", " "); - f.TagText("th", " Capacity "); - f.TagText("th", " Cost "); - f.TagText("th", " Sailors "); - f.TagText("th", " Speed "); - f.TagText("th", " May Sail "); - f.TagText("th", " Sea-Battle Bonus "); - f.Enclose(0, "tr"); - for(i = 0; i < NOBJECTS; i++) { - if(ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if(!ObjectIsShip(i)) continue; - if(ItemDefs[ObjectDefs[i].item].flags & ItemType::DISABLED) - continue; - int normal = (ItemDefs[ObjectDefs[i].item].type & IT_NORMAL); - normal |= (ItemDefs[ObjectDefs[i].item].type & IT_TRADE); -// if(!normal) continue; //BS mod to include all ships. - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(ObjectDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(ObjectDefs[i].capacity); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(ObjectDefs[i].cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(ObjectDefs[i].sailors); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(ObjectDefs[i].speed); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - if(ObjectDefs[i].sailable == 1) f.PutStr(" Shallow Only "); - if(ObjectDefs[i].sailable == 2) f.PutStr(" Deep Only "); - if(ObjectDefs[i].sailable == 3) f.PutStr(" Any "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - f.PutStr(ObjectDefs[i].oceanbonus); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - } - - temp = " The 'Sea-Battle Bonus' is applied to all units in the ship " - "during any battle in an ocean or lake region, and increases the " - "attack and defence strength of the units by the amount listed " - "above. This does not apply for battles in land regions."; - f.Paragraph(temp); - -/* BS Sailing Mod */ - temp = "Any ship which is left unoccupied or occupied only " - "by monsters, and is in an ocean or lake region, has " - "a 20% chance of sinking per month."; - if(!(ObjectDefs[O_FISHTRAP].flags & ObjectType::DISABLED)) { - temp += " In addition, any units which are in an object, " - "which is not a ship, in an ocean or lake region, " - "will be moved out of that object after the sailing " - "phase if (and only if) there are no ships present " - "in the region which they are able to move into. If " - "this occurs, these units will drown if they are " - "unable to swim"; - if(Globals->FLIGHT_OVER_WATER == GameDefs::WFLIGHT_UNLIMITED) temp += " or fly"; - temp += "."; - } - f.Paragraph(temp); - - f.LinkRef("movement_order"); - f.TagText("h3", "Order of Movement:"); - temp = "This section is probably unimportant to beginning players, but " - "it can be helpful for more experienced players."; - f.Paragraph(temp); - temp = "Movement in Atlantis, meaning "; - temp += f.Link("#advance", "ADVANCE") + ", " + f.Link("#move", "MOVE") + - ", " + f.Link("#sail", "SAIL") + " and " + f.Link("#follow", "FOLLOW"); - temp += " orders, is processed one hex of movement at a time, region " - "by region. So, Atlantis cycles through all of the regions; for " - "each region, it finds any units that wish to move, and moves " - "them (if they can move) one hex (and only one hex). Any unit " - "following a unit which moves, will also move, if it is able to do so. After " - "processing all such regions, any battles that take " - "place due to these movements are initiated. The game then cycles through all " - "of the regions again, moving any units which have used " - "exactly one movepoint by one hex (and only one " - "hex). Then, any units with follow orders, which have used one OR LESS " - "movepoints, will follow their targets, suffering a one movepoint penalty if " - "they had not previously used any movepoints. Battles are then initiated due to these movements, " - "before cycling through again, moving any units which have " - "used two movepoints (some of which may have moved only one " - "hex already, and some of which have already moved two), plus " - "any units following these. This process is repeated until no units can " - "move anymore."; - f.Paragraph(temp); - - temp = "Note that the order in which the regions are processed is undefined " - "by the rules. The computer generally does them in the same " - "order every time, but it is up to the wiles of the player to " - "determine (or not) these patterns. The order in which units or " - "ships are moved within a region is the order that they appear " - "on a turn report."; - f.Paragraph(temp); - f.LinkRef("skills"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Skills"); - - temp = "The most important thing distinguishing one character from " - "another in Atlantis is skills. The following basic skills are " - "available: "; - int comma = 0; - found = 0; - last = -1; - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - if(SkillDefs[i].flags & SkillType::APPRENTICE) continue; - if(SkillDefs[i].flags & SkillType::MAGIC) continue; - found = 0; - for(j = 0; j < 3; j++) { - SkillType *pS = FindSkill(SkillDefs[i].depends[j].skill); - if (pS && !(pS->flags & SkillType::DISABLED)) { - found = 1; - break; - } - } - if(found) continue; - if(last == -1) { - last = i; - continue; - } - - temp += SkillDefs[last].name; - temp += ", "; - last = i; - comma++; - } - if(last != -1) { - if(comma) temp += "and "; - temp += SkillDefs[last].name; - } - - temp += ". When a unit possesses a skill, he also has a skill level " - "to go with it. Generally, the effectiveness of a skill is " - "directly proportional to the skill level involved, so a unit with " - "level 2 in a skill is twice as good as a unit with level 1 in the " - "same skill."; - f.Paragraph(temp); - f.LinkRef("skills_limitations"); - f.TagText("h3", "Limitations:"); - if (Globals->LEADERS_EXIST && Globals->SKILL_LIMIT_NONLEADERS) { - temp = "A unit made up of leaders may know one or more skills; " - "for the rest of this section, the word \"leader\" will refer " - "to such a unit. Other units, those which contain " - "non-leaders, will be refered to as normal units. A normal " - "unit may only know one skill."; - f.Paragraph(temp); - } - if(!Globals->RACES_EXIST) { - if(Globals->SKILL_LIMIT_NONLEADERS) { - temp = "A unit may only learn one skill. "; - } else { - temp = "A unit may learn as many skills as it requires. "; - } - ManType *mt = FindRace("MAN"); - if (mt != NULL) { - temp += "Skills can be learned up to a maximum level of "; - temp += mt->defaultlevel; - temp += "."; - } - f.Paragraph(temp); - } - - if (Globals->REAL_EXPERIENCE) { - temp = "Skill levels may be gained in two ways, through " - "knowledge, or through experience. Units may gain up to " - "a maximum knowledge level depending on the unit's race " - "(remembering that for units containing more than one " - "race, the maximum is determined by the least common " - "denominator). Units may also gain up to a maximum " - "experience level depending on race. The unit's skill " - "level for all actions it performs is equal to the " - "sum of the knowledge and experience levels."; - } - if (Globals->RACES_EXIST) { - if(!Globals->REAL_EXPERIENCE) temp = "Skills may be learned up to a maximum level depending on " - "the race of the unit (remembering that for units " - "containing more than one race, the maximum is determined by " - "the least common denominator). Every race has a normal " - "maximum skill level, and a list of skills that they " - "specialize in, and can learn up to higher level."; - if(Globals->LEADERS_EXIST) { - temp += " Leaders, being more powerful, can learn skills to " - "even higher levels."; - } - temp += " Here is a list of the races and the " - "information on normal skill levels and specialized skills."; - f.Paragraph(temp); - if(Globals->REAL_EXPERIENCE) { - temp = "For each race, the first number is the maximum knowledge " - "level, and the second number is the maximum " - "level to which they may gain experience."; - f.Paragraph(temp); - } - f.LinkRef("tableraces"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Race"); - f.TagText("th", "Ethnicity"); - f.TagText("th", "Specialised Skills"); - f.TagText("th", "Hero Skills"); - f.TagText("th", "Max Level (specialized skills)"); - f.TagText("th", "Max Level (non-specialized skills)"); - f.Enclose(0, "tr"); - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[i].type & IT_MAN)) continue; - f.Enclose(1, "tr"); - ManType *mt = FindRace(ItemDefs[i].abr); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].names); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - switch(mt->ethnicity) { - case RA_HUMAN: - f.PutStr("Human"); - break; - case RA_DWARF: - f.PutStr("Dwarf"); - break; - case RA_ELF: - f.PutStr("Elf"); - break; - case RA_OTHER: - f.PutStr("Other"); - break; - default: - f.PutStr("N/A"); - break; - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - int spec = 0; - comma = 0; - temp = ""; - for(j=0; j<(int)(sizeof(mt->skills)/sizeof(mt->skills[0])); j++) { - pS = FindSkill(mt->skills[j]); - if (!pS || (pS->flags & SkillType::DISABLED)) continue; - spec = 1; - if(comma) temp += ", "; - temp += pS->name; - comma++; - } - if(!spec) temp = "None."; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - spec = 0; - comma = 0; - temp = ""; - for(j=0; j<(int)(sizeof(mt->mage_skills)/sizeof(mt->mage_skills[0])); j++) { - pS = FindSkill(mt->mage_skills[j]); - if (!pS || (pS->flags & SkillType::DISABLED)) continue; - spec = 1; - if(comma) temp += ", "; - temp += pS->name; - comma++; - } - if(!spec) temp = "None."; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(spec) { - temp = AString(mt->speciallevel); - if(Globals->REAL_EXPERIENCE) { - temp += ", "; - temp += AString(mt->specialexperlevel); - } - } - else - temp = "--"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = AString(mt->defaultlevel); - if(Globals->REAL_EXPERIENCE) { - temp += ", "; - temp += AString(mt->defaultexperlevel); - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - } - temp = "If units are merged together, their skills are averaged out. " - "No rounding off is done; rather, the computer keeps track for each " - "unit of how many total days of training that unit has in each " - "skill. When units are split up, these days are divided as evenly " - "as possible among the people in the unit; but no months are ever " - "lost."; - f.Paragraph(temp); - - temp = "A units skill level is included in the unit's description in your " - "report. This description will list the skill, the unit's skill level " - "(the sum of the knowledge level and the experience level) and how " - "many days knowledge and experience the unit has in that skill. " - "For example, a unit with 40 days knowledge of, and 50 " - "days experience in combat would be displayed as:"; - f.Paragraph(temp); - - temp = "combat [COMB] 2 (40,50)"; - f.Paragraph(temp); - - f.LinkRef("skills_studying"); - f.TagText("h3", "Studying:"); - temp = "For a unit to gain level 1 of a skill due to knowledge, they must gain one " - "months worth of knowledge in that skill. To raise this knowledge skill level " - "to 2, the unit must add an additional two months worth of " - "knowledge. Then, to raise this to skill level 3 requires another " - "three months worth of knowledge. A month of " - "knowledge is gained when a unit uses the "; - temp += f.Link("#study", "STUDY") + " order. Note that study months " - "do not need to be consecutive; for a unit to go from level 1 to " - "level 2, he can study for a month, do something else for a month, " - "and then go back and complete his second month of study."; - if (Globals->SKILL_PRACTICE_AMOUNT > 0 && !Globals->REAL_EXPERIENCE) { - temp += " A unit can also increase its level of training by " - "using a skill. This progress is "; - if (Globals->SKILL_PRACTICE_AMOUNT < 11) - temp += "much slower than"; - else if (Globals->SKILL_PRACTICE_AMOUNT < 30) - temp += "slower than"; - else if (Globals->SKILL_PRACTICE_AMOUNT == 30) - temp += "the same as"; - else if (Globals->SKILL_PRACTICE_AMOUNT < 61) - temp += "faster than"; - else - temp += "much faster than"; - temp += " studying. Only one skill can be improved through " - "practice in any month; if multiple skills are used, only the " - "first will be improved. A skill will only improve with " - "practice if the unit has first studied the rudiments of the " - "skill."; - } - f.Paragraph(temp); - // XXX -- This is not as nice as it could be and could cause problems - // if the skills are given disparate costs. This should probably be - // a table of all skills/costs. - temp = "Most skills cost $"; - temp += SkillDefs[S_COMBAT].cost; - temp += " per person per month to study (in addition to normal " - "maintenance costs). The exceptions are "; - if(has_stea || has_obse) { - if(has_stea) temp += "Stealth"; - if(has_obse) { - if(has_stea) temp += " and "; - temp += "Observation"; - } - temp += " ("; - if(has_stea && has_obse) - temp += "both of which cost $"; - else - temp += "which costs $"; - temp += SkillDefs[S_STEALTH].cost; - temp += "), "; - } - temp += "Hero skills (which cost $"; - if(Globals->ARCADIA_MAGIC) temp += SkillDefs[S_BASE_PATTERNING].cost; - else temp += SkillDefs[S_FORCE].cost; - temp += ")"; - if(!(SkillDefs[S_TACTICS].flags & SkillType::DISABLED)) { - temp += ", and Tactics (which costs $"; - temp += SkillDefs[S_TACTICS].cost; - temp += ")"; - } - temp += "."; - f.Paragraph(temp); - f.LinkRef("skills_teaching"); - f.TagText("h3", "Teaching:"); - temp = AString("A unit with a teacher can learn up to twice as fast ") + - "as normal. The " + f.Link("#teach", "TEACH") + " order is used to "; - temp += "spend the month teaching one or more other units (your own or " - "another factions). The unit doing the teaching must have either a total skill " - "level greater than the unit doing the studying, or a knowledge skill level " - "greater than the unit doing the studying. (Note: for all " - "skill uses, it is skill level, not number of months of training, " - "that counts. Thus, a unit with 1 month of knowledge is effectively " - "the same as a unit with 2 months of knowledge, since both have a " - "skill level of 1.) The units being taught simply issue the "; - temp += f.Link("#study", "STUDY") + " order normally (also, his faction " - "must be declared Friendly by the teaching faction). Each person " - "can only teach up to " + Globals->STUDENTS_PER_TEACHER + - " student" + (Globals->STUDENTS_PER_TEACHER == 1?"":"s") + " in a "; - temp += "month; additional students dilute the training. Thus, if 1 " - "teacher teaches "; - temp += AString(2*Globals->STUDENTS_PER_TEACHER) + - " men, each man being taught will gain 1 1/2 months of training, " - "not 2 months."; - f.Paragraph(temp); - temp = "Note that it is quite possible for a single unit to teach two " - "or more other units different skills in the same month, provided " - "that the teacher has a higher skill level than each student in " - "the skill that that student is studying, and that there are no " - "more than "; - temp += AString(Globals->STUDENTS_PER_TEACHER) + " student"; - temp += (Globals->STUDENTS_PER_TEACHER == 1 ? "" : "s"); - temp += " per teacher. Note that if during the teaching process, the " - "student reaches the teacher's skill level (and thus cannot be taught), " - "then no further bonus from teaching will be gained."; - f.Paragraph(temp); - if(Globals->LEADERS_EXIST) { - temp = "Note: Only leaders may use the "; - temp += f.Link("#teach", "TEACH") + " order."; - f.Paragraph(temp); - } - - if(Globals->REAL_EXPERIENCE) { - f.LinkRef("skills_experience"); - f.TagText("h3", "Experience:"); - temp = "The other half of the skill equation is the unit's experience level. " - "Experience is gained by a unit when it uses a skill - lumberjack is " - "practised when a unit produces wood, sailing is practised when a unit " - "sails a ship, building is practised when a unit builds a structure. Note " - "that these orders must be successful for a unit to gain experience; if a " - "ship cannot move due to being overloaded, then sailors will not gain " - "experience even if they issued a SAIL order."; - f.Paragraph(temp); - - temp = "Skill levels will be gained through experience in the same " - "way as for studying, that is, if a unit has one month's experience they gain " - "one level, an extra two month's experience is needed for the second level, and a third " - "level requires three months further experience. However, experience is gained more " - "slowly than studying. For leaders or units practising a specialist skill, " - "every month they use the skill will gain them 10 days experience. A unit " - "practising a non-specialist skill will gain only 3 days experience for a " - "month's labour. Skills which cannot be practised with a "; - temp += f.Link("#build", "BUILD") + ", " + f.Link("#produce", "PRODUCE") + ", " - + f.Link("#sail", "SAIL") + ", or " + f.Link("#entertain", "ENTERTAIN"); - temp += " order work slightly differently. Units gain experience " - "in battle skills if they fight in a battle - this includes tactics, " - "riding if the soldier has a mount, and either combat, longbow or crossbow " - "depending on what weapon the soldier has (a soldier with no weapon will " - "gain experience in the combat skill). The amount of experience gained will depend " - "on the course of the battle, easy victories give little or no experience, while " - "hard fought battles provide a lot more. Note that since non-leader units " - "are able to know only one skill, they will not gain any experience from " - "battles if skilled in a non-combat skill, or a skill for which they did " - "not have an appropriate weapon. Heroes may gain experience " - "in hero skills through use of the skills, either by casting them directly, " - "using them in combat, or being in a place whereby the skill will get used. " - "The remaining skills, such as " - "stealth and observation, may not be practised, and experience may only " - "be gained in these skills through study as described below."; - f.Paragraph(temp); - - f.LinkRef("leaders_heros"); - f.TagText("h3", "Leaders and Heros:"); - temp = "Two of the skills above act differently to the others. Normal " - "units may study leadership to turn themselves into \"leader\" units, " - "which cost double the maintenance, but can study and experience " - "one level higher in every skill than shown in the table above. " - "Units with a single leader in them may study heroship, turning " - "them into heros. Heroes cost ten times the maintenance of a " - "normal unit, but can study and experience skills two levels " - "higher than normal, and can also study hero skills, described " - "later in these rules."; - f.Paragraph(temp); - - - f.LinkRef("tableunittypes"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Unit Type"); - f.TagText("th", "Skill Required"); - f.TagText("th", "Maintenance (native / foreign)"); - f.TagText("th", "Specialist knowledge"); - f.TagText("th", "Non-specialist knowledge"); - f.TagText("th", "Specialist hero skills"); - f.TagText("th", "Non-specialist hero skills"); - f.Enclose(0, "tr"); - for(i = 0; i < 3; i++) { - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - switch(i) { - case 0: f.PutStr("Normal"); - break; - case 1: f.PutStr("Leader"); - break; - case 2: f.PutStr("Hero"); - break; - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - switch(i) { - case 0: f.PutStr(" "); - break; - case 1: f.PutStr("Leadership"); - break; - case 2: f.PutStr("Heroship"); - break; - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - switch(i) { - case 0: f.PutStr("10 / 20"); - break; - case 1: f.PutStr("20 / 40"); - break; - case 2: f.PutStr("100 / 200"); - break; - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - f.PutStr(AString(2+i)+"*"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - f.PutStr(AString(1+i)+"**"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - switch(i) { - case 0: f.PutStr(" "); - break; - case 1: f.PutStr(" "); - break; - case 2: f.PutStr(3); - break; - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - switch(i) { - case 0: f.PutStr(" "); - break; - case 1: f.PutStr(" "); - break; - case 2: f.PutStr(2); - break; - } - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - - temp = "* Add 1 to this value for orcs. Note that units can also gain experience equal " - "to their maximum allowed knowledge, so the maximum skill level achievable is double that listed here."; - f.Paragraph(temp); - - temp = "** Subtract 1 from this value for orcs. Note that units can also gain experience equal " - "to their maximum allowed knowledge, so the maximum skill level achievable is double that listed here."; - f.Paragraph(temp); - - - f.LinkRef("skills_overflow"); - f.TagText("h3", "Overflow:"); - temp = "If a unit reaches their maximum knowledge level, " - "then they cannot gain any more days worth of knowledge. " - "However, further study is not wasted; each extra month's " - "study will gain the same experience as if the unit had " - "used that skill for a month - that is, three days experience " - "for a non-specialist skill, or ten days experience for a leader " - "or specialist skill. This applies to all skills, regardless of " - "the method by which experience would normally be gained in that " - "skill. This also works in reverse - a unit which has reached their " - "maximum experience level, but can still gain knowledge in that " - "skill, will gain one days worth of knowledge for every three days " - "of experience they earn."; - f.Paragraph(temp); - } - - f.LinkRef("skills_skillreports"); - f.TagText("h3", "Skill Reports:"); - temp = "When a faction learns a new skill level for this first time, it " - "will be given a report on special abilities that a unit with this " - "skill level has. This report can be shown again at any time (once " - "a faction knows the skill), using the "; - temp += f.Link("#show", "SHOW") + " order. For example, when a faction "; - temp += "learned the skill Shoemaking level 3 for the first time, it " - "might receive the following (obviously farsical) report:"; - f.Paragraph(temp); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.ClearWrapTab(); - f.WrapStr("Shoemaking [SHOE] 3: A unit with this skill may PRODUCE " - "Sooper Dooper Air Max Winged Sandals."); - f.Enclose(0, "pre"); - f.LinkRef("economy"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "The Economy"); - temp = "The unit of currency in Atlantis is the silver piece. Silver " - "is a normal item, with zero weight, appearing in your unit's " - "reports. Silver is used for such things as buying items, and " - "unit's maintenance."; - f.Paragraph(temp); - f.LinkRef("economy_maintenance"); - f.TagText("h3", "Maintenance Costs:"); - temp = "IMPORTANT: Each and every character in Atlantis requires a " - "maintenance fee each month. Anyone who ends the month without " - "this maintenance cost has a "; - temp += Globals->STARVE_PERCENT; - temp += " percent chance of "; - if(Globals->SKILL_STARVATION != GameDefs::STARVE_NONE) { - temp += "starving, leading to the following effects:"; - f.Paragraph(temp); - f.Enclose(1, "ul"); - f.Enclose(1, "li"); - if(Globals->SKILL_STARVATION == GameDefs::STARVE_MAGES) - temp = "If the unit is a mage, it"; - else if(Globals->SKILL_STARVATION == GameDefs::STARVE_LEADERS) - temp = "If the unit is a leader, it"; - else - temp = "A unit"; - temp += " will lose a skill level in some of its skills."; - f.PutStr(temp); - f.Enclose(0, "li"); - if(Globals->SKILL_STARVATION != GameDefs::STARVE_ALL) { - f.Enclose(1, "li"); - f.PutStr("Otherwise, it will starve to death."); - f.Enclose(0, "li"); - } - f.Enclose(1, "li"); - f.PutStr("If a unit should forget a skill level and it knows none, " - "it will starve to death."); - f.Enclose(0, "li"); - f.Enclose(0, "ul"); - temp = ""; - } else { - temp += "starving to death. "; - } - temp += "It is up to you to make sure that your people have enough money "; - if (Globals->UPKEEP_MINIMUM_FOOD > 0) - temp += "and food "; - temp += "available. Money "; - if (Globals->UPKEEP_MINIMUM_FOOD > 0) - temp += "and food "; - temp += "will be shared automatically between your units " - "in the same region, if one is starving and another has more than " - "enough; but this will not happen between units in different " - "regions (this sharing of money applies only for maintenance costs, " - "and does not occur for other purposes). If you have silver in your " - "unclaimed fund, then that silver will be automatically claimed by " - "units that would otherwise starve. "; - if (Globals->UPKEEP_MINIMUM_FOOD && Globals->ALLOW_WITHDRAW) { - temp += "Similarly, food will automatically be "; - temp += f.Link("#withdraw", "withdraw"); - temp += "n if needed and unclaimed funds are available. "; - } - temp += "Lastly, if a faction is allied to yours, their units will " - "provide surplus cash "; - if (Globals->UPKEEP_MINIMUM_FOOD > 0) - temp += "or food "; - temp += "to your units for maintenance, as a last resort."; - f.Paragraph(temp); - temp = ""; - if(Globals->MULTIPLIER_USE == GameDefs::MULT_NONE) { - temp += AString("This fee is generally ") + - Globals->MAINTENANCE_COST + " silver for a normal character"; - if (Globals->LEADERS_EXIST) { - temp += AString(", and ") + Globals->LEADER_COST + - " silver for a leader"; - } - } else { - if(Globals->MULTIPLIER_USE == GameDefs::MULT_MAGES) { - temp += "Mages "; - } else if(Globals->MULTIPLIER_USE==GameDefs::MULT_LEADERS && - Globals->LEADERS_EXIST) { - temp += "Leaders "; - } else { - temp += "All units "; - } - temp += "pay a fee based on the number of skill levels the character " - "has. This fee is the maximum of $"; - temp += AString(Globals->MAINTENANCE_MULTIPLIER) + " per skill level"; - temp += " and a cost of $"; - temp += AString(Globals->MAINTENANCE_COST) + " for normal characters"; - temp += AString(" or $") + Globals->LEADER_COST + " for leaders"; - if(Globals->MULTIPLIER_USE != GameDefs::MULT_ALL) { - temp += ". All other characters pay a fee of "; - temp += Globals->MAINTENANCE_COST; - temp += " silver for a normal character"; - if (Globals->LEADERS_EXIST) { - temp += ", and "; - temp += Globals->LEADER_COST; - temp += " silver for a leader"; - } - } - } -// temp += "."; - //Xanaxor: - temp += ", and is always doubled if the character's ethnicity is " - "different to that of your faction. A listing of the exact costs may be found "; - temp += f.Link("#tableunittypes", "here") + "."; - temp += " Note that if your commanding hero is killed, then your faction will fall into chaos, " - "and all units in the subsequent turn will cost the double maintenance amount if you do not appoint a new " - "commanding hero. Because of this, it is always wise to have a second hero " - "of the same ethnicity who can, in an emergency, take over command " - "of your faction."; - f.Paragraph(temp); - temp = ""; - - if (Globals->FOOD_ITEMS_EXIST) { - temp += " Units may substitute one unit of grain, livestock, or " - "fish for each "; - temp += Globals->UPKEEP_FOOD_VALUE; - temp += " silver of maintenance owed. "; - if (Globals->UPKEEP_MINIMUM_FOOD > 0) { - temp += "A unit must be given at least "; - temp += Globals->UPKEEP_MINIMUM_FOOD; - temp += " maintenance per man in the form of food. "; - } - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0) { - temp += "At most "; - temp += Globals->UPKEEP_MAXIMUM_FOOD; - temp += " silver worth of food can be counted against each " - "man's maintenance. "; - } - temp += "A unit may use the "; - temp += f.Link("#consume", "CONSUME") + " order to specify that it " - "wishes to use food items in preference to silver. Note that "; - temp += "these items are worth more when sold in towns, so selling " - "them and using the money is more economical than using them for " - "maintenance."; - }; - f.Paragraph(temp); - f.LinkRef("economy_recruiting"); - f.TagText("h3", "Recruiting:"); - temp = "People may be recruited in a region. The total amount of " - "recruits available per month in a region, and the amount that must " - "be paid per person recruited, are shown in the region description. " - "The "; - temp += f.Link("#buy", "BUY") + " order is used to recruit new people. "; - temp += "New recruits will not have any skills or items. Note that the " - "process of recruiting a new unit is somewhat counterintuitive; it " - "is necessary to "; - temp += f.Link("#form", "FORM")+" an empty unit, "; - temp += f.Link("#give", "GIVE")+" the empty unit some money, and have it "; - temp += f.Link("#buy", "BUY") + " people; see the description of the "; - temp += f.Link("#form", "FORM")+ " order for further details."; - f.Paragraph(temp); - f.LinkRef("economy_items"); - f.TagText("h3", "Items:"); - temp = "A unit may have a number of possessions, referred to as " - "\"items\". Some details were given above in the section on " - "Movement, but many things were left out. Here is a table giving " - "some information about common items in Atlantis:"; - f.Paragraph(temp); - f.LinkRef("tableiteminfo"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", " "); - f.TagText("th", "Skill (min level)"); - f.TagText("th", "Material"); - f.TagText("th", "Production time"); - f.TagText("th", "Weight (capacity)"); - f.TagText("th", "Extra Information"); - f.Enclose(0, "tr"); - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[i].type & IT_NORMAL)) continue; - pS = FindSkill(ItemDefs[i].pSkill); - if (pS && (pS->flags & SkillType::DISABLED)) continue; - last = 0; - for(j = 0; j < (int) (sizeof(ItemDefs->pInput) / - sizeof(ItemDefs->pInput[0])); j++) { - k = ItemDefs[i].pInput[j].item; - if(k != -1 && - !(ItemDefs[k].flags & ItemType::DISABLED) && - !(ItemDefs[k].type & IT_NORMAL)) - last = 1; - } - if(last == 1) continue; - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(pS != NULL) { - temp = pS->name; - temp += AString(" (") + ItemDefs[i].pLevel + ")"; - f.PutStr(temp); - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - comma = 0; - temp = ""; - if (ItemDefs[k].flags & ItemType::ORINPUTS) - temp = "Any of : "; - for(j = 0; j < (int) (sizeof(ItemDefs->pInput) / - sizeof(ItemDefs->pInput[0])); j++) { - k = ItemDefs[i].pInput[j].item; - if(k < 0 || (ItemDefs[k].flags&ItemType::DISABLED)) - continue; - if(comma) temp += ", "; - temp += ItemDefs[i].pInput[j].amt; - temp += " "; - if(ItemDefs[i].pInput[j].amt > 1) - temp += ItemDefs[k].names; - else - temp += ItemDefs[k].name; - comma = 1; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(ItemDefs[i].pMonths) { - temp = ItemDefs[i].pMonths; - temp += AString(" month") + (ItemDefs[i].pMonths == 1 ? "" : "s"); - } else { - temp = " "; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = ItemDefs[i].weight; - cap = ItemDefs[i].walk - ItemDefs[i].weight; - if(ItemDefs[i].walk || (ItemDefs[i].hitchItem != -1)) { - temp += " ("; - if(ItemDefs[i].hitchItem == -1) - temp += cap; - else { - temp += (cap + ItemDefs[i].hitchwalk); - temp += " with "; - temp += ItemDefs[ItemDefs[i].hitchItem].name; - } - temp += ")"; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\""); - temp = ""; - if(ItemDefs[i].type & IT_WEAPON) { - WeaponType *wp = FindWeapon(ItemDefs[i].abr); - if(wp->attackBonus || wp->defenseBonus || - (wp->flags & WeaponType::RANGED) || - (wp->flags & WeaponType::NEEDSKILL)) { - if(wp->flags & WeaponType::RANGED) - temp += "Ranged weapon"; - else - temp += "Weapon"; - temp += " which gives "; - if(wp->attackBonus > -1) temp += "+"; - temp += wp->attackBonus; - temp += " on attack"; - temp += " and "; - if(wp->defenseBonus > -1) temp += "+"; - temp += wp->defenseBonus; - temp += " on defense"; - if(wp->flags & WeaponType::NEEDSKILL) { - pS = FindSkill(wp->baseSkill); - if (pS && !(pS->flags & SkillType::DISABLED)) - temp += AString(" (needs ") + pS->name; - pS = FindSkill(wp->orSkill); - if (pS && !(pS->flags & SkillType::DISABLED)) - temp += AString(" or ") + pS->name; - temp += " skill)"; - } - temp += ".
"; - } - if(wp->numAttacks < 0) { - temp += "Gives 1 attack every "; - temp += -(wp->numAttacks); - temp += " rounds.
"; - } - } - if(ItemDefs[i].type & IT_MOUNT) { - MountType *mp = FindMount(ItemDefs[i].abr); - pS = FindSkill(mp->skill); - if (pS && !(pS->flags & SkillType::DISABLED)) { - temp += "Gives a riding bonus with the "; - temp += pS->name; - temp += " skill.
"; - } - } - if(ItemDefs[i].type & IT_ARMOR) { - ArmorType *at = FindArmor(ItemDefs[i].abr); - temp += "Gives a "; - temp += at->saves[SLASHING]; - temp += " in "; - temp += at->from; - temp += " chance to survive a normal hit.
"; - if((at->flags & ArmorType::USEINASSASSINATE) && has_stea) { - temp += "May be used during assassinations.
"; - } - } - if(ItemDefs[i].type & IT_TOOL) { - for(j = 0; j < NITEMS; j++) { - if(ItemDefs[j].flags & ItemType::DISABLED) continue; - if(ItemDefs[j].mult_item != i) continue; - if(!(ItemDefs[j].type & IT_NORMAL)) continue; - pS = FindSkill(ItemDefs[j].pSkill); - if (!pS || (pS->flags & SkillType::DISABLED)) continue; - last = 0; - for(k = 0; k < (int) (sizeof(ItemDefs->pInput) / - sizeof(ItemDefs->pInput[0])); k++) { - l = ItemDefs[j].pInput[k].item; - if(l != -1 && - !(ItemDefs[l].flags & ItemType::DISABLED) && - !(ItemDefs[l].type & IT_NORMAL)) - last = 1; - } - if(last == 1) continue; - temp += AString("+") + ItemDefs[j].mult_val + - " bonus when producing " + ItemDefs[j].names + ".
"; - } - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - temp = "All items except silver and trade goods are produced with the "; - temp += f.Link("#produce", "PRODUCE") + " order."; - - temp += " Producing items will always produce as many items as " - "during a month up to the limit of the supplies carried by the " - "producing unit. The required skills and raw materials required " - "to produce one output item are in the table above."; - f.Paragraph(temp); - temp = "If an item requires raw materials, then the specified " - "amount of each material is consumed for each item produced. "; - temp += "The higher the skill of the unit, the more productive each " - "man-month of work will be. Thus, five men at skill level one are " - "exactly equivalent to one guy at skill level 5 in terms of base " - "output. Items which require multiple man-months to produce will " - "take still benefit from higher skill level units, just not as " - "quickly. For example, if a unit of six level one men wanted to " - "produce something which required three man-months per item, that " - "unit could produce two of them in one month. If their skill level " - "was raised to two, then they could produce four of them in a month. " - "At level three, they could then produce 6 per month."; - - temp += "Some items may allow each man to produce multiple output " - "items per raw material or have other differences from these basic " - "rules. Those items will explain their differences in the " - "description of the item."; - - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp += " Only Trade factions can issue "; - temp += f.Link("#produce", "PRODUCE") + " orders however, regardless " - "of skill levels."; - } - f.Paragraph(temp); - temp = "Items which increase production may increase production of " - "advanced items in addition to the basic items listed. Some of " - "them also increase production of other tools. Read the skill " - "descriptions for details on which tools aid which production when " - "not noted above."; -// f.Paragraph(temp); //No tools in Arcadia - temp = "If an item does not list a raw material it may be produced " - "directly from the land. Each region generally has at least one item " - "that can be produced there. Shown on the description of a region " - "is a list of the items that can be produced, and the amount of " - "each that can be produced per month. This amount depends on the " - "region type. "; - if(Globals->RANDOM_ECONOMY) { - temp += "It also varies from region to region of the same type. "; - } - temp += "If the units in a region attempt to produce more of a commodity " - "than can be produced that month, then the amount available is " - "distributed among the producers"; - f.Paragraph(temp); - if(Globals->TOWNS_EXIST) { - f.LinkRef("economy_towns"); - f.TagText("h3", "Villages, Towns, and Cities:"); - temp = "Some regions in Atlantis contain villages, towns, and " - "cities. Villages add to the wages, population, and tax income " - "of the region they are in. "; - if(Globals->FOOD_ITEMS_EXIST) { - temp += "Also, villages will have an additional market for " - "grain, livestock, and fish. "; - } - temp += "As the village's demand for these goods is met, the " - "population will increase. When the population reaches a " - "certain theshold, the village will turn into a town. A " - "town will have some additional products that it demands, " - "in addition to what it previously wanted. Also a town " - "will sell some new items as well. A town whose demands are " - "being met will grow, and above another threshold it will " - "become a full-blown city. A city will have additional " - "markets for common items, and will also have markets for " - "less common, more expensive trade items."; - f.Paragraph(temp); - temp = "Trade items are bought and sold only by cities, and have " - "no other practical uses. However, the profit margins on " - "these items are usually quite high. "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp += "Buying of trade items in a region counts against a " - "Trade faction's quota of regions in which it may " - "undertake trade activity (note that buying and selling " - "normal items does not, nor does selling of Trade items)."; - } - f.Paragraph(temp); - } - f.LinkRef("economy_buildings"); - f.TagText("h3", "Buildings and Trade Structures:"); - temp = "Construction of buildings "; - if(may_sail) temp += "and ships "; - temp += "goes as follows: each unit of work on a building requires a " - "unit of the required resource and a man-month of work by a " - "character with the appropriate skill and level; higher skill " - "levels allow work proceed faster still using one unit of the " - "required resource per unit of work done). "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp += "Again, only Trade factions can issue "; - temp += f.Link("#build", "BUILD") + " orders. "; - } - temp += "Here is a table of the various building types:"; - f.Paragraph(temp); - f.LinkRef("tablebuildings"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", ""); - f.TagText("th", "Size"); - f.TagText("th", "Defence"); - f.TagText("th", "Cost"); - f.TagText("th", "Material"); - f.TagText("th", "Skill (min level)"); - f.Enclose(0, "tr"); - for(i = 0; i < NOBJECTS; i++) { - if(ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if(!ObjectDefs[i].protect) continue; - pS = FindSkill(ObjectDefs[i].skill); - if(pS == NULL) continue; - if(pS->flags & SkillType::MAGIC) continue; - if(ObjectIsShip(i)) continue; - j = ObjectDefs[i].item; - if(j == -1) continue; - /* Need the >0 since item could be WOOD_OR_STONE (-2) */ - if(j > 0 && (ItemDefs[j].flags & ItemType::DISABLED)) continue; - /* Okay, this is a valid object to build! */ - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].protect); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].defenceArray[ATTACK_COMBAT]); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(j == I_WOOD_OR_STONE) - temp = "wood or stone"; - else - temp = ItemDefs[j].name; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = pS->name; - temp += AString(" (") + ObjectDefs[i].level + ")"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - temp = "Size is the number of people that the building can shelter. Defence " - "is the melee defence bonus that sheltered men gain from being inside " - "the building. Details on defence bonuses for other attack types can " - "be found in the object descriptions. Cost " - "is both the number of man-months of labor and the number of units " - "of material required to complete the building. There are possibly " - "other buildings which can be built that require more advanced " - "resources, or odd skills to construct. The description of a skill " - "will include any buildings which it allows to be built."; - f.Paragraph(temp); - temp = "There are other structures that increase the maximum production " - "of certain items in regions"; - if(!(ObjectDefs[O_MINE].flags & ObjectType::DISABLED)) - temp += "; for example, a Mine will increase the amount of iron " - "that is available to be mined in a region"; - temp += ". To construct these structures requires a high skill level in " - "the production skill related to the item that the structure will " - "help produce. "; - if(!(ObjectDefs[O_INN].flags & ObjectType::DISABLED)) { - temp += "(Inns are an exception to this rule, requiring the Building " - "skill, not the Entertainment skill.) "; - } - temp += "This bonus in production is available to any unit in the " - "region; there is no need to be inside the structure."; - f.Paragraph(temp); - temp = "The first structure built in a region will increase the maximum " - "production of the related product by 25%; the amount added by each " - "additional structure will be half of the the effect of the previous " - "one. (Note that if you build enough of the same type of structure " - "in a region, the new structures may not add _any_ to the production " - "level)."; - f.Paragraph(temp); - f.LinkRef("tabletradestructures"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", ""); - f.TagText("th", "Cost"); - f.TagText("th", "Material"); - f.TagText("th", "Skill (level)"); - f.TagText("th", "Production Aided"); - f.Enclose(0, "tr"); - for(i = 0; i < NOBJECTS; i++) { - if(ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if(ObjectDefs[i].protect) continue; - if(ObjectIsShip(i)) continue; - j = ObjectDefs[i].productionAided; - if(j == -1) continue; - if(ItemDefs[j].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[j].type & IT_NORMAL) && !(ItemDefs[j].type & IT_NORMAL)) continue; - pS = FindSkill(ObjectDefs[i].skill); - if (pS == NULL) continue; - if(pS->flags & SkillType::MAGIC) continue; - j = ObjectDefs[i].item; - if(j == -1) continue; - /* Need the >0 since item could be WOOD_OR_STONE (-2) */ - if(j > 0 && (ItemDefs[j].flags & ItemType::DISABLED)) continue; - if(j > 0 && !(ItemDefs[j].type & IT_NORMAL)) continue; - /* Okay, this is a valid object to build! */ - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(j == I_WOOD_OR_STONE) - temp = "wood or stone"; - else - temp = ItemDefs[j].name; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = pS->name; - temp += AString(" (") + ObjectDefs[i].level + ")"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(ObjectDefs[i].productionAided == I_SILVER) - f.PutStr("entertainment"); - else - f.PutStr(ItemDefs[ObjectDefs[i].productionAided].names); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - temp = "Note that these structures will not increase the availability " - "of an item in a region which does not already have that item " - "available. Also, Trade structures do not offer defensive bonuses " - "(which is why they do not have a size associated with them). As " - "with regular buildings, the Cost is the number of man-months of " - "labor and also the number of units of raw material required to " - "complete the structure. "; - if(!(ItemDefs[I_WOOD].flags & ItemType::DISABLED) && - !(ItemDefs[I_STONE].flags & ItemType::DISABLED)) { - temp += "You can use two different materials (wood or stone) to " - "construct most trade structures. "; - } -/* temp += "It is possible that there are structures not listed above " - "which require either advanced resources to build or which " - "increase the production of advanced resources. The skill " - "description for a skill will always note if new structures may " - "be built based on knowing that skill.";*/ - f.Paragraph(temp); - if(!(ObjectDefs[O_ROADN].flags & ObjectType::DISABLED)) { - f.LinkRef("economy_roads"); - f.TagText("h3", "Roads:"); - temp = "There is a another type of structure called roads. They do " - "not protect units, nor aid in the production of resources, but " - "do aid movement, and can improve the economy of a hex."; - f.Paragraph(temp); - temp = "Roads are directional and are only considered to reach from " - "one hexside to the center of the hex. To gain a movement " - "bonus, there must be two connecting roads, one in each " - "adjacent hex. Only one road may be built in each direction. " - "If a road in the given direction is connected, units move " - "along that road at half cost to a minimum of 1 movement point."; - f.Paragraph(temp); - temp = "For example: If a unit is moving northwest, then hex it is " - "in must have a northwest road, and the hex it is moving into " - "must have a southeast road."; - f.Paragraph(temp); - temp = "To gain an economy bonus, a hex must have roads that connect " - "to roads in at least two adjoining hexes. The economy bonus " - "for the connected roads raises the wages in the region by 1 " - "point."; - f.Paragraph(temp); - f.LinkRef("tableroadstructures"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", ""); - f.TagText("th", "Cost"); - f.TagText("th", "Material"); - f.TagText("th", "Skill (min level)"); - f.Enclose(0, "tr"); - for(i = 0; i < NOBJECTS; i++) { - if(ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if(ObjectDefs[i].productionAided != -1) continue; - if(ObjectDefs[i].protect) continue; - if(ObjectIsShip(i)) continue; - pS = FindSkill(ObjectDefs[i].skill); - if (pS == NULL) continue; - if(pS->flags & SkillType::MAGIC) continue; - j = ObjectDefs[i].item; - if(j == -1) continue; - /* Need the >0 since item could be WOOD_OR_STONE (-2) */ - if(j > 0 && (ItemDefs[j].flags & ItemType::DISABLED)) continue; - if(j > 0 && !(ItemDefs[j].type & IT_NORMAL)) continue; - /* Okay, this is a valid object to build! */ - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(j == I_WOOD_OR_STONE) - temp = "wood or stone"; - else - temp = ItemDefs[j].name; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = pS->name; - temp += AString(" (") + ObjectDefs[i].level + ")"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - } - if (Globals->DECAY) { - f.LinkRef("economy_builddecay"); - f.TagText("h3", "Building Decay:"); - temp = "Some structures will decay over time if they are not " - "maintained. Difficult terrain and bad weather will speed up " - "this decay. Maintnenance involves having units with the " - "appropriate level of skill expend a small amount of the " - "material used to build the structure and labor on a fairly " - "regular basis in the exactly same manner as they would work on " - "the building it if it was not completed. In other words, enter " - "the structure and issue the BUILD command with no parameters. " - "If a structure will need maintenance, that information will be " - "related in the object information given about the structure. " - "If a structure is allowed to decay, it will not give any of " - "its bonuses until it is repaired."; - f.Paragraph(temp); - } - if(may_sail) { - f.LinkRef("economy_ships"); - f.TagText("h3", "Ships:"); - temp = "Ships are constructed similarly to buildings, except they " - "tend to be constructed out of wood, not stone, and their " - "construction tends to depend on the Shipbuilding skill, not " - "the Building skill. "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp += "Only faction with at least one faction point spent on " - "trade can issue "; - temp += f.Link("#build", "BUILD") + " orders. "; - } - temp += "Here is a table on the various ship types:"; - f.Paragraph(temp); - f.LinkRef("tableshipinfo"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", ""); - f.TagText("th", "Capacity"); - f.TagText("th", "Cost"); - f.TagText("th", "Material"); - f.TagText("th", "Skill (level)"); - f.Enclose(0, "tr"); - for(i = 0; i < NOBJECTS; i++) { - if(ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if(!ObjectIsShip(i)) continue; - pS = FindSkill(ObjectDefs[i].skill); - if(pS == NULL) continue; - if(pS->flags & SkillType::MAGIC) continue; - j = ObjectDefs[i].item; - if(j == -1) continue; - /* Need the >0 since item could be WOOD_OR_STONE (-2) */ - if(j > 0 && (ItemDefs[j].flags & ItemType::DISABLED)) continue; -// if(j > 0 && !(ItemDefs[j].type & IT_NORMAL)) continue; //BS mod to show all ships - /* Okay, this is a valid object to build! */ - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].capacity); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(j == I_WOOD_OR_STONE) - temp = "wood or stone"; - else - temp = ItemDefs[j].name; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = pS->name; - temp += AString(" (") + ObjectDefs[i].level + ")"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - temp = "The capacity of a ship is the maximum weight that the ship " - "may have aboard and still move. The cost is both the " - "man-months of labor and the number of units of material " - "required to complete the ship. The sailors are the number of " - "skill levels of the Sailing skill that must be aboard the " - "ship (and issuing the "; - temp += f.Link("#sail", "SAIL") + " order in order for the ship " - "to sail)."; - f.Paragraph(temp); - } - f.LinkRef("economy_advanceditems"); - f.TagText("h3", "Advanced Items:"); -/* temp = "There are also certain advanced items that highly skilled units " - "can produce. These are not available to starting players, but can " - "be discovered through study. When a unit is skilled enough to " - "produce one of these items, he will receive a skill report " - "describing the production of this item. Production of advanced " - "items is generally done in a manner similar to the normal items.";*/ - temp = "Advanced items differ from normal items in three respects. Firstly, " - "the withdraw order only works for normal items. Secondly, when " - "advanced resources are present in a region, they will only be visible " - "to players if their faction has a unit present in the region, skilled " - "enough to produce the advanced resource. Thirdly, advanced items may " - "not be bought in cities, though in some cases they may be sold there by players."; - - f.Paragraph(temp); - - - f.LinkRef("economy_income"); - f.TagText("h3", "Income:"); - temp = "Units can earn money with the "; - temp += f.Link("#work", "WORK") + " order. This means that the unit " - "spends the month performing manual work for wages. The amount to " - "be earned from this is usually not very high, so it is generally " - "a last resort to be used if one is running out of money. The " - "current wages are shown in the region description for each region. " - "All units may "; - temp += f.Link("#work", "WORK") + ", regardless of skills"; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) - temp += "or faction type"; - temp += "."; - f.Paragraph(temp); - if(!(SkillDefs[S_ENTERTAINMENT].flags & SkillType::DISABLED)) { - f.LinkRef("economy_entertainment"); - f.TagText("h3", "Entertainment:"); - temp = "Units with the Entertainment skill can use it to earn " - "money. A unit with Entertainment level 1 will earn "; - temp += AString(Globals->ENTERTAIN_INCOME) + - " silver per man by issuing the "; - temp += f.Link("#entertain", "ENTERTAIN") + " order. The total " - "amount of money that can be earned this way is shown in the " - "region descriptions. Higher levels of Entertainment skill can " - "earn more, so a character with Entertainment skill 2 can earn " - "twice as much money as one with skill 1 (and uses twice as " - "much of the demand for entertainment in the region). Note that " - "entertainment income is much less, per region, than the income " - "available through working or taxing."; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp += " All factions may have entertainers, regardless of " - "faction type."; - } - f.Paragraph(temp); - } - - f.LinkRef("economy_taxingpillaging"); - f.TagText("h3", "Taxing/Pillaging:"); - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) - temp = "War factions "; - else - temp = "Factions "; - temp += "may collect taxes in a region. This is done using the "; - temp += f.Link("#tax", "TAX") + " order (which is "; - if(!Globals->TAX_PILLAGE_MONTH_LONG) temp += "not "; - temp += "a full month order). The amount of tax money that can be " - "collected each month in a region is shown in the region " - "description. "; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_ANYONE) { - temp += "Any unit may "; - temp += f.Link("#tax", "TAX"); - } else { - AString temp3; - int prev = 0, hold = 0; - temp += "A unit may "; - temp += f.Link("#tax", "TAX"); - temp += " if it "; - if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_COMBAT_SKILL | GameDefs::TAX_BOW_SKILL | - GameDefs::TAX_RIDING_SKILL | GameDefs::TAX_STEALTH_SKILL)) { - int prev2 = 0, hold2 = 0; - if (hold) { - if (prev) temp += ", "; - temp += temp2; - prev= 1; - } - temp2 = "has "; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_COMBAT_SKILL) { - temp3 = "Combat"; - hold2 = 1; - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_BOW_SKILL) { - if (hold2) { - temp2 += temp3; - prev2 = 1; - } - if (prev2) temp2 += ", "; - temp2 += "Longbow"; - prev2 = 1; - temp3 = "Crossbow"; - hold2 = 1; - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_RIDING_SKILL) { - if (hold2) { - if (prev2) temp2 += ", "; - temp2 += temp3; - prev2 = 1; - } - temp3 = "Riding"; - hold2 = 1; - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_STEALTH_SKILL) { - if (hold2) { - if (prev2) temp2 += ", "; - temp2 += temp3; - prev2= 1; - } - temp3 = "Stealth"; - hold2 = 1; - } - if (prev2) temp2 += " or "; - temp2 += temp3; - temp2 += " skill of at least level 1"; - hold = 1; - } - if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_ANY_WEAPON | GameDefs::TAX_USABLE_WEAPON | - GameDefs::TAX_MELEE_WEAPON_AND_MATCHING_SKILL | - GameDefs::TAX_BOW_SKILL_AND_MATCHING_WEAPON)) { - if (hold) { - if (prev) temp += ", "; - temp += temp2; - prev= 1; - } - temp2 = "has "; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_ANY_WEAPON) - temp2 += "a weapon (regardless of skill requirements)"; - else if (Globals->WHO_CAN_TAX & GameDefs::TAX_USABLE_WEAPON) - temp2 += "a weapon and the appropriate skill to use it"; - else if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_MELEE_WEAPON_AND_MATCHING_SKILL | - GameDefs::TAX_BOW_SKILL_AND_MATCHING_WEAPON)) { - AString temp3; - int prev2 = 0, hold2 = 0; - if (Globals->WHO_CAN_TAX & - GameDefs::TAX_MELEE_WEAPON_AND_MATCHING_SKILL) { - temp2 += "Combat skill of at least level 1 and a " - "weapon which does not require any skill"; - temp3 = "Riding skill of at least level 1 and " - "a weapon which requires riding skill"; - prev2 = 1; - hold2 = 1; - } - if (Globals->WHO_CAN_TAX & - GameDefs::TAX_BOW_SKILL_AND_MATCHING_WEAPON) { - if (hold2) { - temp2 += ", "; - temp2 += temp3; - } - temp3 = "a Bow (Longbow or Crossbow) skill and a weapon " - "which requires that skill"; - hold2 = 1; - } - if (prev2) temp2 += " or "; - temp2 += temp3; - } - hold = 1; - } - if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_HORSE | GameDefs::TAX_HORSE_AND_RIDING_SKILL)) { - if (hold) { - if (prev) temp += ", "; - temp += temp2; - prev= 1; - } - temp2 = "has a mount"; - if (!(Globals->WHO_CAN_TAX & GameDefs::TAX_HORSE)) - temp2 += " and sufficient skill to ride it in combat"; - hold = 1; - } - if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_ANY_MAGE | GameDefs::TAX_MAGE_DAMAGE | - GameDefs::TAX_MAGE_FEAR | GameDefs::TAX_MAGE_OTHER)) { - if (hold) { - if (prev) temp += ", "; - temp += temp2; - prev= 1; - } - temp2 = "is a mage "; - if ((Globals->WHO_CAN_TAX & - (GameDefs::TAX_MAGE_DAMAGE | - GameDefs::TAX_MAGE_FEAR | - GameDefs::TAX_MAGE_OTHER)) == - (GameDefs::TAX_MAGE_DAMAGE | GameDefs::TAX_MAGE_FEAR | - GameDefs::TAX_MAGE_OTHER)) { - if (Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_COMBAT_SPELL) - temp2 += "who has a combat spell set"; - else - temp2 += "who knows a combat spell"; - } else { - int hold2 = 0, prev2 = 0; - AString temp3; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_COMBAT_SPELL) - temp2 += "whose combat spell "; - else - temp2 += "who knows a spell which "; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_DAMAGE) { - temp3 = "damages enemies"; - hold2 = 1; - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_FEAR) { - if (hold2) { - temp2 += temp3; - prev2 = 1; - } - temp3 = "weakens opponents"; - hold2 = 1; - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_OTHER) { - if (hold2) { - if (prev2) temp2 += ", "; - temp2 += temp3; - prev2 = 1; - } - temp3 = "protects in combat"; - hold2 = 1; - } - if (prev2) temp2 += " or "; - temp2 += temp3; - } - hold = 1; - } - if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_BATTLE_ITEM | - GameDefs::TAX_USABLE_BATTLE_ITEM)) { - if (hold) { - if (prev) temp += ", "; - temp += temp2; - prev= 1; - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_USABLE_BATTLE_ITEM) - temp2 = "has a "; - else - temp2 = "can use a "; - temp2 += "magical item which gives a special attack in combat"; - hold = 1; - } - if (prev) temp += " or "; - temp += temp2; - temp += ". "; - } - if (Globals->WHO_CAN_TAX & - (GameDefs::TAX_CREATURES | GameDefs::TAX_ILLUSIONS)) { - if (Globals->WHO_CAN_TAX & GameDefs::TAX_CREATURES) { - temp += "Summoned "; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_ILLUSIONS) - temp += "and illusory "; - } else if (Globals->WHO_CAN_TAX & GameDefs::TAX_ILLUSIONS) - temp += "Illusory "; - temp += "creatures will assist in taxation. "; - } - temp += "Each taxing character can collect a minimum of $"; - temp += AString(Globals->TAX_BASE_INCOME) + ", though if the number of " - "taxers would tax more than the available tax income, the tax " - "income is split evenly among all taxers."; - f.Paragraph(temp); - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) - temp = "War factions "; - else - temp = "Factions "; - temp += "may also pillage a region. To do this requires the faction to " - "have enough combat ready men in the region to tax half of the " - "available money in the region. The total amount of money that can " - "be pillaged will then be shared out between every combat ready " - "unit that issues the "; - temp += f.Link("#pillage", "PILLAGE") + " order. The amount of money " - "collected is equal to twice the available tax money. However, the " - "economy of the region will be seriously damaged by pillaging, and " - "will only slowly recover over time. Note that "; - temp += f.Link("#pillage", "PILLAGE") + " comes before " + - f.Link("#tax", "TAX") + ", so a unit performing " + - f.Link("#tax", "TAX") + " will collect no money in that region that " - "month."; - f.Paragraph(temp); - temp = "It is possible to safeguard one's tax income in regions one " - "controls. Units which have the Guard flag set (using the "; - temp += f.Link("#guard", "GUARD") + " order) will block " + - f.Link("#tax", "TAX") + " orders issued by other factions in the same " - "region, unless you have declared the faction in question Friendly. " - "Units on guard will also block "; - temp += f.Link("#pillage", "PILLAGE") + " orders issued by other " - "factions in the same region, regardless of your attitude towards " - "the faction in question, and they will attempt to prevent " - "Unfriendly units from entering the region. Only units which are " - "able to tax may be on guard. Units on guard "; - if(has_stea) - temp += " are always visible regardless of Stealth skill, and "; - temp += "will be marked as being \"on guard\" in the region description."; - f.Paragraph(temp); - - if (qm_exist) { - f.LinkRef("economy_transport"); - f.TagText("H3", "Transportation of goods"); - - temp = "Trade factions may train Quartermaster units. A " - "Quartermaster unit, may accept "; - temp += f.Link("#transport", "TRANSPORT") + "ed items, from " - "any unit within " + Globals->LOCAL_TRANSPORT + " hexes " - "distance from the hex containing the quartermaster. "; - temp += "Quartermasters may also"; - temp += f.Link("#distribute", "DISTRIBUTE") + " items to any " - "unit within " + Globals->LOCAL_TRANSPORT + " hexes " - "distance from the hex containing the quartermaster and may " + - f.Link("#transport", "TRANSPORT") + " items to another " - "quartermaster up to " + Globals->NONLOCAL_TRANSPORT + - " hexes distant."; - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_DIST) { - temp += " The distance a quartermaster can "; - temp += f.Link("#transport", "TRANSPORT") + " items to " - "another quartermaster will increase with the level of " - "skill possessed by the quartermaster unit."; - } - f.Paragraph(temp); - temp = "In order to accomplish this function, a quartermaster " - "must be the owner of a structure which allows transportation " - "of items. The structures which allow this are: "; - last = -1; - comma = 0; - j = 0; - for (i = 0; i < NOBJECTS; i++) { - if (!(ObjectDefs[i].flags & ObjectType::TRANSPORT)) continue; - j++; - if (last == -1) { - last = i; - continue; - } - temp += ObjectDefs[i].name; - temp += ", "; - comma++; - last = i; - } - if (comma) temp += "and "; - temp += ObjectDefs[last].name; - temp += "."; - f.Paragraph(temp); - - if (Globals->SHIPPING_COST > 0) { - temp = "The cost of transport items from one quartermaster to " - "another is based on the weight of the items and costs $"; - temp += Globals->SHIPPING_COST; - temp += " silver per weight unit."; - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_COST) { - temp += " The cost of shipping is increased for units with a " - "lower quartermaster skill, dropping to the minimum " - "above when the unit is at the maximum skill level."; - } - f.Paragraph(temp); - } - - temp = "Quartermasters must be single man units"; - if (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - temp += ", and a faction is limited in the number of " - "quartermasters it may have at any one time"; - } - temp += ". Both the "; - temp += f.Link("#transport", "TRANSPORT") + " and " + - f.Link("#distribute", "DISTRIBUTE") + " orders count as " - "trade activity in the hex of the unit issuing the order. "; - temp += " The target unit must be at least FRIENDLY to the unit " - "which issues the order."; - f.Paragraph(temp); - } - - if(Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) { - f.LinkRef("economy_banking"); - f.TagText("H3","Banking:"); - temp = "Each faction has access to a bank account where silver can " - "be deposited and withdrawn. Initially the bank account is " - "empty and can be operated using the "; - temp += f.Link("#bank","BANK") + " order. "; - if (!(ObjectDefs[O_OBANK].flags & ObjectType::DISABLED) - || (Globals->ALLOW_BANK & GameDefs::BANK_INSETTLEMENT) - || (Globals->ALLOW_BANK & GameDefs::BANK_NOTONGUARD)) { - temp += "A unit issuing the "; - temp += f.Link("#bank","BANK") + " order "; - if (!(ObjectDefs[O_OBANK].flags & ObjectType::DISABLED)) { - // do we have banks ? - temp += "must be inside a bank"; - if (Globals->ALLOW_BANK & GameDefs::BANK_INSETTLEMENT) - temp += ", which "; - } - if(Globals->ALLOW_BANK & GameDefs::BANK_INSETTLEMENT) { - temp += "must be located in a region "; - temp += "with a settlement of any size"; - } - if(Globals->ALLOW_BANK & GameDefs::BANK_NOTONGUARD) - temp += " which cannot be guarded by a faction with " - "an attitude less than Friendly"; - temp += "."; - } - if (!(SkillDefs[S_BANKING].flags & SkillType::DISABLED)) { - // do we have banking skill ? - temp += " To be able to use the "; - temp += f.Link("#bank","BANK") + " order, a unit must possess " - "the BANKING skill. Each level of this skill enables the " - "unit to withdraw or deposit "; - temp += Globals->BANK_MAXSKILLPERLEVEL; - temp += " silver."; - } else { - temp += " Each unit is limited to withdrawing or depositing "; - temp += Globals->BANK_MAXUNSKILLED; - temp += " silver."; - } - if (Globals->ALLOW_BANK & GameDefs::BANK_FEES) { - temp += " Every operation (be it depositing or withdrawing) " - "will incur in a fee of "; - temp += Globals->BANK_FEE; - temp += "% the amount. The full amount will be deducted from " - "the bank account (for a withdrawal) and from the unit " - "(for a deposit), though only the amount after the fees " - "will be transferred. For example, a unit trying to " - "deposit 5000 silver, would see 5000 silver taken from " - "its inventory, but only "; - temp += (5000 - (5000 * Globals->BANK_FEE)/100); - temp += " silver would be credited in the bank account."; - } - if (Globals->ALLOW_BANK & GameDefs::BANK_TRADEINTEREST) { - temp += " Each faction will receive an interest in the deposit " - "equal to the number of its trade points in percentage (a " - "trade 5 faction would get 5%). "; - } - // FIXME: mention Globals->ALLOW_BANK & GameDefs::BANK_SKILLTOBUILD - // here"; - f.Paragraph(temp); - } - - f.LinkRef("com"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Combat"); - temp = "Combat occurs when one unit attacks another. The computer then " - "gathers together all the units on the attacking side, and all the " - "units on the defending side, and the two sides fight until an " - "outcome is reached."; - f.Paragraph(temp); - f.LinkRef("com_attitudes"); - f.TagText("h3", "Attitudes:"); - temp = "Which side a faction's units will fight on depends on declared " - "attitudes. A faction can have one of the following attitudes " - "towards another faction: Ally, Friendly, Neutral, Unfriendly or " - "Hostile. Each faction has a general attitude, called the \"Default " - "Attitude\", that it normally takes towards other factions; this is " - "initially Neutral, but can be changed. It is also possible to "; - temp += f.Link("#declare", "DECLARE") + " attitudes to specific " - "factions, e.g. "; - temp += f.Link("#declare", "DECLARE") + " 27 ALLY will declare the " - "Ally attitude to faction 27. (Note that this does not necessarily " - "mean that faction 27 has decided to treat you as an ally.)"; - f.Paragraph(temp); - temp = "Ally means that you will fight to defend units of that faction " - "whenever they come under attack, if you have non-avoiding units in " - "the region where the attack occurs. "; - if(has_stea) { - temp += " You will also attempt to prevent any theft or " - "assassination attempts against units of the faction"; - if(has_obse) { - temp += ", if you are capable of seeing the unit which is " - "attempting the crime"; - } - temp += ". "; - } - temp += "It also has the implications of the Friendly attitude."; - f.Paragraph(temp); - temp = "Friendly means that you will accept gifts from units of that " - "faction. This includes the giving of items, units of people, and " - "the teaching of skills. You will also admit units of that faction " - "into buildings or ships owned by one of your units, and you will " - "permit units of that faction to collect taxes (but not pillage) " - "in regions where you have units on guard."; - f.Paragraph(temp); - temp = "Unfriendly means that you will not admit units of that faction " - "into any region where you have units on guard. You will not, " - "however, automatically attack unfriendly units which are already " - "present."; - f.Paragraph(temp); - temp = "Hostile means that any of your units which do not have the " - "Avoid Combat flag set (using the "; - temp += f.Link("#avoid", "AVOID") + " order) will attack any units of " - "that faction wherever they find them."; - f.Paragraph(temp); - temp = "If a unit can see another unit, but "; - if(has_obse) { - temp += "does not have high enough Observation skill to determine " - "its faction,"; - } else { - temp += "it is not revealing its faction,"; - } - temp += " it will treat the unit using the faction's default attitude, " - "even if the unit belongs to an Unfriendly or Hostile faction, " - "because it does not know the unit's identity. However, if your " - "faction has declared an attitude of Friendly or Ally towards that " - "unit's faction, the unit will be treated with the better attitude; " - "it is assumed that the unit will produce proof of identity when " - "relevant."; - if(has_stea) { - temp += " (See the section on stealth for more information on when " - "units can see each other.)"; - } - f.Paragraph(temp); - temp = "If a faction declares Unfriendly or Hostile as default attitude " - "(the latter is a good way to die fast), it will block or attack " - "all unidentified units, unless they belong to factions for which a " - "Friendly or Ally attitude has been specifically declared."; - if(has_stea) { - temp += " Units which cannot be seen at all cannot be directly " - "blocked or attacked, of course."; - } - f.Paragraph(temp); - f.LinkRef("com_attacking"); - f.TagText("h3", "Attacking:"); - temp = "A unit can attack another by issuing an "; - temp += f.Link("#attack", "ATTACK") + " order. A unit that does not " - "have Avoid Combat set will automatically attack any Hostile units " - "it identifies as such."; - if(has_stea || !(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) { - temp += " When a unit issues the "; - temp += f.Link("#attack", "ATTACK") + " order, or otherwise " - "decides to attack another unit, it must first be able to " - "attack the unit. "; - if(has_stea && !(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) - temp += "On land, there are two conditions for this; the first is that the"; - else - temp += "The"; - if(has_stea) { - temp += " attacking unit must be able to see the unit that it " - "wishes to attack. More information is available on this " - "in the stealth section of the rules."; - } - if(!(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) { - if(has_stea) { - f.Paragraph(temp); - temp = "Secondly, the"; - } - temp += " attacking unit must be able to catch the unit it " - "wishes to attack. A unit may only catch a unit if its " - "effective Riding skill is greater than or equal to the " - "target unit's effective Riding skill; otherwise, the " - "target unit just rides away from the attacking unit. " - "Effective Riding is the unit's Riding skill, but with " - "a potential maximum; if the unit can not ride, the " - "effective Riding skill is 0; if the unit can ride, the " - "maximum effective Riding is 3; if the unit can fly, the " - "maximum effective Riding is 6. Note that the effective " //Arcadia mod - "Riding also depends on whether the unit is attempting to " - "attack or defend; for attack purposes, only one man in " - "the unit needs to be able to ride or fly (generally, this " - "means one of the men must possess a horse, or other form " - "of transportation), whereas for defense purposes the entire " - "unit needs to be able to ride or fly (usually meaning " - "that every man in the unit must possess a horse or other " - "form of speedier transportation). Also, note that for a " - "unit to be able to use its defensive Riding ability to " - "avoid attack, the unit cannot be in a building, ship, or " - "structure of any type."; - } - } - f.Paragraph(temp); - temp = "A unit which is on guard, and is Unfriendly towards a unit, " - "will deny access to units using the "; - temp += f.Link("#move", "MOVE") + " order to enter its region. "; - if(has_stea || !(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) { - temp += "Note that to deny access to a unit, at least one unit " - "from the same faction as the unit guarding the hex must satisfy " - "the above requirements. "; - } - temp += "A unit using "; - temp += f.Link("#advance", "ADVANCE") + " instead of " + - f.Link("#move", "MOVE") + " to enter a region, will attack any " - "units that attempt to deny it access. If the advancing unit loses " - "the battle, it will be forced to retreat to the previous region it " - "moved through. If the unit wins the battle and its army doesn't " - "lose any men, it is allowed to continue to move, provided that it " - "has enough movement points."; - f.Paragraph(temp); - if(has_stea || !(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) { - temp = "Note that "; - if(has_stea && !(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) - temp += "these restrictions do "; - else - temp += "this restriction does "; - temp += "not apply for sea combat, as "; - if(has_stea) - temp += "units within a ship are always visible"; - if(!(SkillDefs[S_RIDING].flags & SkillType::DISABLED)) { - if(has_stea) temp += ", and"; - temp += " Riding does not play a part in combat on board ships"; - } - temp += ". Instead, if a unit at sea wishes to attack a unit " - "onboard a different ship, then that unit's ship must be able" - "to catch the ship of the unit it wishes to attack. This will " - "occur if the speed of the unit's ship is equal to or greater " - "than the speed of the target's ship. Note that if a ship " - "cannot move due to a shortage of skilled sailors, or if " - "it is overloaded, then it may always be caught. Units may " - "always attack a unit which is in the same ship."; - f.Paragraph(temp); - } - f.LinkRef("com_muster"); - f.TagText("h3", "The Muster:"); - temp = "Once the attack has been made, the sides are gathered. Although " - "the "; - temp += f.Link("#attack", "ATTACK") + " order takes a unit rather than " - "a faction as its parameter (mainly so that unidentified units can " - "be attacked), an attack is basically considered to be by an entire " - "faction, against an entire faction and its allies."; - f.Paragraph(temp); - temp = "On the attacking side are all units of the attacking faction in " - "the region where the fight is taking place, except those with Avoid " - "Combat set. A unit which has explicitly (or implicitly via "; - temp += f.Link("#advance", "ADVANCE") + ") issued an " + - f.Link("#attack", "ATTACK") + " order will join the fight anyway, " - "regardless of whether Avoid Combat is set."; - f.Paragraph(temp); - temp = "Also on the attacking side are all units of other factions that " - "attacked the target faction (implicitly or explicitly) in the " - "region where the fight is taking place. In other words, if several " - "factions attack one, then all their armies join together to attack " - "at the same time (even if they are enemies and will later fight " - "each other)."; - f.Paragraph(temp); - temp = "On the defending side are all identifiable units belonging to " - "the defending faction. If a unit has Avoid Combat set and it " - "belongs to the target faction, it will be uninvolved only if its " - "faction cannot be identified by the attacking faction. A unit " - "which was explicitly attacked will be involved anyway, regardless " - "of Avoid Combat. "; - if(has_stea) { - temp += "(This means that Avoid Combat is mostly useful for high " - "stealth scouts.) "; - } - temp += "Also, all non-avoiding units located in the target region " - "belonging to factions allied with the defending unit will join " - "in on the defending side"; - if(Globals->ALLIES_NOAID) - temp += ", provided that at least one of the units belonging to " - "the defending faction is not set to noaid."; - else - temp += "."; - f.Paragraph(temp); - temp = "Units in adjacent regions can also become involved. This is " - "the exception to the general rule that you cannot interact with " - "units in a different region."; - f.Paragraph(temp); - temp = "If a faction has at least one unit involved in the initial " - "region, then any units in adjacent regions will join the fight, " - "if they could reach the region and do not have Avoid Combat set. " - "There are a few flags that units may set to affect this; a unit " - "with the Hold flag (set using the "; - temp += f.Link("#hold", "HOLD") + " order) will not join battles in " - "adjacent regions. This flag applies to both attacking and " - "defending factions. A unit with the Noaid flag (set using the "; - temp += f.Link("#noaid", "NOAID") + " order) will receive no aid from " - "adjacent hexes when attacked, or when it issues an attack."; - f.Paragraph(temp); - temp = "Example: A fight starts in region A, in the initial combat " - "phase (before any movement has occurred). The defender has a unit " - "of soldiers in adjacent region B. They have 2 movement points at " - "this stage. "; - temp += "They will buy horses later in the turn, so that when " - "they execute their "; - temp += f.Link("#move", "MOVE") + " order they will have 4 movement " - "points, but right now they have 2. "; - if(Globals->WEATHER_EXISTS) - temp += "Region A is forest, but fortunately it is summer, "; - else - temp += "Region A is forest, "; - temp += "so the soldiers can join the fight."; - f.Paragraph(temp); - temp = "It is important to note that the units in nearby regions do not " - "actually move to the region where the fighting happens; the " - "computer only checks that they could move there. (In game world " - "terms, presumably they did move there to join the fight, and then " - "moved back where they started.) The computer checks for weight " - "allowances and terrain types when determining whether a unit could " - "reach the scene of the battle. Note that the use of ships is not " - "allowed in this virtual movement."; - f.Paragraph(temp); - temp = "If you order an attack on an ally (either with the "; - temp += f.Link("#attack", "ATTACK") + " order, or if your ally has " - "declared you Unfriendly, by attempting to "; - temp += f.Link("#advance", "ADVANCE") +" into a region which he is " - "guarding), then your commander will decide that a mistake has " - "occurred somewhere, and withdraw your troops from the fighting " - "altogether. Thus, your units will not attack that faction in " - "that region. Note that you will always defend an ally against " - "attack, even if it means that you fight against other factions " - "that you are allied with."; - f.Paragraph(temp); - f.LinkRef("com_thebattle"); - f.TagText("h3", "The Battle:"); - - if(!(SkillDefs[S_TACTICS].flags & SkillType::DISABLED)) { - temp = " The computer selects the best tactician from each side; " - "that unit is regarded as the commander of its side. If two or " - "more units on one side have the same Tactics skill, then the " - "one with the lower unit number is regarded as the commander of " - "that side."; - f.Paragraph(temp); - } - - temp = "Having arrived on the battlefield, the troops are split up into battle formations."; - temp += " Formations can be of three types - foot, riding, or flying. At the start " - "of each battle, two formations of each type will be created, one for units " - "which will be fighting from the front, and one for units with the behind flag " - "activated, which will attempt to avoid hand-to-hand combat. To join a riding " - "formation, a soldier must not only have a mount, but to have high enough " - "riding skill to use that mount in combat. To join a flying formation, the soldier " - "must have a mount capable of flight, and sufficient skill to use it."; - temp += " The terrain in which the battle is fought has a strong influence on the battle " - "lines. The following table presents the effects of various terrains on foot, " - "riding and flying units."; - f.Paragraph(temp); - - f.LinkRef("tablebattleterrain"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", "Terrain"); - f.TagText("th", " Foot "); - f.TagText("th", " Riding "); - f.TagText("th", " Flying "); - f.TagText("th", " Ranged "); - f.Enclose(0, "tr"); - /*int num = 8; - if(Globals->UNDERWORLD_LEVELS > 0) num = 11; - if(Globals->UNDERDEEP_LEVELS > 0) num = 14;*/ - - - - for(i = 0; i < R_NUM; i++) { - if(TerrainDefs[i].flags & TerrainType::DISABLED) continue; - if(i == R_NEXUS) continue; -// if(RegionDefs[i].flags & RegionDefs::DISABLED) continue; - - /* Okay, this is a valid region for standard games! */ - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(TerrainDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - if(TerrainDefs[i].flags & TerrainType::RESTRICTEDFOOT) temp = " Restricted "; - else temp = " Normal "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - if(TerrainDefs[i].flags & TerrainType::RIDINGLIMITED) temp = " Limited "; - else if(TerrainDefs[i].flags & TerrainType::RIDINGMOUNTS) temp = " Normal "; - else temp = " None "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - if(TerrainDefs[i].flags & TerrainType::FLYINGLIMITED) temp = " Limited "; - else if(TerrainDefs[i].flags & TerrainType::FLYINGMOUNTS) temp = " Normal "; - else temp = " None "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\""); - if(TerrainDefs[i].flags & TerrainType::RESTRICTEDRANGED) temp = " Restricted "; - else if(TerrainDefs[i].flags & TerrainType::ENHANCEDRANGED) temp = " Enhanced "; - else temp = " Normal "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - temp = "If the terrain does not allow for riding in battle, " - "then any units which would normally ride will fight on foot. " - "If flying units are not allowed in the terrain, then those " - "units will try to ride. If they cannot ride, they " - "will also fight on foot. If the terrain allows for limited " - "riding or flying, then formations will be created and behave " - "as normal; however, the soldiers in these formations will " - "not get any combat bonus due to their riding skill, as " - "detailed later in this section. In terrains where foot " - "movement is restricted, foot formations may not undertake " - "any battle maneuvres, such as flanking around outnumbered " - "opponents. If ranged attacks are restricted, " - "ranged units have a -1 penalty to their attack skill " - "and chance-to-attack. Enhanced ranged attacks gain a +1 bonus. " - "Note two exceptions here: because of their skill with ranged weapons, " - "elves do not suffer from ranged penalties, and, except for elves, " - "enhanced range bonuses apply only to magic attacks, not to " - "attacks with bow or crossbow."; - f.Paragraph(temp); - /* - temp = "Formations are also limited by the skill of the tactitian " - "commanding the battle. If the commander of a side is not " - "sufficiently skilled to command " - "flying or riding cavalry, then those units will fight " - "using tactics understood by the commander. However, if the " - "terrain allows it, these units will still get a combat " - "bonus from their riding skill."; - f.Paragraph(temp); - */ - /* - if(!(SkillDefs[S_TACTICS].flags & SkillType::DISABLED)) { - temp += " The computer selects the best tactician from each side; " - "that unit is regarded as the leader of its side. If two or " - "more units on one side have the same Tactics skill, then the " - "one with the lower unit number is regarded as the leader of " - "that side. If one side's leader has a better Tactics skill " - "than the other side's, then that side gets a free round of " - "attacks."; - } - f.Paragraph(temp);*/ - - temp = "Coordinating large armies is no easy task, however, it is assumed " - "the commander of an army delegates sufficient officers to help " - "him or her control it. Some spells are able to interfere " - "with this control; if one is active, and there is no friendly mage " - "able to cast a counterspell, then some soldiers will not be placed in their proper formation. In " - "addition, the lack of coordination will effect the success of " - "some maneuvers undertaken during battle. " - "These magic spells can potentially turn a well commanded army into " - "a confused horde of soldiers, which may (depending on the army's " - "makeup) make a massive difference to its success in battle."; - f.Paragraph(temp); - - temp = "Armies made of mixed ethnicities will suffer morale problems, as soldiers " - "do not like to fight alongside troops they are not well disposed to. " - "On average, if x% of the army are of a different ethnicity, then " - "a soldier will suffer a penalty of \"2x\" to his or her attack " - "melee defence skills. So if an army is composed of 90 elves and " - "10 orcs, the elves will, on average lose 0.2 to their attack and " - "defence skills (which means they have a 20% chance of a -1 penalty, " - "since attack and defence skills are always integers), while the orcs " - "will suffer a penalty of 1.8, ie an 80% chance of a -2 penalty and a " - "20% chance of a -1 penalty. Monsters fighting in an army do not cause " - "or suffer morale penalties, except for the undead, who will cause " - "morale penalties to elves, dwarves and humans. The hero skill \"unity\" " - "can help alleviate morale penalties in battle."; - f.Paragraph(temp); - - temp = AString("In each combat round, combat formations vie for position. ") + - "Foot troops will initially engage the enemy foot troops, " - "while cavalry may attempt to flank behind the enemy, or " - "stay in reserve and defend ranged troops from " - "enemy cavalry. Formations which sufficiently outnumber " - "their opponents may also send some men to flank " - "behind the enemy; assuming perfect army control, " - "a formation needs to be 2.5 times the size of its " - "before any men will flank. Most of these decisions are " - "made by the commander of the army, but they can be " - "influenced with the " + f.Link("#tactics", "TACTICS") + " order " - "which can make the commander more or less aggressive in the use " - "of his cavalry."; - f.Paragraph(temp); - - temp = "Units which successfully flank behind the enemy may hit " - "ranged soldiers who are behind the frontline, or attack the " - "enemy frontline from behind. In the latter case, they gain a +1 bonus " - "to their attack skill and chance-to-attack."; - temp += " Cavalry and aerial cavalry units which are positioned " - "behind the frontline (eg mounted archers) will attempt to evade their attackers, " - "with flying units more likely to succeed in doing so. " - "However, ranged units do not need to " - "be able to catch a formation in order to attack them."; - f.Paragraph(temp); - - temp = "When formations have completed their positioning, the " - "combatants each get to attack once, in a random order. " - "Each combatant will attempt to hit an enemy randomly " - "selected from all formations with which he is engaged. " - "If he hits, and the target has no armour, then the target is " - "automatically killed. Armour may provide extra defense against " - "otherwise successful attacks. " - "If the attacker's formation is not directly engaged with " - "the enemy (for example " - "a soldier with the behind flag which has not been " - "engaged by enemy cavalry) then he will only attack if " - "equipped with a ranged weapon or magic skill. Ranged units " - "will first target formations they are personally engaged with, " - "then formations which have flanked or are flanking, and then " - "the enemy's frontline. Only when all other enemies have been " - "killed will a ranged unit with the behind flag attack enemy " - "ranged formations. "; - temp += "If any melee formation kills all enemies with which it is engaged, then " - "it will attempt to engage another target."; - f.Paragraph(temp); - - temp = "The basic skill used in battle is the Combat skill; this is " - "used for hand to hand fighting. If one soldier tries to hit " - "another using most weapons, he has a 1:1 (ie 50%) chance-to-attack. " - "This chance-" - "to-attack may be modified by terrain (-1 for ranged units in " - "restricted terrains), by position (+1 for soldiers who have " - "attacked the enemy frontline from behind while the enemy is still " - "engaged with attackers from the front), by fortifications (-1 or -2 " - "if attacking a soldier in a fort or other defensive " - "building), or by some spells. A +1 bonus gives a soldier a 1+1=2:1 " - "(i.e. 67%) chance-to-attack, while a -2 bonus gives a soldier " - "a 1:1+2=3 (ie 25%) chance. If the " - "attacker does get to attack, then there is a contest " - "between his combat skill (modified by weapon attack bonus) and " - "the defender's combat skill (modified by weapon defense bonus). " - "Some weapons may not allow combat skill to affect defense (e.g. " - "bows), and others may allow different skills to be used on " - "defense (or offense)."; - f.Paragraph(temp); - temp = "If the skills are equal, then there is a 1:1 (i.e. 50%) " - "chance that the attack will succeed. If the attacker's skill is 1 " - "higher then there is a 2:1 (i.e. 67%) chance, if the attacker's " - "skill is 2 higher then there is a 4:1 (i.e. 80%) chance, 3 higher " - "means an 8:1 (i.e. 88%) chance (2*2*2 = 8), and so on. Similarly if the " - "defender's skill is 3 higher, then there is only a 1:8 (i.e. 11%) " - "chance, etc."; - f.Paragraph(temp); - temp = ""; - temp = "There are a variety of weapons in the world which can increase " - "a soldier's skill on attack or defense. Better weapons will " - "generally convey better bonuses, but not all weapons are as good " - "in all situations. Specifics about the bonuses conferred by " - "specific weapons can be found both in these rules (for most basic " - "weapons), and in the descriptions of the weapons themselves. Troops " - "which are fighting hand-to-hand without specific weapons are " - "assumed to be irregularly armed with makeshift weapons such as " - "clubs, pitchforks, torches, etc. "; - f.Paragraph(temp); - - temp = "Possession of a mount, and the appropriate skill to use that " - "mount, may also confer a bonus to the effective combat skill. The " - "amount of the bonus will depend on the level of the appropriate " - "skill and the mount in question. Some mounts are better than " - "others, and may provide better bonus, but may also require higher " - "levels of skill to get any bonus at all. Some terrain, as listed " - "above, will not " - "allow mounts to give a combat advantage at all."; - f.Paragraph(temp); - -/* Not enabled in Arcadia !!! - temp += "Certain weapons may provide different attack and defense " - "bonuses, or have additional attack bonuses against mounted " - "opponents or other special characteristics. These bonuses will " - "be listed in the item descriptions in the turn reports."; - f.Paragraph(temp); - temp = "Some melee weapons may be defined as Long or Short (this is " - "relative to a normal weapon, e.g. the sword). A soldier wielding " - "a longer weapon than his opponent gets a +1 bonus to his attack " - "skill."; - f.Paragraph(temp); - */ - temp = "Ranged weapons are slightly different from melee weapons. The " - "target will generally not get any sort of combat bonus to defense " - "against a ranged attack. Also, the weapon may require a skill other " - "than the Combat skill for a soldier to use. " - "In addition, when defending against an attack, a " - "soldier using a ranged weapon will generally be " - "treated as if they have a Combat skill of 0, even if they have an " - "actual Combat skill. This is the trade off for being able to hit " - "from the back line of fighting."; - f.Paragraph(temp); - temp = "Some weapons, including some ranged weapons, may only attack " - "every other round, or even less frequently. When a weapon is not " - "able to attack every round, this will be specified in the item " - "description. Wielders of these weapons will still move around in " - "their formations, even if they cannot attack in that round."; - f.Paragraph(temp); - temp = "Weapons may have one of several different attack types: " - "Slashing, Piercing, Crushing, Cleaving and Armour Piercing. " - "Different types of armour may give different survival chances " - "against a sucessful attack of different types."; - //Arcadia only: - temp += " In this version of Atlantis, Slashing, Piercing, " - "Crushing and Cleaving weapons all have identical effects, " - "and there is no difference between these types of attacks. " - "The terminology is included only because Atlantis is " - "based on a game engine which has the ability to be more " - "more complex."; - f.Paragraph(temp); - temp = "Being inside a building confers a bonus to a soldier's defence " - "skill (in addition to giving the attacker a -1 penalty to his " - "chance-to-attack). This " - "bonus is effective against ranged as well as melee attacks. " - "The magnitude of the defensive bonus may vary between buildings, " - "and will be listed in the description of a building. " - /* "This bonus is equal to a +2 increase in the defensive skill level, " - "regardless of the building type, providing that the number of men " - "the building can protect is not exceeded (some buildings, such as " - "trade structures, cannot protect any men). "*/ - "The number of men that a building can protect is equal to its size. " - "The size of the various common buildings was listed in the "; - temp += f.Link("#tablebuildings", "Table of Buildings") + " earlier. "; - f.Paragraph(temp); - temp = "If there are too many units in a building to all gain " - "protection from it, then those units who have been in the building " - "longest will gain protection. (Note that these units appear first " - "on the turn report.)"; - if(!(ObjectDefs[O_FORT].flags & ObjectType::DISABLED)) { - temp += " If a unit of 200 men is inside a Fort (capacity "; - temp += ObjectDefs[O_FORT].protect; - temp += "), then the first "; - temp += ObjectDefs[O_FORT].protect; - temp += " men in the unit will gain the full +2 bonus, and the other "; - temp += (200 - ObjectDefs[O_FORT].protect); - temp += " will gain no protection."; - } - f.Paragraph(temp); - - f.LinkRef("com_report"); - f.TagText("h3", "The Battle Report"); - temp = "Everything which occurs during a battle will be recorded in the battle " - "report. This is seen by everyone who has units in the region where the " - "battle took place. For each round of the battle, you will see a list of " - "spells cast, formation movements, and a summary of how many people from " - "each side died in that combat round."; - f.Paragraph(temp); - temp = "In addition, at the start of every combat round, you will see a diagrammatical " - "map of the battle, marking infantry, cavalry, aerial cavalry and ranged troops " - "from both sides. An example map is below: "; - f.Paragraph(temp); - - f.Enclose(1, "pre"); - f.PutNoFormat(" The Battle Position:"); - f.PutNoFormat(" Fighters (106)"); - f.PutNoFormat(" R#: 5 - line 1"); - f.PutNoFormat(" C#: 20 I*: 12 - line 2"); - f.PutNoFormat(" C#: 18 I#: 36 - line 3"); - f.PutNoFormat(" I*: 102 - line 4"); - f.PutNoFormat(" C*: 5 - line 5"); - f.PutNoFormat(" C#: 43 R*: 4 A#: 18 - line 6"); - f.PutNoFormat(" City Guard (8)"); - f.Enclose(0, "pre"); - - temp = "In this example, unit 106, named 'Fighters', attacked unit 8, the City Guard. " - "Entries marked with a # represent soldiers belonging to the attacker, 'Fighters', " - "while entries with a * represent soldiers belonging to the defender, 'City Guard'. " - "The first line below fighters has places for three entries. First, are listed the " - "number of 'City Guard' cavalry which have flanked around to 'Fighters' backline. " - "Second, is listed the number of troops in 'Fighters' ranged formations, whether " - "on foot, horseback, or flying. Third, are the number of aerial cavalry belonging " - "to 'City Guard' which have flanked around to 'Fighters' backline. In this instance, " - "two of these entries are blank, indicating that 'City Guard' does not have any " - "cavalry behind 'Fighters' frontline. 'Fighters' does, however, have 5 troops " - "assigned to his ranged formations. These are soldiers from a unit with the behind " - "flag set, they may or may not have ranged weapons."; - f.Paragraph(temp); - temp = "The second line in this example lists: (i) 'Fighters' cavalry which is in reserve, " - "and trying to prevent 'City Guard' soldiers from getting to the 'Fighters' backline, " - "(ii) 'City Guard' infantry which has flanked around 'Fighters' frontline, and reached " - "their backline, and (iii) 'Fighters' aerial cavalry which is in reserve. In this case, 'City Guard' " - "has 12 infantry which reached the backline of 'Fighters', despite 'Fighters' still " - "having 20 cavalry in reserve. Such a situation would not commonly occur (usually the " - "cavalry would intercept the soldiers before they reached the backline) but there " - "are some spells which may bring this about. The map does not tell you who 'City Guards' " - "flanked infantry is fighting, but in most cases it will be attacking the 'Fighters' 5 ranged " - "soldiers, while also being attacked by 'Fighters' 20 reserve cavalry. " - "The third line in the battle lists (i) 'Fighters' cavalry which is trying to reach " - "the 'City Guard' backline, but have been prevented from doing by the 5 'City Guard' cavalry " - "in reserve (listed at the start of line 5). (ii) is 'Fighters' infantry, which is either in the battle " - "frontline, or attempting to flank to the 'City Guard' backline, and (iii) 'Fighters' " - "aerial cavalry which has been blocked by 'City Guard' reserves (there are none in " - "this battle). "; - f.Paragraph(temp); - temp = "Lines 4, 5 and 6 are the mirror image of lines 3, 2 and 1, with the " - "sides swopped. Thus, in this battle, 'City Guard' had little cavalry, and was unable to " - "prevent most of the 'Fighters' cavalry - and all of his aerial cavalry - from reaching the 'City Guard' backline and attacking his " - "ranged soldiers, of which 4 survive. 'City Guard' did manage to get 12 infantry past " - "the outnumbered frontline of 'Fighters', despite 'Fighters' having cavalry kept in reserve to " - "prevent such a move. However, that infantry is likely to die quickly, under attack from " - "20 cavalry and 5 ranged troops. 'Fighters' might try for the next battle to have more " - "troops in his frontline so that the 'City Guard' infantry is tied down unable to flank, " - "while 'City Guard' would need to bring more cavalry to defend his ranged troops, or " - "alternatively mix them in with his melee infantry, so that they may not be picked off " - "by 'Fighter's large number of cavalry."; - f.Paragraph(temp); - - f.LinkRef("com_victory"); - f.TagText("h3", "Victory!"); - temp = "Combat rounds continue until one side has accrued 50% losses " - "(or more). Illusions are not counted in this calculation."; - if(Globals->ARMY_ROUT != GameDefs::ARMY_ROUT_FIGURES) temp += " Soldiers " - "with multiple hit points are counted (hitpoints) times in this " - "calculation, and each time are counted as alive until the " - "soldier dies (loses his last hitpoint)."; - temp += " There is then one more round of attacks with the " - "losing side suffering " - "a -1 penalty to their chance-to-hit and attack skill. If both sides have " - "more than 50% losses, the battle is a draw, and there is no " - "extra round."; - f.Paragraph(temp); - if(!(SkillDefs[S_HEALING].flags & SkillType::DISABLED) && - !(ItemDefs[I_HERBS].flags & SkillType::DISABLED)) { - temp = "Units with the Healing skill have a chance of being able " - "to heal casualties of the winning side, so that they recover " - "rather than dying. Each character with this skill can attempt " - "to heal "; - temp += Globals->HEALS_PER_MAN; - temp += AString(" casualties per skill level. Each attempt however " - "requires one unit of Herbs, which is thereby used up. Each " - "attempt has a ") + HealDefs[1].rate + "% chance of healing one casualty; only one " - "attempt at Healing may be made per casualty. Healing occurs " - "automatically, after the battle is over, by any living " - "healers on the winning side."; - f.Paragraph(temp); - } - temp = "Any items owned by dead combatants on the losing side have a " - "50% chance of being found and collected by the winning side. " - "Each item which is recovered is picked up by one of the " - "survivors able to carry it (see the "; - temp += f.Link("#spoils", "SPOILS") + " command) at random, so the " - "winners generally collect loot in proportion to their number of " - "surviving men."; - f.Paragraph(temp); - temp = "If you are expecting to fight an enemy who is carrying so " - "much equipment that you would not be able to move after picking " - "it up, and you want to move to another region later that month, it " - "may be worth issuing some orders to drop items (with the "; - temp += f.Link("#give", "GIVE") + " 0 order) or to prevent yourself " - "picking up some spoils (with the "; - temp += f.Link("#spoils", "SPOILS") + " order) in case you win the " - "battle! Also, note that if the winning side took any losses in " - "the battle, any units on this side will not be allowed to move, " - "or attack again for the rest of the turn. Units on the losing " - "side do not suffer this penalty."; - f.Paragraph(temp); - if(has_stea || has_obse) { - f.LinkRef("stealthobs"); - f.ClassTagText("div", "rule", ""); - temp = (has_stea ? "Stealth" : ""); - if(has_obse) { - if(has_stea) temp += " and "; - temp += "Observation"; - } - f.TagText("h2", temp); - if(has_stea && has_obse) { - temp = "The Stealth skill is used to hide units, while the " - "Observation skill is used to see units that would otherwise " - "be hidden. A unit can be seen only if you have at least " - "one unit in the same region, with an Observation skill at " - "least as high as that unit's Stealth skill. If your " - "Observation skill is equal to the unit's Stealth skill, " - "you will see the unit, but not the name of the owning " - "faction. If your Observation skill is higher than the " - "unit's Stealth skill, you will also see the name of the " - "faction that owns the unit."; - } else if(has_stea) { - temp = "The Stealth skill is used to hide units. A unit can be " - "seen only if it doesn't know the Stealth skill and if you " - "have at least one unit in the same region."; - } else if(has_obse) { - temp = "The Observation skill is used to see information about " - "units that would otherwise be hidden. If your unit knows " - "the Observation skill, it will see the name of the faction " - "that owns any unit in the same region."; - } - f.Paragraph(temp); - if(has_stea) { - temp = "Regardless of Stealth skill, units are always visible " - "when participating in combat; when guarding a region with " - "the Guard flag; or when in a building or aboard a ship."; - if(has_obse) { - temp += " However, in order to see the faction that owns " - "the unit, you will still need a higher Observation " - "skill than the unit's Stealth skill."; - } - f.Paragraph(temp); - f.LinkRef("stealthobs_stealing"); - f.TagText("h3", "Stealing:"); - temp = AString("The ") + f.Link("#steal", "STEAL") + - " order is a way to steal items from other factions without " - "a battle. The order can only be issued by a one-man unit. " - "The order specifies a target unit; the thief will then " - "attempt to steal the specified item from the target unit."; - f.Paragraph(temp); - if(has_obse) { - temp = "If the thief has higher Stealth than any of the " - "target faction's units have Observation (i.e. the " - "thief cannot be seen by the target faction), the theft " - "will succeed."; - } else { - temp = "The thief must know Stealth to attempt theft."; - } - temp += " The target faction will be told what was stolen, but " - "not by whom. If the specified item is silver, then $200 " - "or half the total available, whichever is less, will be " - "stolen. If it is any other item, then only one will be " - "stolen (if available)."; - f.Paragraph(temp); - if(has_obse) { - temp = "Any unit with high enough Observation to see the " - "thief will see the attempt to steal, whether the " - "attempt is successful or not. Allies of the target " - "unit will prevent the theft, if they have high enough " - "Observation to see the unit trying to steal. Non-player-" - "factions, such as City Guards, may not be stolen from."; - f.Paragraph(temp); - } - f.LinkRef("stealthobs_assassination"); - f.TagText("h3", "Assassination:"); - temp = AString("The ") + f.Link("#assassinate", "ASSASSINATE") + - " order is a way to kill another person without attacking " - "and going through an entire battle. This order can only be " - "issued by a one-man unit, and specifies a target unit. If " - "the target unit contains more than one person, then one " - "will be singled out at random."; - f.Paragraph(temp); - if(has_obse) { - temp = "Success for assassination is determined as for " - "theft, i.e. the assassin will fail if any of the " - "target faction's units can see him. In this case, " - "the assassin will flee, and the target faction will " - "be informed which unit made the attempt. As with " - "theft, allies of the target unit will prevent the " - "assassination from succeeding, if their Observation " - "level is high enough."; - f.Paragraph(temp); - temp = "In addition, if the target is a mage, they have " - "a chance to detect the assassination attempt. " - "This chance depends on the mage's power; the more " - "powerful the mage, the more likely they are to escape."; - if(Globals->ARCADIA_MAGIC) f.Paragraph(temp); - temp = ""; - } else { - temp = "The assasin must know Stealth to attempt " - "assassination."; - } - if(has_obse) { - temp += "If the assassin has higher stealth than any of the " - "target faction's units have Observation, then a " - "one-on-one "; - } else { - temp += " A one-on-one "; - } - temp += "fight will take place between the assassin and the " - "target character. The battle is handled like a normal " - "fight, with the exception that the assassin cannot " - "use any armour, and the victim may only use leather armour."; //BS mod, Arcadia only - temp2 = ""; - last = -1; -/* comma = 0; - for(i = 0; i < NITEMS; i++) { - if(!(ItemDefs[i].type & IT_ARMOR)) continue; - if(!(ItemDefs[i].type & IT_NORMAL)) continue; - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - ArmorType *at = FindArmor(ItemDefs[i].abr); - if (at == NULL) continue; - if (!(at->flags & ArmorType::USEINASSASSINATE) && !(at->flags & ArmorType::DEFINASSASSINATE)) continue; - if(last == -1) { - last = i; - continue; - } - temp2 += ItemDefs[last].name; - temp2 += ", "; - last = i; - comma++; - } - if(comma) temp2 += "or "; - if(last != -1) { - temp2 += ItemDefs[last].name; - temp += " except "; - temp += temp2; - } - temp += ".";*/ - if(last == -1) - temp += " Armour "; - else - temp += " Most armour "; - temp += "is forbidden for the assassin because it would " - "make it too hard to sneak around, and for the victim " - "because he was caught by surprise with his armour off. If " - "the assassin wins, the target faction is told merely that " - "the victim was assassinated, but not by whom. If the " - "victim wins, then the target faction learns which unit " - "made the attempt. (Of course, this does not necessarily " - "mean that the assassin's faction is known.) The winner of " - "the fight gets 50% of the loser's property as usual."; - f.Paragraph(temp); - temp = f.Link("#steal", "STEAL") + " and " + - f.Link("#assassinate", "ASSASSINATE") + - " are not full month orders, and do not interfere with other " - "activities, but a unit can only issue one " + - f.Link("#steal", "STEAL") + " order or one " + - f.Link("#assassinate", "ASSASSINATE") + " order in a month."; - f.Paragraph(temp); - } - } - f.LinkRef("magic"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Heroes and Magic"); - if(Globals->ARCADIA_MAGIC) { - temp = "Heroes are created in Atlantis when a one-man leader unit " - "studies \"heroship\". Heros can study and experience normal skills one " - "level further than leaders, and two levels further than normal " - "units. However, heroes gain most of their power by virtue of their " - "ability to study hero skills, including magical abilities. Only " - "hero units may study these skills."; - temp = ""; - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - temp += "The number of heros that a faction may own is "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) - temp += "limited."; - else - temp += "determined by the faction's type."; - temp += " Any attempt to gain more, either through study, recruitment, or by " - "transfer from another faction, will fail. In addition, heroes "; - } else { - temp += "Heroes "; - } - temp += "may not "; - temp += f.Link("#give", "GIVE") + " men at all; once a unit is a " - "hero, the unit number is " - "fixed, and men may not be added or removed. (The hero may be given to another faction using the "; - temp += f.Link("#give", "GIVE") + " UNIT order.)"; - f.Paragraph(temp); - } else { - temp = "A character enters the world of magic in Atlantis by beginning " - "study on one of the Foundation magic skills. Only one man units"; - if(!Globals->MAGE_NONLEADERS && Globals->LEADERS_EXIST) - temp += ", with the man being a leader,"; - temp += " are permitted to study these skills. "; - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - temp += "The number of these units (known as \"magicians\" or " - "\"mages\") that a faction may own is "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_MAGE_COUNT) - temp += "limited."; - else - temp += "determined by the faction's type."; - temp += " Any attempt to gain more, either through study, or by " - "transfer from another faction, will fail. In addition, mages "; - } else { - temp += "Mages "; - } - temp += "may not "; - temp += f.Link("#give", "GIVE") + " men at all; once a unit becomes a " - "mage (by studying one of the Foundations), the unit number is " - "fixed. (The mage may be given to another faction using the "; - temp += f.Link("#give", "GIVE") + " UNIT order.)"; - f.Paragraph(temp); - } - f.LinkRef("magic_skills"); - f.TagText("h3", "Hero Skills:"); - temp = "Hero skills are treated the same as normal skills, with a few " - "differences. The basic hero skills, called foundations, are: "; - last = -1; - comma = 0; - j = 0; - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - if((SkillDefs[i].baseskill != i)) continue; - j++; - if(last == -1) { - last = i; - continue; - } - temp += SkillDefs[last].name; - temp += ", "; - comma++; - last = i; - } - if(comma) temp += "and "; - temp += SkillDefs[last].name; - temp += ". "; - if(Globals->ARCADIA_MAGIC) { - temp += "Each of these skills is at the base of a 'field' of hero spells. " - "As a unit studies the Foundations, he will be able " - "to study deeper into the arts of heroship; the additional skills that " - "he may study will be indicated on your turn report. Foundation skills " - "will not be included in this turn report list; they may be studied by any hero."; - f.Paragraph(temp); - temp = "There are two major differences between Hero skills and most " - "normal skills. The first is that the ability to study Hero skills " - "sometimes depends on lower level Hero skills. Studying higher in the Foundation " - "skills, and certain other skills, will make other skills " - "available to the hero. The second is that, unlike other units, " - "heroes may both study a skill AND perform a different month-long activity " - "every turn. This allows your heroes to move around, without " - "halting their study."; - f.Paragraph(temp); - } else { - temp += "To become a mage, a unit undertakes study in one of these " - "Foundations. As a unit studies the Foundations, he will be able " - "to study deeper into the magical arts; the additional skills that " - "he may study will be indicated on your turn report."; - f.Paragraph(temp); - temp = "There are two major differences between Magic skills and most " - "normal skills. The first is that the ability to study Magic skills " - "sometimes depends on lower level Magic skills. The Magic skills " - "that a mage may study are listed on his turn report, so he knows " - "which areas he may pursue. Studying higher in the Foundation " - "skills, and certain other Magic skills, will make other skills " - "available to the mage. Also, study into a magic skill above " - "level 2 requires that the mage be located in some sort of " - "building which can "; - if(!Globals->LIMITED_MAGES_PER_BUILDING) { - temp += "offer protection. Trade structures do not count. "; - } else { - temp += "offer specific protection to mages. Certain types of " - "buildings can offer shelter and support and a proper " - "environment, some more so than others. "; - } - temp += "If the mage is not in such a structure, his study rate is cut " - "in half, as he does not have the proper environment and " - "equipment for research."; - f.Paragraph(temp); - - if(Globals->LIMITED_MAGES_PER_BUILDING) { - temp = "It is possible that there are advanced buildings not listed " - "here which also can support mages. The description of a " - "building will tell you for certain. The common buildings and " - "the mages a building of that type can support follows:"; - f.LinkRef("tablemagebuildings"); - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("td", ""); - f.TagText("th", "Mages"); - f.Enclose(0, "tr"); - for(i = 0; i < NOBJECTS; i++) { - if(ObjectDefs[i].flags & ObjectType::DISABLED) continue; - if(!ObjectDefs[i].maxMages) continue; - pS = FindSkill(ObjectDefs[i].skill); - if(pS == NULL) continue; - if(pS->flags & SkillType::MAGIC) continue; - k = ObjectDefs[i].item; - if(k == -1) continue; - /* Need the >0 since item could be WOOD_OR_STONE (-2) */ - if(k > 0 && (ItemDefs[k].flags & ItemType::DISABLED)) continue; - if(k > 0 && !(ItemDefs[k].type & IT_NORMAL)) continue; - /* Okay, this is a valid object to build! */ - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ObjectDefs[i].maxMages); - f.Enclose(0, "td"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - } - } - - f.LinkRef("magic_foundations"); - f.TagText("h3", "Foundations:"); - temp = "The "; - temp += NumToWord(j); - temp += " foundation skills are called "; - last = -1; - comma = 0; - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - if((SkillDefs[i].baseskill != i)) continue; - if(last == -1) { - last = i; - continue; - } - temp += SkillDefs[last].name; - temp += ", "; - comma++; - last = i; - } - if(comma) temp += "and "; - temp += SkillDefs[last].name; - temp += "."; - f.Paragraph(temp); - - temp = "Windkey, Patterning, Mysticism, Summoning and Artifact Lore " - "are all magic skills, and allow the hero to study further magical " - "skills. Knowledge of the five magical foundations determines " - "the maximum energy and energy recharge rate of magical heroes " - "(known as mages). The mage's energy will be consumed when using " - "any magical skills."; - temp += " Battletraining and Charisma are different, in that they do " - "not add to a hero's magical energy, and the skills they lead " - "to do not consume magical energy. Battletraining and Charisma lead to " - "non-magical abilities which may aid a hero in combat or " - "trade."; - temp += " Heroes may study magical and non-magical skills interchangeably, " - "they are not limited to one or the other."; - f.Paragraph(temp); - - temp = "As with normal skills, different races specialise in different " - "hero skills. Most races will specialise in three foundations (listed in the "; - temp += f.Link("#tableraces", "Table of Races") + "); they " - "may study those foundations, and all skills related to those foundations, " - "to level three, and gain a further three levels from experience. In other " - "foundations, and the skills they lead to, a hero may only gain two " - "levels from each of knowledge and experience."; - f.Paragraph(temp); - - - /* XXX -- This needs better handling! */ - /* Add each foundation here if it exists */ -/* if(!(SkillDefs[S_FORCE].flags & SkillType::DISABLED)) { - temp += " Force indicates the quantity of magical energy that a " - "mage is able to channel (a Force rating of 0 does not mean " - "that the mage can channel no magical energy at all, but only " - "a minimal amount)."; - } - if(!(SkillDefs[S_PATTERN].flags & SkillType::DISABLED)) { - temp += " Pattern indicates ability to handle complex patterns, and " - "is important for things like healing and nature spells. "; - } - if(!(SkillDefs[S_SPIRIT].flags & SkillType::DISABLED)) { - temp += " Spirit deals with meta-effects that lie outside the scope " - "of the physical world."; - } - if(!(SkillDefs[S_BASE_WINDKEY].flags & SkillType::DISABLED)) { - temp += " Windkey is at the heart of control of the wind and weather. " - "Mages skilled in windkey are especially sought after by ship captains, " - "but many people may benefit from good winds and weather, while " - "storms and lightning may be powerful offensive weapons. "; - } - if(!(SkillDefs[S_BASE_ILLUSION].flags & SkillType::DISABLED)) { - temp += " Illusion indicates the ability to weave illusions in the " - "air, making people see that which does not exist, or in some " - "cases concealing that which does exist. It is not known why, " - "but mages with the innate ability to weave illusions are most " - "often found in the east. "; - } - if(!(SkillDefs[S_BASE_PATTERNING].flags & SkillType::DISABLED)) { - temp += " Patterning indicates the ability of a mage to harness the " - "energies of nature and the earth. Such abilities are usually used " - "to nourish lands, but may be used for destruction as well. " - "Mages with innate strength in patterning most commonly originate " - "in the north. "; - } - if(!(SkillDefs[S_BASE_SUMMONING].flags & SkillType::DISABLED)) { - temp += " Summoning deals with the ability of mages to reach in distant " - "places or different worlds, and pluck out creatures to pull them " - "here. Necromancy and the ability to communicate with the dead are " - "the most famous abilities study in summoning may bestow. Natural ability " - "in summoning is most common among the southern folk. "; - } - if(!(SkillDefs[S_BASE_MYSTICISM].flags & SkillType::DISABLED)) { - temp += " Mysticism is the least understood, and arguably the most powerful " - "of the magic fields. Study in mysticism allows a mage to harness " - "energies from outside his body, as well as from within. This allows " - "mages to cast spells more often, but is occasionally unpredictable. " - "Mysticism mages are most famous not for the great works of magic they " - "are capable of, but for the times when, just as it is most needed, " - "their magic fizzles or even turns on its wielder. "; - } - f.Paragraph(temp); - -*/ - - - if(app_exist) { - temp = "Apprentices may be created by having them study "; - comma = 0; - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - if(!(SkillDefs[i].flags & SkillType::APPRENTICE)) continue; - if(last == -1) { - last = i; - continue; - } - temp += SkillDefs[last].name; - temp += ", "; - comma++; - last = i; - } - if(comma) temp += "or "; - temp += SkillDefs[last].name; - temp += ". "; - temp += "Apprentices may not cast spells, but may utilize items " - "which otherwise only mages can use."; - f.Paragraph(temp); - } - - f.LinkRef("magic_furtherstudy"); - f.TagText("h3", "Further Hero Study:"); - if(Globals->ARCADIA_MAGIC) { - temp = "Once a hero has begun study of one or more Foundations, more " - "skills they may study will begin to show up in your report. " - "As with " - "normal skills, when a hero achieves a new level of a hero skill, " - "you will be given a skill report describing the powers that the new skill confers. The "; - temp += f.Link("#show", "SHOW") + " order may be used to show this " - "information on future reports."; - f.Paragraph(temp); - temp = "A hero can also gain skill levels through experience; " - "this may be gained in a number of ways. Most commonly, when spells are "; - temp += f.Link("#cast", "CAST") + " or used in combat, a hero will " - "gain experience in that spell. This experience will be halved if " - "the hero's race does not specialise in the skill. Using skills in " - "other ways, including automatic skills that are \"always on\", will " - "also increase a hero's experience in that skill."; - f.Paragraph(temp); - } else { - temp = "Once a mage has begun study of one or more Foundations, more " - "skills that he may study will begin to show up on his report. " - "These skills are the skills that give a mage his power. As with " - "normal skills, when a mage achieves a new level of a magic skill, " - "he will be given a skill report, describing the new powers (if " - "any) that the new skill confers. The "; - temp += f.Link("#show", "SHOW") + " order may be used to show this " - "information on future reports."; - f.Paragraph(temp); - } - f.LinkRef("magic_usingmagic"); - f.TagText("h3", "Using Hero Skills:"); - if(Globals->ARCADIA_MAGIC) { - temp = "A hero may use his skills in four different ways, " - "depending on the type of skill or spell he wants to use. Some spells, " - "once learned, take effect automatically and are considered " - "always to be in use; these spells do not require any order to " - "take effect."; - f.Paragraph(temp); - temp = "Secondly, some spells are for use in combat. A hero may specify " - "that he wishes to use a spell in combat by issuing the "; - temp += f.Link("#combat", "COMBAT") + " order. A combat skill " - "specified in this way will only be used if the hero finds " - "himself taking part in a battle."; - f.Paragraph(temp); - temp = "The third type of spell use is for spells or skills that take an entire " - "month to cast or use. These spells are cast by the hero issuing the "; - temp += f.Link("#cast", "CAST") + " order (even if the skill is non-magical in nature). A hero may issue " - "multiple CAST orders each month, providing " - "that each cast order is for a different skill, and that no more than " - "one spell moves the hero (through teleportation or gate " - "jumping)."; - f.Paragraph(temp); - temp = "Finally, some skills may affect the way other orders work, usually " - "in a way beneficial to the hero. These skills will be used automatically " - "whenever other orders are used by the hero."; - f.Paragraph(temp); - temp = "Every magical spell that is cast, or used in combat, will drain the mage of " - "energy. How much energy is needed for a spell will be specified in the " - "skill description that a mage recieved when he first learns a new " - "spell, and may depend on the skill level of the mage. Skills " - "in the Charisma and Battletraining skilltrees are considered non-magical, " - "and never require energy to use."; - f.Paragraph(temp); - } else { - temp = "A mage may use his magical power in three different ways, " - "depending on the type of spell he wants to use. Some spells, " - "once learned, take effect automatically and are considered " - "always to be in use; these spells do not require any order to " - "take effect."; - f.Paragraph(temp); - temp = "Secondly, some spells are for use in combat. A mage may specify " - "that he wishes to use a spell in combat by issuing the "; - temp += f.Link("#combat", "COMBAT") + " order. A combat spell " - "specified in this way will only be used if the mage finds " - "himself taking part in a battle."; - f.Paragraph(temp); - temp = "The third type of spell use is for spells that take an entire " - "month to cast. These spells are cast by the mage issuing the "; - temp += f.Link("#cast", "CAST") + " order. Because " + - f.Link("#cast", "CAST") + " takes an entire month, a mage may use " - "only one of this type of spell each turn. Note, however, that a "; - temp += f.Link("#cast", "CAST") + " order is not a full month order; " - "a mage may still "; - temp += f.Link("#move", "MOVE") + ", "; - temp += f.Link("#study", "STUDY") + ", or use any other month long order. "; - temp += "The justification for this (as well as being for game balance) " - "is that a spell drains a mage of his magic power for the month, " - "but does not actually take the entire month to cast."; - f.Paragraph(temp); - temp = "The description that a mage receives when he first learns a " - "spell specifies the manner in which the spell is used (automatic, " - "in combat, or by casting)."; - f.Paragraph(temp); - } - if(Globals->ARCADIA_MAGIC) { - f.LinkRef("magic_energy"); - f.TagText("h3", "Magical Energy:"); - temp = "Every mage has a limited supply of energy, which is partially regenerated every turn. " - "This energy supply depends on the mage's level in the fundamental magic skills; other magic " - "skills allow a mage to cast new spells, but do not increase the mage's energy supply. " - "For each fundamental magic skill that a mage is skilled in, his maximum energy storage " - "will be increased by his level in that skill, squared, while the rate at which he regains " - "energy will be increased by his skill level. If the mage's race is specialised in that fundamental, " - "then his increased affinity to that field of magic doubles the contribution of that skill. " - "For this reason, if you plan for a hero to specialise in magic, it is advisable to make " - "a hero from a race which specialises in multiple magic foundations, even if you only " - "plan to study castable spells in one of those foundation skilltrees."; - f.Paragraph(temp); - temp = "If a mage runs out of energy, then he will be unable to "; - temp += f.Link("#cast", "CAST") + " any more magic spells. The exception is in combat, when a mage will be driven " - "to cast spells even if he has no energy; however these spells will be cast at only " - "half their usual skill level, rounded down (if a mage has his combat spell only at " - "level 1, then without energy he will not cast at all). Some magical skills also create " - "items which cause an ongoing energy drain for the mage to sustain them. These costs reduce " - "a mage's rate of energy recharge, and if the mage cannot regenerate enough energy to " - "sustain them, the items will be lost."; - f.Paragraph(temp); - } - f.LinkRef("magic_incombat"); - f.TagText("h3", "Heroes in Combat:"); - temp = "NOTE: This section is rather vague, and quite advanced. You " - "may want to wait until you have figured out other parts of " - "Atlantis before trying to understand exactly all of the rules in " - "this section."; - f.Paragraph(temp); - temp = "Although the hero skills and magic spells are unspecified in these " - "rules, left for the players to discover, the rules for combat " - "spells' interaction are spelled out here. There are five major " - "types of attacks and defenses: Combat, Ranged, Energy, Weather, " - "and Spirit. Every attack and defense has a type, and only the " - "appropriate defense is effective against an attack."; - f.Paragraph(temp); - temp = "Defensive spells are cast at the beginning of each round of " - "combat, and will have a type of attack they deflect, and skill " - "level (Defensive spells are generally called Shields). Every " - "time an attack is launched against an army, it must first attack " - "the highest level Shield of the same type as the attack, before " - "it may attack a soldier directly. Note that an attack only has " - "to attack the highest Shield, any other Shields of the same " - "type are ignored for that attack."; - f.Paragraph(temp); - temp = "An attack skill or spell (and any other type of attack) also has an " - "attack type, and attack level, and a number of blows it deals. " - "When the attack spell is cast, it is matched up against the most " - "powerful defensive spell of the appropriate type that the other " - "army has cast. If the other army has not cast any applicable " - "defensive spells, the attack goes through unmolested. For " - "every blow the spell attempts to deal, there is usually a " - "50% chance of getting the opportunity for a lethal hit, " - "although as with other attacks, this chance may be modified " - "by position, terrain, fortifications or other spells. As with " - "normal combat, men which are in the open (not protected by " - "a building) have an effective skill against magic attacks of 0, unless they have a " - "shield or some other defensive magic. Some monsters " - "have bonuses to resisting some attacks but are more susceptible " - "to others. The skill level of the attack spell and the effective " - "skill for defence are matched against each other. The formula " - "for determining the victor between a defensive shield and offensive " - "spell is the same as for a contest of soldiers, except that " - "defensive shields get a +1 skill level bonus when defending against " - "magic spells, so the attack spell must be one skill level higher " - "for the effective levels to be equal. If the effective levels " - "are equal, there is a 1:1 chance of success, and so on. If the " - "offensive spell is victorious, it deals its blows " - "to the defending army, and the Shield in question loses one level in power " - "(thus, a level 2 shield (having an initial strength of 3) will be destroyed after three spells have " - "passed through " - "it). Otherwise, the attack spell disperses, and " - "the defending spell remains in place."; - f.Paragraph(temp); - temp = "Some skills and spells do not actually kill enemies, but rather have some " - "negative effect on them. These spells are treated the same as " - "normal spells; if there is a Shield of the same type as them, " - "they must attack the Shield before attacking the army. However, " - "these spells will not cause a shield to be weakened. " - "Physical attacks that go through a defensive spell also must " - "match their skill level against that of the defensive spell in " - "question. However, if they pass through the shield, they only " - "have a 1% chance of weakening the shield. Note that this check " - "is done before the check for chance-to-attack for the bowmen, " - "so this is effectively a 2% chance per actual attack."; - f.Paragraph(temp); - temp = "There are a few hero spells which provide a beneficial effect for the " - "hero's army. These spells cannot be blocked by enemy shields."; - f.Paragraph(temp); - f.LinkRef("magic_miscellaneous"); - f.TagText("h3", "Miscellaneous Hero Rules:"); - temp = "Because of the status given to heroes, and their respect for their " - "counterparts, no hero may assassinate another hero. However, heroes " - "have no qualms about assassinating non-heroes, and vice versa."; - f.Paragraph(temp); - - - if(Globals->EARTHSEA_VICTORY) { - f.LinkRef("magic_mastery"); - f.TagText("h3", "Magic Mastery:"); - temp = "Before the destruction of Bashkeil, the school at Alanum " - "was the primary location for all teaching of magic. It was " - "here that the six Masters were appointed; one to head each school " - "of magic. The role of a Master is more than a title; when a " - "candidate was appointed, they would spend a month in meditation " - "of the path they should take. It is said that if one who was " - "unworthy was appointed, he would never wake to take the mantle " - "of master."; - temp = " The role of a Master is not a light one. They must always make " - "themselves available to students of the arts, and to help those " - "non-magicians who need their aid. As such, they may never walk in " - "secret, and may not travel further than 15 regions from Alanum for " - "an extended period - a distance which would take them beyond " - "the major islands of the world. Likewise, there is a limit to how " - "long a Master may spend at sea or underground before he loses " - "the mantle of a Master. The benefits are small; a Master will gain " - "a one-tenth bonus to the rate at which his energy recharges. But " - "there are some abilities which only Masters may hold, and only " - "those mages who are known as Masters will be able to face, and fix, " - "the problems around Bashkeil."; - f.Paragraph(temp); - temp = " There have been occasions, during times of conflict " - "or confusion, when two mages been appointed Master " - "and stood in challenge for the title. In our times of trouble, " - "with six Masters dead and none left to appoint new Masters " - "it is inevitable that mages may claim the title unto themselves. " - "However, the magic of the world itself prevents more than two " - "mages from assuming the role of Master; more may try, but are " - "bound to fail. In such a circumstance, only if a Master " - "relinquishes his title, or is killed, may another mage take " - "his place."; - f.Paragraph(temp); - temp = " For each of the fields of magic, the requirements for a mage " - "to be able to become a Master are different. Generally, a mage " - "must know a particular spell to level 5. Knowledge of which spell is necessary may be " - "provided to you with the skilltree mages may study, or may perhaps be found " - "only within the game world. To begin the meditation required to " - "assume the title of Master, a mage should issue a "; - temp += f.Link("#master", "MASTER") + " order."; - f.Paragraph(temp); - } - f.LinkRef("nonplayers"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Non-Player Units"); - temp = "There are a number of units that are not controlled by players " - "that may be encountered in Atlantis. Most information about " - "these units must be discovered in the course of the game, but a " - "few basics are below."; - f.Paragraph(temp); - if(Globals->TOWNS_EXIST && Globals->CITY_MONSTERS_EXIST) { - f.LinkRef("nonplayers_guards"); - f.TagText("h3", "City and Town Guardsmen:"); - temp = "All cities and towns begin with guardsmen in them. These " - "units will defend any units that are attacked in the city or " - "town, and will also prevent theft and assassination attempts, "; - if(has_obse) - temp += "if their Observation level is high enough. "; - else - temp += "if they can see the criminal. "; - temp += "They are on guard, and will prevent other units from " - "taxing or pillaging. "; - if(Globals->SAFE_START_CITIES) - temp += "Except in the starting cities, the "; - else - temp += "The "; - temp += "guards may be killed by players, although they will form " - "again if the city is left unguarded."; - f.Paragraph(temp); - if(Globals->SAFE_START_CITIES || Globals->START_CITY_GUARDS_PLATE || - Globals->START_CITY_MAGES) { - if(Globals->AMT_START_CITY_GUARDS) { - temp = "Note that the city guardsmen in the starting cities " - "of Atlantis possess "; - if(Globals->SAFE_START_CITIES) - temp += "Amulets of Invincibility "; - if(Globals->START_CITY_GUARDS_PLATE) { - if(Globals->SAFE_START_CITIES) temp += "and "; - temp += "plate armour "; - } - temp += "in addition to being more numerous and "; - if(Globals->SAFE_START_CITIES) - temp += "may not be defeated."; - else - temp += "are therefore harder to kill."; - } - - if(Globals->START_CITY_MAGES) { - if(Globals->AMT_START_CITY_GUARDS) - temp += " Additionally, in "; - else - temp += "In "; - temp += "the starting cities, Mage Guards will be found. " - "These mages are adept at the fire spell"; - if(!Globals->SAFE_START_CITIES) { - temp += " making any attempt to control a starting " - "city a much harder proposition"; - } - temp += "."; - } - f.Paragraph(temp); - } - } - if (Globals->WANDERING_MONSTERS_EXIST) { - f.LinkRef("nonplayers_monsters"); - f.TagText("h3", "Wandering Monsters:"); - temp = "There are a number of monsters who wander free throughout " - "Atlantis. They will occasionally attack player units, so be " - "careful when wandering through the wilderness."; - f.Paragraph(temp); - } - f.LinkRef("nonplayers_controlled"); - f.TagText("h3", "Controlled Monsters:"); - temp = "Through various magical methods, you may gain control of " - "certain types of monsters. These monsters are just another item " - "in a unit's inventory, with a few special rules. Monsters will " - "be able to carry things at their speed of movement; use the "; - temp += f.Link("#show", "SHOW") + " ITEM order to determine the " - "carrying capacity and movement speed of a monster. Monsters will " - "also fight for the controlling unit in combat; their strength " - "can only be determined in battle. Also, note that a monster will " - "always fight from the front rank, even if the controlling unit " - "has the behind flag set. Whether or not you are allowed to give a " - "monster to other units depends on the type of monster; some may be " - "given freely, while others must remain with the controlling unit."; - if(Globals->RELEASE_MONSTERS) { - temp += " All monsters may be released completely by using the "; - temp += f.Link("#give", "GIVE") + " order targetting unit 0. When " - "this is done, the monster will become a wandering monster."; - } - f.Paragraph(temp); - f.LinkRef("orders"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Orders"); - temp = "To enter orders for Atlantis, you should send a mail message " - "to the Atlantis server, containing the following:"; - f.Paragraph(temp); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.ClearWrapTab(); - f.WrapStr("#ATLANTIS faction-no "); - f.PutNoFormat(""); - f.WrapStr("UNIT unit-no"); - f.WrapStr("...orders..."); - f.PutNoFormat(""); - f.WrapStr("UNIT unit-no"); - f.WrapStr("...orders..."); - f.PutNoFormat(""); - f.WrapStr("#END"); - f.Enclose(0, "pre"); - temp = "For example, if your faction number (shown at the top of your " - "report) is 27, your password if \"foobar\", and you have two " - "units numbered 5 and 17:"; - f.Paragraph(temp); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.WrapStr("#ATLANTIS 27 \"foobar\""); - f.PutNoFormat(""); - f.WrapStr("UNIT 5"); - f.WrapStr("...orders..."); - f.PutNoFormat(""); - f.WrapStr("UNIT 17"); - f.WrapStr("...orders..."); - f.PutNoFormat(""); - f.WrapStr("#END"); - f.Enclose(0, "pre"); - temp = "Thus, orders for each unit are given separately, and indicated " - "with the UNIT keyword. (In the case of an order, such as the " - "command to rename your faction, that is not really for any " - "particular unit, it does not matter which unit issues the command; " - "but some particular unit must still issue it.) The exceptions to this " - "are the ALL and TEMPLATE orders, which de-activate the current selected " - "unit, and store orders until referred to later by a labelled unit, or " - "TYPE commands."; - f.Paragraph(temp); - temp = "IMPORTANT: You MUST use the correct #ATLANTIS line or else your " - "orders will be ignored."; - f.Paragraph(temp); - temp = "If you have a password set, you must specify it on you " - "#atlantis line, or the game will reject your orders. See the "; - temp += f.Link("#password", "PASSWORD") + " order for more details."; - f.Paragraph(temp); - temp = "Each type of order is designated by giving a keyword as the " - "first non-blank item on a line. Parameters are given after this, " - "separated by spaces or tabs. Blank lines are permitted, as are " - "comments; anything after a semicolon is treated as a comment " - "(provided the semicolon is not in the middle of a word)."; - f.Paragraph(temp); - temp = "The parser is not case sensitive, so all commands may be given " - "in upper case, lower case or a mixture of the two. However, when " - "supplying names containing spaces, the name must be surrounded " - "by double quotes, or else underscore characters must be used in " - "place of spaces in the name. (These things apply to the #ATLANTIS " - "and #END lines as well as to order lines.)"; - f.Paragraph(temp); - temp = "You may precede orders with the at sign (@), in which case they " - "will appear in the Template at the bottom of your report. This is " - "useful for orders which your units repeat for several months in a " - "row. For example, to tax every turn:"; - f.Paragraph(temp); - temp = "@TAX"; - f.Paragraph(temp); - temp = "You may suppress errors generated by most (but not all) orders " - "with an exclamation mark (!), in which case, providing the order " - "is a valid order, errors will not be shown in your next report " - "if the order is unable to be carried out (for example because the " - "target unit was not present). This is " - "useful for orders which can only take place sometimes, and you " - "do not wish to receive errors when they are not successful. For example, " - "to not receive an error if a repeating GIVE order fails:"; - f.Paragraph(temp); - temp = "@!GIVE 200 ALL WOOD"; - f.Paragraph(temp); - - f.LinkRef("orders_abbreviations"); - f.TagText("h3", "Abbreviations:"); - temp = "All common items and skills have abbreviations that can be used " - "when giving orders, for brevity. Any time you see the item on your " - "report, it will be followed by the abbreviation. Please be careful " - "using these, as they can easily be confused."; - f.Paragraph(temp); - f.LinkRef("ordersummary"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Order Summary"); - temp = "To specify a [unit], use the unit number. If specifying a " - "unit that will be created this turn, use the form \"NEW #\" if " - "the unit belongs to your faction, or \"FACTION # NEW #\" if the " - "unit belongs to a different faction. See the "; - temp += f.Link("#form", "FORM"); - temp += " order for a more complete description. [faction] means that " - "a faction number is required; [object] means that an object " - "number (generally the number of a building or ship) is required. " - "[item] means an item (like wood or longbow) that a unit can have " - "in its possession. [flag] is an argument taken by several orders, " - "that sets or unsets a flag for a unit. A [flag] value must be " - "either 1 (set the flag) or 0 (unset the flag). Other parameters " - "are generally numbers or names."; - f.Paragraph(temp); - temp = "IMPORTANT: Remember that names containing spaces (e.g., " - "\"Plate Armour\"), must be surrounded by double quotes, or the " - "spaces must be replaced with underscores \"_\" (e.g., Plate_Armour)."; - f.Paragraph(temp); - temp = "Also remember that anything used in an example is just that, " - "an example and makes no gaurentee that such an item, structure, " - "or skill actually exists within the game."; - f.Paragraph(temp); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("address"); - f.TagText("h4", "ADDRESS [new address]"); - f.Paragraph("Change the email address to which your reports are sent."); - f.Paragraph("Example:"); - temp = "Change your faction's email address to atlantis@rahul.net."; - temp2 = "ADDRESS atlantis@rahul.net"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("advance"); - f.TagText("h4", "ADVANCE [dir] ..."); - temp = "This is the same as the "; - temp += f.Link("#move", "MOVE"); - temp += " order, except that it implies attacks on units which attempt " - "to forbid access. See the "; - temp += f.Link("#move", "MOVE") + " order for details."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Move north, then northwest, attacking any units that forbid " - "access to the regions."; - temp2 = "ADVANCE N NW"; - f.CommandExample(temp, temp2); - temp = "In order, move north, then enter structure number 1, move " - "through an inner route, and finally move southeast. Will attack " - "any units that forbid access to any of these locations."; - temp2 = "ADVANCE N 1 IN SE"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("all"); - f.TagText("h4", "ALL [label]"); - temp = AString("This order enables you to issue a set of orders to all " - "units that have been ") + f.Link("#label", "labelled") + " with " - "the specified label. All lines following the ALL order will be stored, until " - "the next line beginning with ALL, TEMPLATE or UNIT. Due to parsing issues, " - + f.Link("#type", "TYPE") + " and " + f.Link("#form", "FORM") + - " orders should not be included following an ALL order. Note " - "that orders given via an ALL command will only affect units listed " - "later in your orders; hence ALL commands should usually be issued " - "at the beginning of your orders. Also, while LABEL commands " - "may be included in an ALL order, they will not take effect until " - "the next turn."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - f.Paragraph("Issue orders for all units labelled 'North Army Archers'"); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.PutNoFormat("ALL \"North Army Archers\""); - f.PutNoFormat("behind 1"); - f.PutNoFormat("MOVE NE N"); - f.PutNoFormat("GIVE 99 ALL HORS"); - f.Enclose(0, "pre"); - - if(Globals->USE_WEAPON_ARMOR_COMMAND) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("armour"); - f.TagText("h4", "ARMOUR [item1] [item2] [item3] [item4]"); - f.TagText("h4", "ARMOUR"); - temp = "This command allows you to set a list of preferred armour " - "for a unit. After searching for armour on the preferred " - "list, the standard armour precedence takes effect if an armour " - "hasn't been set. The second form clears the preferred armour " - "list."; - f.Paragraph(temp); - f.Paragraph("Examples"); - temp = "Set the unit to select chain armour before plate armour."; - temp2 = "ARMOUR CARM PARM"; - f.CommandExample(temp, temp2); - temp = "Clear the preferred armor list."; - temp2 = "ARMOUR"; - f.CommandExample(temp, temp2); - } - - if(has_stea) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("assassinate"); - f.TagText("h4", "ASSASSINATE [unit]"); - temp = "Attempt to assassinate the specified unit, or one of the " - "unit's people if the unit contains more than one person. The " - "order may only be issued by a one-man unit."; - f.Paragraph(temp); - temp = "A unit may only attempt to assassinate a unit which is able " - "to be seen."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Assassinate unit number 177."; - temp2 = "ASSASSINATE 177"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("attack"); - f.TagText("h4", "ATTACK [unit] ... "); - temp = "Attack a target unit. If multiple ATTACK orders are given, " - "all of the targets will be attacked."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "To attack units 17, 431, and 985:"; - temp2 = "ATTACK 17\nATTACK 431 985"; - f.CommandExample(temp, temp2); - temp = "or:"; - temp2 = "ATTACK 17 431 985"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("autotax"); - f.TagText("h4", "AUTOTAX [flag]"); - temp = "AUTOTAX 1 causes the unit to attempt to tax every turn " - "(without requiring the TAX order) until the flag is unset. " - "AUTOTAX 0 unsets the flag."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "To cause the unit to attempt to tax every turn."; - temp2 = "AUTOTAX 1"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("avoid"); - f.TagText("h4", "AVOID [flag]"); - temp = "AVOID 1 instructs the unit to avoid combat wherever possible. " - "The unit will not enter combat unless it issues an ATTACK order, " - "or the unit's faction is attacked in the unit's hex. AVOID 0 " - "cancels this."; - f.Paragraph(temp); - temp = "The Guard and Avoid Combat flags are mutually exclusive; " - "setting one automatically cancels the other."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set the unit to avoid combat when possible."; - temp2 = "AVOID 1"; - f.CommandExample(temp, temp2); - - if(Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) { - f.ClassTagText("DIV", "rule", ""); - f.LinkRef("bank"); - f.TagText("H4", "BANK DEPOSIT amount"); - f.TagText("H4", "BANK WITHDRAW amount"); - temp = "The BANK order is used to deposit or withdraw silver from the bank."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Deposit 2500 silver in the bank."; - temp2 = "BANK DEPOSIT 2500"; - f.CommandExample(temp, temp2); - } - f.ClassTagText("div", "rule", ""); - f.LinkRef("behind"); - f.TagText("h4", "BEHIND [flag]"); - temp = "BEHIND 1 sets the unit to be behind other units in combat. " - "BEHIND 0 cancels this."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set the unit to be in front in combat."; - temp2 = "BEHIND 0"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("build"); - f.TagText("h4", "BUILD"); - f.TagText("h4", "BUILD [object type]"); - f.TagText("h4", "BUILD [object type] [direction]"); - f.TagText("h4", "BUILD HELP [unit]"); - if(Globals->HEXSIDE_TERRAIN) { - temp = "BUILD given with no parameters causes the unit to perform work " - "on the object that it is currently inside. BUILD given with an " - "[object type] (such as \"Tower\" or \"Galleon\") instructs the unit " - "to begin work on a new object of the type given. If this object is " - "a seagoing vessel (anything that cannot be present in the centre of " - "a land hex) then the third form must be used, specifying which edge " - "of the region the object is to be built in. The final form " - "instructs the unit to enter the same building as [unit] and to " - "assist in building that structure, even if it is a structure which " - "was begun that same turn. This help will be rejected if the unit " - "you are helping does not consider you to be friendly. Building of " - "features which only exist on the edge of regions (such as bridges " - "and roads) should always use the third form. For these objects, " - "the third form may be used by multiple units, and all will perform " - "work on the same feature."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "To build a new tower."; - temp2 = "BUILD Tower"; - f.CommandExample(temp, temp2); - temp = "To continue building a partially built road to the north-east."; - temp2 = "BUILD Road NE"; - f.CommandExample(temp, temp2); - temp = "To help unit 5789 build a structure."; - temp2 = "BUILD HELP 5789"; - f.CommandExample(temp, temp2); - } else { - temp = "BUILD given with no parameters causes the unit to perform work " - "on the object that it is currently inside. BUILD given with an " - "[object type] (such as \"Tower\" or \"Galleon\") instructs the unit " - "to begin work on a new object of the type given. The final form " - "instructs the unit to enter the same building as [unit] and to " - "assist in building that structure, even if it is a structure which " - "was begun that same turn. This help will be rejected if the unit " - "you are helping does not consider you to be friendly."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "To build a new tower."; - temp2 = "BUILD Tower"; - f.CommandExample(temp, temp2); - temp = "To help unit 5789 build a structure."; - temp2 = "BUILD HELP 5789"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("buy"); - f.TagText("h4", "BUY [quantity] [item]"); - f.TagText("h4", "BUY ALL [item]"); - temp = "Attempt to buy a number of the given item from a city or town " - "marketplace, or to buy new people in any region where people are " - "available for recruiting. If the unit can't afford as many as " - "[quantity], it will attempt to buy as many as it can. If the " - "demand for the item (from all units in the region) is greater " - "than the number available, the available items will be split " - "among the buyers in proportion to the amount each buyer attempted " - "to buy. "; - if (Globals->RACES_EXIST) { - temp += "When buying people, specify the race of the people as the " - "[item], or use the generic term \"PEASANTS\". "; - } - temp += "If the second form is specified, the unit will attempt to buy " - "as many as it can afford."; - f.Paragraph(temp); - f.Paragraph(AString("Example") + (Globals->RACES_EXIST?"s":"") + ":"); - temp = "Buy one plate armour from the city market."; - temp2 = "BUY 1 \"Plate Armour\""; - f.CommandExample(temp, temp2); - if (Globals->RACES_EXIST) { - temp = "Recruit 5 barbarians into the current unit. (This will " - "dilute the skills that the unit has.)"; - temp2 = "BUY 5 barbarians"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("cast"); - f.TagText("h4", "CAST [skill] [arguments]"); - temp = "Cast the given spell. Note that most spell names contain " - "spaces; be sure to enclose the name in quotes! [arguments] " - "depends on which spell you are casting; when you are able to cast " - "a spell, the skill description will tell you the syntax."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Cast the spell called \"Super Spell\"."; - temp2 = "CAST \"Super Spell\""; - f.CommandExample(temp, temp2); - temp = "Cast the fourth-level spell in the \"Super Magic\" skill."; - temp2 = "CAST Super_Magic 4"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("claim"); - f.TagText("h4", "CLAIM [amount]"); - temp = "Claim an amount of the faction's unclaimed silver, and give it " - "to the unit issuing the order. The claiming unit may then spend " - "the silver or give it to another unit."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Claim 100 silver."; - temp2 = "CLAIM 100"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("combat"); - f.TagText("h4", "COMBAT [spell]"); - f.TagText("h4", "COMBAT"); - temp = "Set the given spell as the spell that the unit will cast in " - "combat. This order may only be given if the unit can cast the " - "spell in question. The second form of the order may be used " - "to clear the mage's combat spell, if you do not wish him to " - "cast a spell in combat."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Instruct the unit to use the spell \"Super Spell\", when the " - "unit is involved in a battle."; - temp2 = "COMBAT \"Super Spell\""; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("command"); - f.TagText("h4", "COMMAND"); - temp = "Order the unit to take command of your faction, changing your " - "faction's affiliation if the new commander is from a different " - "ethnic group."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Instruct the unit to take command of your faction."; - temp2 = "COMMAND"; - f.CommandExample(temp, temp2); - - if (Globals->FOOD_ITEMS_EXIST) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("consume"); - f.TagText("h4", "CONSUME UNIT"); - f.TagText("h4", "CONSUME FACTION"); - f.TagText("h4", "CONSUME"); - temp = "The CONSUME order instructs the unit to use food items in " - "preference to silver for maintenance costs. CONSUME UNIT tells " - "the unit to use food items that are in that unit's possession " - "before using silver. CONSUME FACTION tells the unit to use any " - "food items that the faction owns (in the same region as the " - "unit) before using silver. CONSUME tells the unit to use " - "silver before food items (this is the default)."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Tell a unit to use food items in the unit's possession for " - "maintenance costs."; - temp2 = "CONSUME UNIT"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("declare"); - f.TagText("h4", "DECLARE [faction] [attitude]"); - f.TagText("h4", "DECLARE [faction]"); - f.TagText("h4", "DECLARE DEFAULT [attitude]"); - temp = "The first form of the DECLARE order sets the attitude of your " - "faction towards the given faction. The second form cancels any " - "attitude towards the given faction (so your faction's attitude " - "towards that faction will be its default attitude). The third " - "form sets your faction's default attitude."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Declare your faction to be hostile to faction 15."; - temp2 = "DECLARE 15 hostile"; - f.CommandExample(temp, temp2); - temp = "Set your faction's attitude to faction 15 to its default " - "attitude."; - temp2 = "DECLARE 15"; - f.CommandExample(temp, temp2); - temp = "Set your faction's default attitude to friendly."; - temp2 = "DECLARE DEFAULT friendly"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("describe"); - f.TagText("h4", "DESCRIBE UNIT [new description]"); - f.TagText("h4", "DESCRIBE SHIP [new description]"); - f.TagText("h4", "DESCRIBE BUILDING [new description]"); - f.TagText("h4", "DESCRIBE OBJECT [new description]"); - f.TagText("h4", "DESCRIBE STRUCTURE [new description]"); - temp = "Change the description of the unit, or of the object the unit " - "is in (of which the unit must be the owner). Descriptions can be " - "of any length, up to the line length your mailer can handle. If " - "no description is given, the description will be cleared out. The " - "last four are completely identical and serve to modify the " - "description of the object you are currently in."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set the unit,s description to read \"Merlin's helper\"."; - temp2 = "DESCRIBE UNIT \"Merlin's helper\""; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("destroy"); - f.TagText("h4", "DESTROY"); - temp = "Destroy the object you are in (of which you must be the owner). " - "The order cannot be used at sea."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Destroy the current object"; - temp2 = "DESTROY"; - f.CommandExample(temp, temp2); - - - f.ClassTagText("div", "rule", ""); - f.LinkRef("disable"); - f.TagText("h4", "DISABLE [skill] [flag]"); - f.TagText("h4", "DISABLE [skill]"); - temp = "Disable the unit from using the specified skill. This order " - "may be useful to turn off magic spells that operate automatically, " - "in order to conserve energy. However, the order will work for " - "non-magical skills as well. For all purposes except "; - temp += f.Link("#study", "STUDY") + " orders, the unit " - "will effectively not possess the skill until it is " - "re-enabled. The first form of this order may be used " - "to turn skills on or off, the second form may only " - "be used to turn them off."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Disable the unit's necromancy skill."; - temp2 = "DISABLE necromancy on"; - f.CommandExample(temp, temp2); - temp = "Disable the unit's riding skill."; - temp2 = "DISABLE riding"; - f.CommandExample(temp, temp2); - temp = "Re-enable the unit's riding skill."; - temp2 = "DISABLE riding off"; - f.CommandExample(temp, temp2); - - if (qm_exist) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("distribute"); - f.TagText("h4", "DISTRIBUTE [unit] [num] [item]"); - f.TagText("h4", "DISTRIBUTE [unit] ALL [item]"); - f.TagText("h4", "DISTRIBUTE [unit] ALL [item] EXCEPT [amount]"); - temp = "Distribute the specified items to the given friendly unit. " - "In the second form, all of that item, are distributed. In the " - "last form, all of that item except for the specified amount " - "are distributed."; - temp += " The unit issuing the distribute order must have the " - "quartermaster skill, and be the owner of a transport " - "structure. Use of this order counts as trade activity in " - "the hex."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Distribute 10 STON to unit 1234"; - temp2 = "DISTRIBUTE 1234 10 STON"; - f.CommandExample(temp, temp2); - temp = "Distribute all except 10 SWOR to unit 3432"; - temp2 = "DISTRIBUTE 3432 ALL SWOR EXCEPT 10"; - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("enter"); - f.TagText("h4", "ENTER [object]"); - temp = "Attempt to enter the specified object. If issued from inside " - "another object, the unit will first leave the object it is " - "currently in. The order will only work if the target object is " - "unoccupied, or is owned by a unit in your faction, or is owned by " - "a unit which has declared you Friendly."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Enter ship number 114."; - temp2 = "ENTER 114"; - f.CommandExample(temp, temp2); - - if (!(SkillDefs[S_ENTERTAINMENT].flags & SkillType::DISABLED)) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("entertain"); - f.TagText("h4", "ENTERTAIN"); - temp = "Spend the month entertaining the populace to earn money."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Entertain for money."; - temp2 = "ENTERTAIN"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("evict"); - f.TagText("h4", "EVICT [unit] ..."); - temp = "Evict the specified unit from the object of which you are " - "currently the owner. If multipe EVICT orders are given, all " - "of the units will be evicted."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Evict units 415 and 698 from an object that this unit owns."; - temp2 = "EVICT 415 698"; - f.CommandExample(temp, temp2); - temp = "or"; - temp2 = "EVICT 415\nEVICT 698"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("exchange"); - f.TagText("h4", "EXCHANGE [unit] [quantity given] [item given] " - "[quantity expected] [item expected]"); - temp = "This order allows any two units that can see each other, to " - "trade items regardless of faction stances. The orders given by " - "the two units must be complementary. If either unit involved does " - "not have the items it is offering, or if the exchange orders given " - "are not complementary, the exchange is aborted. Men may not be " - "exchanged."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Exchange 10 LBOW for 10 SWOR with unit 1310"; - temp2 = "EXCHANGE 1310 10 LBOW 10 SWOR"; - f.CommandExample(temp, temp2); - temp = "Unit 1310 would issue (assuming the other unit is 3453)"; - temp2 = "EXCHANGE 3453 10 SWOR 10 LBOW"; - f.CommandExample(temp, temp2); - - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("faction"); - f.TagText("h4", "FACTION [type] [points] ..."); - temp = AString("Attempt to change your faction's type. In the order, you " - "can specify up to three faction types (") + FactionStrs[0] + ", " + FactionStrs[1] + ", and " + FactionStrs[2] + - ") and the number of faction points to assign to each type; if " - "you are assigning points to only one or two types, you may " - "omit the types that will not have any points."; - f.Paragraph(temp); - temp = "Changing the number of faction points assigned to HEROES may " - "be tricky. Increasing the HEROES points will always succeed, but " - "if you decrease the number of points assigned to HEROES, you " - "must make sure that you have only the number of heroes " - "allowed by the new number of HEROES points BEFORE you " - "change your point distribution. For example, if you have 4 " - "heroes (3 points assigned to HEROES), but want to use one of " - "those points for WAR or TRADE (change to HEROES 2), you must " - "first get rid of one of your heroes by either giving it to " - "another faction or disbanding the unit. "; - temp += "If you have too many heroes for the number of points you " - "try to assign to HEROES, the FACTION order will fail."; - if (qm_exist) { - temp += " Similar problems could occur with TRADE points and " - "the number of quartermasters controlled by the faction."; - } - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Assign 2 faction points to WAR, 2 to TRADE, and 1 to HEROES."; - temp2 = "FACTION WAR 2 TRADE 2 HEROES 1"; - f.CommandExample(temp, temp2); - temp = "Become a pure hero faction (assign all points to heroes)."; - temp2 = "FACTION HEROES "; - temp2 += Globals->FACTION_POINTS; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("fightas"); - f.TagText("h4", "FIGHTAS [type]"); - f.TagText("h4", "FIGHTAS"); - temp = "The FIGHTAS order commands a unit to fight in battle as " - "though it has less mobility than it does. The valid values " - "for type are 'FOOT', 'RIDE', or 'FLY'. A unit fighting as if it " - "is on foot will still get combat bonuses from being mounted, " - "but will fight alongside the army's foottroops. 'FIGHTAS RIDE' " - "will only affect flying troops, which will fight as though they " - "are able to ride but not fly. 'FIGHTAS FLY' is equivalent to the " - "second form, and will cause a unit to fight using its full " - "mobility."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set a unit to fight as though it is on foot:"; - temp2 = "FIGHTAS FOOT"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("find"); - f.TagText("h4", "FIND [faction]"); - f.TagText("h4", "FIND ALL"); - temp = "Find the email address of the specified faction or of all " - "factions."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Find the email address of faction 4."; - temp2 = "FIND 4"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("follow"); - f.TagText("h4", "FOLLOW SHIP [number]"); - f.TagText("h4", "FOLLOW UNIT [unit]"); - temp = "Attempt to follow the target unit or ship. If the unit issuing this order is the " - "owner of a ship (during the move phase) then he will attempt to follow the target by " - "sailing the ship in the direction the target moves; otherwise, he will MOVE or " - "ADVANCE in this direction. If the target is not present or moving in a particular " - "move phase, then the unit will wait, and if the target departs during a later move phase, " - "then following unit will suffer a penalty to his movepoints equal to the number of movepoints the " - "target unit has used, and then follow the target to the best of his ability. If the unit " - "being followed escapes by moving while the follower cannot, then the follower will stop " - "in the last region where he saw the target unit, and not attempt to move further. " - "If the target unit is from the follower's or an allied faction, then the following " - "unit will use the ADVANCE order if the unit he is following is advancing, otherwise he " - "will simply MOVE. If this order is used to move an army together, it is recommended that " - "the unit followed should be one of the slowest units in the army, otherwise the army will " - "get split up."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Follow ship number 115"; - temp2 = "FOLLOW SHIP 115"; - f.CommandExample(temp, temp2); - temp = "Follow newly formed unit, alias 3"; - temp2 = "FOLLOW UNIT NEW 3"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("forget"); - f.TagText("h4", "FORGET [skill]"); - temp = "Forget the given skill. This order is useful for normal units " - "who wish to learn a new skill, but already know a different skill."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Forget knowledge of Mining."; - temp2 = "FORGET Mining"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("form"); - f.TagText("h4", "FORM [alias]"); - f.TagText("h4", "FORM"); - temp = "Form a new unit. The newly created unit will be in your " - "faction, in the same region as the unit which formed it, and in " - "the same structure if any. It will start off, however, with no " - "people or items; you should, in the same month, issue orders to " - "transfer people into the new unit, or have it recruit members. The " - "new unit will inherit its flags from the unit that forms it, such " - "as avoiding, behind, and autotax."; - f.Paragraph(temp); - temp = "The FORM order is followed by a list of orders for the newly " - "created unit. This list is terminated by the END keyword, after " - "which orders for the original unit resume."; - f.Paragraph(temp); - temp = "The purpose of the \"alias\" parameter is so that you can refer " - "to the new unit. You will not know the new unit's number until " - "you receive the next turn report. To refer to the new unit in " - "this set of orders, pick an alias number (the only restriction on " - "this is that it must be at least 1, and you should not create two " - "units in the same region in the same month, with the same alias " - "numbers). The new unit can then be referred to as NEW in " - "place of the regular unit number. If no alias is specified, you " - "will not be able to refer to the new unit in your orders."; - f.Paragraph(temp); - temp = "You can refer to newly created units belonging to other " - "factions, if you know what alias number they are, e.g. FACTION 15 " - "NEW 2 will refer to faction 15's newly created unit with alias 2."; - f.Paragraph(temp); - temp = "Note: If a unit moves out of the region in which it was formed " - "(by the "; - temp += f.Link("#move", "MOVE") + " order, or otherwise), the alias " - "will no longer work. This is to prevent conflicts with other units " - "that may have the same alias in other regions."; - f.Paragraph(temp); - temp = "If the demand for recruits in that region that month is much " - "higher than the supply, it may happen that the new unit does not " - "gain all the recruits you ordered it to buy, or it may not gain " - "any recruits at all. If the new units gains at least one recruit, " - "the unit will form possessing any unused silver and all the other " - "items it was given. If no recruits are gained at all, the empty " - "unit will be dissolved, and the silver and any other items it was " - "given will revert to the first unit you have in that region."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "This set of orders for unit 17 would create two new units with " - "alias numbers 1 and 2, name them Merlin's Guards and Merlin's " - "Workers, set the description for Merlin's Workers, have both units " - "recruit men, and have Merlin's Guards study combat. Merlin's " - "Workers will have the default order "; - temp += f.Link("#work", "WORK") + ", as all newly created units do. The " - "unit that created these two then pays them enough money (using the " - "NEW keyword to refer to them by alias numbers) to cover the costs " - "of recruitment and the month's maintenance."; - temp2 = "UNIT 17\n"; - temp2 += "FORM 1\n"; - temp2 += " NAME UNIT \"Merlin's Guards\"\n"; - if(Globals->RACES_EXIST) - temp2 += " BUY 5 Plainsmen\n"; - else - temp2 += " BUY 5 men\n"; - temp2 += " STUDY COMBAT\n"; - temp2 += "END\n"; - temp2 += "FORM 2\n"; - temp2 += " NAME UNIT \"Merlin's Workers\"\n"; - temp2 += " DESCRIBE UNIT \"wearing dirty overalls\"\n"; - if(Globals->RACES_EXIST) - temp2 += " BUY 15 Plainsmen\n"; - else - temp2 += " BUY 15 men\n"; - temp2 += "END\n"; - temp2 += "CLAIM 2500\n"; - temp2 += "GIVE NEW 1 1000 silver\n"; - temp2 += "GIVE NEW 2 2000 silver\n"; - f.CommandExample(temp,temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("give"); - f.TagText("h4", "GIVE [unit] [quantity] [item]"); - f.TagText("h4", "GIVE [unit] ALL [item]"); - f.TagText("h4", "GIVE [unit] ALL [item] EXCEPT [quantity]"); - f.TagText("h4", "GIVE [unit] ALL [item class]"); - f.TagText("h4", "GIVE [unit] UNIT"); - temp = "The first form of the GIVE order gives a quantity of an item to " - "another unit. The second form of the GIVE order will give all of " - "a given item to another unit. The third form will give all of an " - "item except for a specific quantity to another unit. The fourth " - "form will give all items of a specific type to another unit. The " - "final form of the GIVE order gives the entire unit to the " - "specified unit's faction."; - f.Paragraph(temp); - temp = "The classes of items which are acceptable for the fourth form of " - "this order are, NORMAL, ADVANCED, TRADE, MAN or MEN, MONSTER or " - "MONSTERS, MAGIC, WEAPON OR WEAPONS, ARMOUR, MOUNT or MOUNTS, BATTLE, " - "SPECIAL, TOOL or TOOLS, FOOD, and ITEM or ITEMS (which is the " - "combination of all of the previous categories)."; - f.Paragraph(temp); - temp = "A unit may only give items, including silver, to a unit which " - "it is able to see, unless the faction of the target unit has " - "declared you Friendly or better. If the target unit is not a " - "member of your faction, then its faction must have declared you " - "Friendly, with a couple of exceptions. First, silver may be given " - "to any visible unit, regardless of factional affiliation. Secondly, men " - "may not be given to units in other factions (you must give the " - "entire unit); the reason for this is to prevent highly skilled " - "units from being sabotaged with a "; - temp += f.Link("#give", "GIVE") + " order."; - f.Paragraph(temp); - temp = "There are also a few restrictions on orders given by units who are " - "being given to another faction. If the receiving faction is not " - "allied to the giving faction, the unit may not issue the "; - temp += f.Link("#advance", "ADVANCE") + " order, or issue any more "; - temp += f.Link("#give", "GIVE") + " orders. Both of these rules are to " - "prevent unfair sabotage tactics."; - f.Paragraph(temp); - temp = "If 0 is specified as the unit number, then the items are " - "discarded."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Give 10 swords to unit 4573."; - temp2 = "GIVE 4573 10 swords"; - f.CommandExample(temp, temp2); - temp = "Give 5 chain armour to the new unit, alias 2, belonging to " - "faction 14."; - temp2 = "GIVE FACTION 14 NEW 2 5 \"Chain armour\""; - f.CommandExample(temp, temp2); - temp = "Give control of this unit to the faction owning unit 75."; - temp2 = "GIVE 75 UNIT"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("guard"); - f.TagText("h4", "GUARD [flag]"); - temp = "GUARD 1 sets the unit issuing the order to prevent non-Friendly " - "units from collecting taxes in the region, and to prevent any " - "units not your own from pillaging the region. Guarding units " - "will also attempt to prevent Unfriendly units from entering the " - "region. GUARD 0 cancels Guard status."; - f.Paragraph(temp); - temp = "The Guard and Avoid Combat flags are mutually exclusive; " - "setting one automatically cancels the other."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Instruct the current unit to be on guard."; - temp2 = "GUARD 1"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("hold"); - f.TagText("h4", "HOLD [flag]"); - temp = "HOLD 1 instructs the issuing unit to never join a battle in " - "regions the unit is not in. This can be useful if the unit is in " - "a building, and doesn't want to leave the building to join combat. " - "HOLD 0 cancels holding status."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Instruct the unit to avoid combat in other regions."; - temp2 = "HOLD 1"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("label"); - f.TagText("h4", "LABEL [new label]"); - temp = "Change the label of the unit. Labels can be " - "of any length, up to the line length your mailer can handle. If " - "no label is given, the current label will be cleared out. The " - "label of a unit functions like a description, but it is not " - "visible to other players, and may be referred to with the "; - temp += f.Link("#all", "ALL") + " order."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set the unit's label to read \"North Army\"."; - temp2 = "Label \"North Army\""; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("leave"); - f.TagText("h4", "LEAVE"); - temp = "Leave the object you are currently in."; - if(move_over_water) { - temp += " If a unit is capable of swimming "; - if(Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) - temp += "or flying "; - temp += "then this order is usable to leave a boat while at sea."; - } else - temp += " The order cannot be used at sea."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Leave the current object"; - temp2 = "LEAVE"; - f.CommandExample(temp, temp2); - - if(Globals->EARTHSEA_VICTORY) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("master"); - f.TagText("h4", "MASTER [flag]"); - temp = "MASTER 0 instructs a mage unit to relinquish any claim to mastery " - "which they hold. MASTER 1 is a month long order, and causes a mage " - "to spend the month in meditation, to assume the mantle of master " - "of whichever field of magic the mage specialises in. The mage " - "must specialise in one magic field, there may be no more than one other " - "mage in the world who has previously claimed the title of master " - "in that magic field, and the mage must have the appropriate skills " - "necessary to claim mastery. The title of master brings with it a 10% bonus " - "to the mage's energy recharge, but that mage's location will " - "forever after be revealed to the world."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Spend the month assuming the mantle of a master"; - temp2 = "MASTER 1"; - f.CommandExample(temp, temp2); - } - f.ClassTagText("div", "rule", ""); - f.LinkRef("move"); - f.TagText("h4", "MOVE [dir] ..."); - temp = "Attempt to move in the direction(s) specified. If more than " - "one direction is given, the unit will move multiple times, in " - "the order specified by the MOVE order, until no more directions " - "are given, or until one of the moves fails. A move can fail " - "because the units runs out of movement points, because the unit " - "attempts to move into the ocean, or because the units attempts " - "to enter a structure, and is rejected."; - f.Paragraph(temp); - temp = "Valid directions are:"; - f.Paragraph(temp); - temp = "1) The compass directions North, Northwest, Southwest, South, " - "Southeast, and Northeast. These can be abbreviated N, NW, SW, S, " - "SE, NE."; - f.Paragraph(temp); - temp = "2) A structure number."; - f.Paragraph(temp); - temp = "3) OUT, which will leave the structure that the unit is in."; - f.Paragraph(temp); - temp = "4) IN, which will move through an inner passage in the " - "structure that the unit is currently in."; - f.Paragraph(temp); - temp = "Multiple MOVE orders given by one unit will chain together."; - f.Paragraph(temp); - temp = "Note that MOVE orders can lead to combat, due to hostile units " - "meeting, or due to an advancing unit being forbidden access to a " - "region. In this case, combat occurs each time all movement out " - "of a single region occurs."; - f.Paragraph(temp); - temp = "Example 1: Units 1 and 2 are in Region A, and unit 3 is in " - "Region B. Units 1 and 2 are hostile to unit 3. Both unit 1 and " - "2 move into region B, and attack unit 3. Since both units moved " - "out of the same region, they attack unit 3 at the same time, and " - "the battle is between units 1 and 2, and unit 3."; - f.Paragraph(temp); - temp = "Example 2: Same as example 1, except unit 2 is in Region C, " - "instead of region A. Both units move into Region B, and attack " - "unit 3. Since unit 1 and unit 2 moved out of different regions, " - "their battles occur at different times. Thus, unit 1 attacks unit " - "3 first, and then unit 2 attacks unit 3 (assuming unit 3 survives " - "the first attack). Note that the order of battles could have " - "happened either way."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Move N, NE and In"; - temp2 = "MOVE N\nMOVE NE IN"; - f.CommandExample(temp, temp2); - temp = "or:"; - temp2 = "MOVE N NE IN"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("name"); - f.TagText("h4", "NAME UNIT [new name]"); - f.TagText("h4", "NAME FACTION [new name]"); - f.TagText("h4", "NAME OBJECT [new name]"); - if (Globals->TOWNS_EXIST) - f.TagText("h4", "NAME CITY [new name]"); - temp = "Change the name of the unit, or of your faction, or of " - "the object the unit is in (of which the unit must be the owner). " - "Names can be of any length, up to the line length your mailer " - "can handle. Names may not contain parentheses (square brackets " - "can be used instead if necessary), or any control characters."; - f.Paragraph(temp); - if (Globals->TOWNS_EXIST) { - temp = "In order to rename a settlement (city, town or village), " - "the unit attempting to rename it must be the owner of a large " - "enough structure located in the city. It requires a tower or " - "better to rename a village, a fort or better to rename a town " - "and a castle or mystic fortress to rename a city. "; - if (Globals->CITY_RENAME_COST) { - int c=Globals->CITY_RENAME_COST; - temp += AString("It also costs $") + c + " to rename a village, $"; - temp += AString(2*c) + " to rename a town, and $"; - temp += AString(3*c) + " to rename a city."; - } - f.Paragraph(temp); - } - f.Paragraph("Example:"); - temp = "Name your faction \"The Merry Pranksters\"."; - temp2 = "NAME FACTION \"The Merry Pranksters\""; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("noaid"); - f.TagText("h4", "NOAID [flag]"); - temp = "NOAID 1 indicates that if the unit attacks, or is attacked, it " - "is not to be aided by units in other hexes. NOAID status is very " - "useful for scouts or probing units, who do not wish to drag " - "their nearby armies into battle if they are caught. NOAID 0 " - "cancels this."; - f.Paragraph(temp); - temp = "If multiple units are on one side in a battle, they must all " - "have the NOAID flag on, or they will receive aid from other hexes."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set a unit to receive no aid in battle."; - temp2 = "NOAID 1"; - f.CommandExample(temp, temp2); - - if(move_over_water) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("nocross"); - f.TagText("h4", "NOCROSS [flag]"); - temp = "NOCROSS 1 indicates that if a unit attempts to cross a " - "body of water then that unit should instead not cross it, " - "regardless of whether the unit otherwise could do so. "; - if(may_sail) { - temp += "Units inside of a ship are not affected by this flag " - "(IE, they are able to sail within the ship). "; - } - temp += "This flag is useful to prevent scouts from accidentally " - "drowning when exploring in games where movement over water " - "is allowed. NOCROSS 0 cancels this."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set a unit to not permit itself to cross water."; - temp2 = "NOCROSS 1"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("option"); - f.TagText("h4", "OPTION TIMES"); - f.TagText("h4", "OPTION NOTIMES"); - f.TagText("h4", "OPTION TEMPLATE OFF"); - f.TagText("h4", "OPTION TEMPLATE SHORT"); - f.TagText("h4", "OPTION TEMPLATE LONG"); - f.TagText("h4", "OPTION TEMPLATE MAP"); - temp = "The OPTION order is used to toggle various settings that " - "affect your reports, and other email details. OPTION TIMES sets it " - "so that your faction receives the times each week (this is the " - "default); OPTION NOTIMES sets it so that your faction is not sent " - "the times."; - f.Paragraph(temp); - temp = "The OPTION TEMPLATE order toggles the length of the Orders " - "Template that appears at the bottom of a turn report. The OFF " - "setting eliminates the Template altogether, and the SHORT, LONG " - "and MAP settings control how much detail the Template contains. " - "The MAP setting will produce an ascii map of the region and " - "surrounding regions in addition other details."; - f.Paragraph(temp); - temp = "For the MAP template, the region identifiers are (there might " - "be additional symbols for unusual/special terrain):"; - f.Paragraph(temp); - f.Enclose(1, "table"); - if(Globals->UNDERWORLD_LEVELS) { - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("####"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("BLOCKED HEX (Underworld)"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("~~~~"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("OCEAN HEX"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = "PLAINS"; - if(Globals->UNDERWORLD_LEVELS) - temp += "/TUNNELS"; - temp += " HEX"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("^^^^"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = "FOREST"; - if(Globals->UNDERWORLD_LEVELS) - temp += "/UNDERFOREST"; - temp += " HEX"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("/\\/\\"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("MOUNTAIN HEX"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("vvvv"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("SWAMP HEX"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - if(!Globals->CONQUEST_GAME) { - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("@@@@"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("JUNGLE HEX"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("...."); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = "DESERT"; - if(Globals->UNDERWORLD_LEVELS) - temp += "/CAVERN"; - temp += " HEX"; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr(",,,,"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("TUNDRA HEX"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - if(Globals->NEXUS_EXISTS) { - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap class=\"fixed\""); - f.PutStr("!!!!"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("THE NEXUS"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Paragraph("Example:"); - temp = "Set your faction to recieve the map format order template"; - temp2 = "OPTION TEMPLATE MAP"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("password"); - f.TagText("h4", "PASSWORD [password]"); - f.TagText("h4", "PASSWORD"); - temp = "The PASSWORD order is used to set your faction's password. If " - "you have a password set, you must specify it on your #ATLANTIS " - "line for the game to accept your orders. This protects you orders " - "from being overwritten, either by accident or intentionally by " - "other players. PASSWORD with no password given clears out your " - "faction's password."; - f.Paragraph(temp); - temp = "IMPORTANT: The PASSWORD order does not take effect until the " - "turn is actually run. So if you set your password, and then want " - "to re-submit orders, you should use the old password until the " - "turn has been run."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set the password to \"xyzzy\"."; - temp2 = "PASSWORD xyzzy"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("pillage"); - f.TagText("h4", "PILLAGE"); - temp = "Use force to extort as much money as possible from the region. " - "Note that the "; - temp += f.Link("#tax", "TAX") + " order and the PILLAGE order are "; - temp += "mutually exclusive; a unit may only attempt to do one in a " - "turn."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Pillage the current hex."; - temp2 = "PILLAGE"; - f.CommandExample(temp, temp2); - - if(Globals->USE_PREPARE_COMMAND) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("prepare"); - f.TagText("h4", "PREPARE [item]"); - temp = "This command allows a mage or apprentice to prepare a " - "battle item (e.g. a Staff of Fire) for use in battle. "; - if (Globals->USE_PREPARE_COMMAND == GameDefs::PREPARE_STRICT) { - temp += " This selects the battle item which will be used, "; - } else { - temp += "This allows the mage to override the usual selection " - "of battle items, "; - } - temp += "and also cancels any spells set via the "; - temp += f.Link("#combat", "COMBAT") + " order."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Select a staff of fire as the "; - if (!(Globals->USE_PREPARE_COMMAND == GameDefs::PREPARE_STRICT)) - temp += "preferred "; - temp += "battle item."; - temp2 = "PREPARE STAF"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("produce"); - f.TagText("h4", "PRODUCE [item]"); - temp = "Spend the month producing as much as possible of the specified " - "item."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Produce as many crossbows as possible."; - temp2 = "PRODUCE crossbows"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("promote"); - f.TagText("h4", "PROMOTE [unit]"); - temp = "Promote the specified unit to owner of the object of which you " - "are currently the owner. The target unit must have declared you " - "Friendly."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Promote unit 415 to be the owner of the object that this unit " - "owns."; - temp2 = "PROMOTE 415"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("quit"); - f.TagText("h4", "QUIT [password]"); - temp = "Quit the game. On issuing this order, your faction will be " - "completely and permanently destroyed. Note that you must give " - "your password for the quit order to work; this is to provide " - "some safety against accidentally issuing this order."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Quit the game if your password is foobar."; - temp2 = "QUIT \"foobar\""; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("restart"); - f.TagText("h4", "RESTART [password]"); - temp = "Similar to the "; - temp += f.Link("#quit", "QUIT") + " order, this order will completely " - "and permanently destroy your faction. However, it will begin a " - "brand new faction for you (you will get a separate turn report for " - "the new faction). Note that you must give your password for this " - "order to work, to provide some protection against accidentally " - "issuing this order."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Restart as a new faction if your password is foobar."; - temp2 = "RESTART \"foobar\""; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("reveal"); - f.TagText("h4", "REVEAL"); - f.TagText("h4", "REVEAL UNIT"); - f.TagText("h4", "REVEAL FACTION"); - temp = "Cause the unit to either show itself (REVEAL UNIT), or show " - "itself and its faction affiliation (REVEAL FACTION), in the turn " - "report, to all other factions in the region. "; - if(has_stea) { - temp += "Used to reveal high stealth scouts, should there be some " - "reason to. "; - } - temp += "REVEAL is used to cancel this."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Show the unit to all factions."; - temp2 = "REVEAL UNIT"; - f.CommandExample(temp, temp2); - temp = "Show the unit and it's affiliation to all factions."; - temp2 = "REVEAL FACTION"; - f.CommandExample(temp, temp2); - temp = "Cancels revealling."; - temp2 = "REVEAL"; - f.CommandExample(temp, temp2); - - if(may_sail) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("sail"); - f.TagText("h4", "SAIL [dir] ..."); - f.TagText("h4", "SAIL"); - temp = "The first form will sail the ship, which the unit must be " - "the owner of, in the directions given. The second form " - "will cause the unit to aid in the sailing of the ship, using " - "the Sailing skill. See the section on movement for more " - "information on the mechanics of sailing."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Sail north, then northwest."; - temp2 = "SAIL N NW"; - f.CommandExample(temp, temp2); - temp = "or:"; - temp2 = "SAIL N\nSAIL NW"; - f.CommandExample(temp, temp2); - } - - if(Globals->TOWNS_EXIST) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("sell"); - f.TagText("h4", "SELL [quantity] [item]"); - f.TagText("h4", "SELL ALL [item]"); - temp = "Attempt to sell the amount given of the item given. If the " - "unit does not have as many of the item as it is trying to sell, " - "it will attempt to sell all that it has. The second form will " - "attempt to sell all of that item, regardless of how many it has. " - "If more of the item are on sale (by all the units in the region) " - "than are wanted by the region, the number sold per unit will be " - "split up in proportion to the number each unit tried to sell."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Sell 10 furs to the market."; - temp2 = "SELL 10 furs"; - f.CommandExample(temp, temp2); - } - - if(Globals->SEND_COST >= 0) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("send"); - f.TagText("h4", "SEND DIRECTION [dir] [quantity] [item]"); - f.TagText("h4", "SEND UNIT [unit] [quantity] [item]"); - f.TagText("h4", "SEND DIRECTION [dir] UNIT [unit] [quantity] [item]"); - f.TagText("h4", "SEND UNIT [unit] ALL [item]"); - f.TagText("h4", "SEND UNIT [unit] ALL [item] EXCEPT [quantity]"); - f.TagText("h4", "SEND UNIT [unit] ALL [item class]"); - temp = "The send order allows goods to be sent to neighbouring hexes. " - "Using this order will cost an amount of silver dependent on the weight of the goods SENT. " - "Each good sent will cost the square root of its weight, rounded down. " - "For example, swords (weight 1) cost 1 silver, wood (weight 5) costs 2 silver, " - "while stone (weight 50) costs 7 silver. If the neighbouring " - "hex cannot be reached by a walking unit (eg a forest in winter), " - "this cost will be doubled. If the sending unit cannot " - "pay this cost, the order will fail."; - f.Paragraph(temp); - temp = "The unit to recieve the goods may be specified in three ways. " - "Firstly, the direction the goods are to be sent may be given, " - "and they will be transferred to the first unit belonging to your faction " - "in the neighbouring hex in the direction specified. Valid directions " - "are: N, NE, SE, S, SW, NW, IN, or the number of an object with an " - "inner passage. Alternatively, the unit " - "number may be given, and the goods will be transferred to that unit, " - "providing it is present in a neighbouring hex (and not via an " - "inner passage. Finally, both a direction " - "and unit number may be specified, if required."; - f.Paragraph(temp); - - temp = "The classes of items which are acceptable for " - "this order are NORMAL, ADVANCED, TRADE, " - "MAGIC, WEAPON OR WEAPONS, ARMOUR, MOUNT or MOUNTS, BATTLE, " - "SPECIAL, TOOL or TOOLS, FOOD, and ITEM or ITEMS (which is the " - "combination of all of the previous categories)."; - f.Paragraph(temp); - temp = "A unit may not send any of the following: men, monsters, or illusions. " - "If the target unit is not a member of your faction, then its faction " - "must have declared you Friendly. Lastly, the recieving unit may not " - "have any MOVE, ADVANCE, FOLLOW or SAIL orders, nor be onboard a ship " - "which a crew member is attempting to SAIL."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Send 10 swords to the region to the northwest."; - temp2 = "SEND DIRECTION NW 10 swords"; - f.CommandExample(temp, temp2); - temp = "Send 5 wood to unit 1668."; - temp2 = "SEND UNIT 1668 5 wood"; - f.CommandExample(temp, temp2); - temp = "Send 5 chain armour to the new unit, alias 2, created in the region directly to the north."; - temp2 = "SEND DIRECTION N UNIT NEW 2 5 \"Chain armour\""; - f.CommandExample(temp, temp2); - temp = "Send all magic items to unit 1668, but only if it is located in the region reached via the inner passage in object number 1."; - temp2 = "SEND DIRECTION 1 UNIT 1668 ALL magic"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("share"); - f.TagText("h4", "SHARE [flag]"); - temp = "SHARE 1 instructs the unit to share its possessions with any " - "other unit of your faction that needs them. Thus a unit with a " - "supply of silver could automatically provide silver if any of " - "your other units in the same region does not have enough to " - "perform an action, such as "; - temp += f.Link("#study", "studying"); - temp += ", "; - temp += f.Link("#buy", "buying"); - temp += " or "; - temp += f.Link("#produce", "producing"); - temp += ". SHARE 0 returns a unit to its default selfish state."; - f.Paragraph(temp); - temp = "This sharing does not extend to the heat of battle, " - "only to economic actions. So a unit that is sharing will provide " - "silver for buying or studying, and resources for production " - "(for example, if a sharing unit has wood in its inventory, and " - "another unit is produceing axes but has no wood, then the sharing " - "unit will automatically supply wood for that production)," - "but will not provide weapons to all units if combat occurs."; - f.Paragraph(temp); - temp = "Note that in the case of sharing silver, this can leave the " - "sharing unit without enough funds to pay maintenance, so " - "sharing is to be used with care. You may like to make sure that " - "there is a unit with sufficient funds for maintenance in the " - "same region, and which is not sharing, as those funds will be " - "shared for maintenance, but not for less important purposes."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Instruct the unit to share its possessions with other units " - "of the same faction."; - temp2 = "SHARE 1"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("show"); - f.TagText("h4", "SHOW SKILL [skill] [level]"); - f.TagText("h4", "SHOW ITEM [item]"); - f.TagText("h4", "SHOW OBJECT [object]"); - temp = "The first form of the order shows the skill description for a " - "skill that your faction already possesses. The second form " - "returns some information about an item that is not otherwise " - "apparent on a report, such as the weight. The last form " - "returns some information about an object (such as a ship or a " - "building)."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Show the skill report for Mining 3 again."; - temp2 = "SHOW SKILL Mining 3"; - f.CommandExample(temp, temp2); - temp = "Show the item information for swords again."; - temp2 = "SHOW ITEM sword"; - f.CommandExample(temp, temp2); - temp = "Show the information for towers again."; - temp2 = "SHOW OBJECT tower"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("spoils"); - f.TagText("h4", "SPOILS [type]"); - f.TagText("h4", "SPOILS"); - temp = "The SPOILS order determines which types of spoils the unit " - "should take after a battle. The valid values for type are " - "'NONE', 'WALK', 'RIDE', 'FLY', 'SWIM', 'SAIL' or 'ALL'. The second form is " - "equivalent to 'SPOILS ALL'."; - f.Paragraph(temp); - temp = "When this command is issued, only spoils with 0 weight (at " - "level NONE) or spoils which may be picked up without preventing " - "the unit moving in the specified movement mode (at any level other than " - "ALL) will be picked up. SPOILS ALL will allow a unit to collect " - "any spoils which are dropped regardless of weight or capacity."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Set a unit to pick up items as long as it does not prevent them flying."; - temp2 = "SPOILS FLY"; - f.CommandExample(temp, temp2); - temp = "Set a unit to pick up items as long as it does not overload the ship they are in."; - temp2 = "SPOILS SAIL"; - f.CommandExample(temp, temp2); - - if(has_stea) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("steal"); - f.TagText("h4", "STEAL [unit] [item]"); - temp = "Attempt to steal as much as possible of the specified " - "item from the specified unit. The order may only be issued " - "by a one-man unit."; - f.Paragraph(temp); - temp = "A unit may only attempt to steal from a unit which is " - "able to be seen."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Steal silver from unit 123."; - temp2 = "STEAL 123 SILVER"; - f.CommandExample(temp, temp2); - temp = "Steal wood from unit 321."; - temp2 = "STEAL 321 wood"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("study"); - f.TagText("h4", "STUDY [skill]"); - f.TagText("h4", "STUDY [skill] [level]"); - temp = "Spend the month studying the specified skill. The second form will " - "cause the STUDY order to be placed in your order template, unless the " - "unit has reached the specified level."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Study horse training."; - temp2 = "STUDY \"Horse Training\""; - f.CommandExample(temp, temp2); - temp = "Keep studying combat until the unit reaches level 4, or is ordered otherwise."; - temp2 = "STUDY combat 4"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("tactics"); - f.TagText("h4", "TACTICS"); - f.TagText("h4", "TACTICS AGGRESSIVE"); - f.TagText("h4", "TACTICS DEFENSIVE"); - temp = "Used to adjust the behaviour of battle commanders. " - "Aggressive commanders will be more likely to order " - "their cavalry to flank, and that cavalry is more likely " - "to attack enemy ranged formations if it does so. Defensive " - "commanders will flank more rarely, requiring a more powerful lure " - "to send any cavalry to try and hit the enemy's backline. " - "If a unit does not command the battle, then this flag will " - "have no effect. Using TACTICS without specifying a behaviour will reset " - "the commander to normal behaviour."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Set a unit to lead aggressively in combat."; - temp2 = "TACTICS AGGRESSIVE"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("tax"); - f.TagText("h4", "TAX"); - temp = "Attempt to collect taxes from the region. "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) - temp += "Only War factions may collect taxes, and then "; - else - temp += "Taxes may be collected "; - temp += "only if there are no non-Friendly units on guard. Only " - "combat-ready units may issue this order. Note that the TAX order " - "and the "; - temp += f.Link("#pillage", "PILLAGE") + " order are mutually exclusive; " - "a unit may only attempt to do one in a turn."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Attempt to collect taxes."; - temp2 = "TAX"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("teach"); - f.TagText("h4", "TEACH [unit] ..."); - temp = "Attempt to teach the specified units whatever skill they are " - "studying that month. A list of several units may be specified. " - "All units to be taught must have declared you Friendly. " - "Subsequent TEACH orders can be used to add units to be taught. " - "Only leaders and heroes may teach units."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Teach new unit 2 and unit 510 whatever they are studying."; - temp2 = "TEACH NEW 2 510"; - f.CommandExample(temp, temp2); - temp = "or:"; - temp2 = "TEACH NEW 2\nTEACH 510"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("template"); - f.TagText("h4", "TEMPLATE [name]"); - temp = AString("This order enables you to store a set of orders, to be used by " - "any unit when they are given the appropriate ") + f.Link("#type", "TYPE") + " command. " - "All lines following the TEMPLATE order will be stored, until " - "the next line beginning with ALL, TEMPLATE or UNIT. Due to parsing issues, " - "TYPE and FORM orders should not be included following a TEMPLATE order."; - - f.Paragraph(temp); - f.Paragraph("Examples:"); - f.Paragraph("Store orders for a 'Scout' type unit"); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.PutNoFormat("TEMPLATE Scout"); - f.PutNoFormat(f.Link("#avoid", "avoid") + " 1"); - f.PutNoFormat(f.Link("#noaid", "noaid") + " 1"); - f.PutNoFormat(f.Link("#buy", "BUY") + " 1 peasant"); - f.PutNoFormat(f.Link("#claim", "claim") + " 100"); - f.PutNoFormat(f.Link("#name", "NAME UNIT") + " \"Intrepid Explorer\""); - f.Enclose(0, "pre"); - f.Paragraph("Store orders for an 'Advanced Miner' type unit"); - f.Paragraph(""); - f.Enclose(1, "pre"); - f.PutNoFormat("TEMPLATE Miner"); - f.PutNoFormat(f.Link("#study", "STUDY") + " MINI 2"); - f.PutNoFormat(f.Link("#turn", "TURN")); - f.PutNoFormat("STUDY LEAD"); - f.PutNoFormat("ENDTURN"); - f.PutNoFormat("TURN"); - f.PutNoFormat("STUDY MINI 3"); - f.PutNoFormat("ENDTURN"); - f.PutNoFormat("TURN"); - f.PutNoFormat(f.Link("#produce", "@PRODUCE IRON")); - f.PutNoFormat("ENDTURN"); - f.Enclose(0, "pre"); - - if (qm_exist) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("transport"); - f.TagText("h4", "TRANSPORT [unit] [num] [item]"); - f.TagText("h4", "TRANSPORT [unit] ALL [item]"); - f.TagText("h4", "TRANSPORT [unit] ALL [item] EXCEPT [amount]"); - temp = "Transport the specified items to the given target. In " - "the second form all of the specified item is transport. In " - "the last form, all of the specified item except for the " - "specified amount is transport."; - if (Globals->SHIPPING_COST > 0) { - temp += " Long distance transportation of goods between "; - temp += Globals->LOCAL_TRANSPORT; - temp += AString(" and ") + Globals->NONLOCAL_TRANSPORT; - temp += " hexes away has an associated cost. This cost is based " - "on the weight of the items being transported."; - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_COST) { - temp += " At higher skill levels of the quartermaster " - "skill, the cost for transporting goods will be less."; - } - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_DIST) { - temp += " At higher skill levels of the quartermaster " - "skill, the maximum distance goods can be transported " - "increases over the above."; - } - } - temp += " The target of the transport unit must be a unit with the " - "quartermaster skill and must be the owner of a transport " - "structure."; - temp += " For long distance transport between quartermasters, the " - "issuing unit must also be a quartermaster and be the owner of " - "a transport structure. Use of this order counts as trade " - "activity in the hex."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Transport 10 STON to unit 1234"; - temp2 = "TRANSPORT 1234 10 STON"; - f.CommandExample(temp, temp2); - temp = "Transport all except 10 SWOR to unit 3432"; - temp2 = "TRANSPORT 3432 ALL SWOR EXCEPT 10"; - f.CommandExample(temp, temp2); - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("turn"); - f.TagText("h4", "TURN"); - temp = "The TURN order may be used to delay orders by one (or more) " - "turns. By making the TURN order repeating (via '@'), orders inside " - "the TURN/ENDTURN construct will repeat. Multiple TURN orders in a " - "row will execute on successive turns, and if they all repeat, they " - "will form a loop of orders. Each TURN section must be ended by an " - "ENDTURN line."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Study combat until the unit reaches level 2, move north the next month, and then " - "months pillage and advance north."; - temp2 = "STUDY COMB 2\n"; - temp2 += "TURN\n"; - temp2 += " MOVE N\n"; - temp2 += "ENDTURN\n"; - temp2 += "TURN\n"; - temp2 += " PILLAGE\n"; - temp2 += " ADVANCE N\n"; - temp2 += "ENDTURN"; - f.CommandExample(temp, temp2); - temp = "After the turn, the orders for that unit would look as " - "follows in the orders template:"; - temp2 = "MOVE N\n"; - temp2 += "TURN\n"; - temp2 += " PILLAGE\n"; - temp2 += " ADVANCE N\n"; - temp2 += "ENDTURN"; - f.CommandExample(temp, temp2); - temp = "Set up a simple cash caravan (It's assumed here that someone is " - "funnelling cash into this unit."; - temp2 = "MOVE N\n"; - temp2 += "@TURN\n"; - temp2 += " GIVE 13523 1000 SILV\n"; - temp2 += " MOVE S S S\n"; - temp2 += "ENDTURN\n"; - temp2 += "@TURN\n"; - temp2 += " MOVE N N N\n"; - temp2 += "ENDTURN"; - f.CommandExample(temp, temp2); - temp = "After the turn, the orders for that unit would look as " - "follows in the orders template:"; - temp2 = "GIVE 13523 1000 SILV\n"; - temp2 += "MOVE S S S\n"; - temp2 += "@TURN\n"; - temp2 += " MOVE N N N\n"; - temp2 += "ENDTURN\n"; - temp2 += "@TURN\n"; - temp2 += " GIVE 13523 1000 SILV\n"; - temp2 += " MOVE S S S\n"; - temp2 += "ENDTURN"; - f.CommandExample(temp, temp2); - temp = "If the unit does not have enough movement points to cover " - "the full distance, the MOVE commands will automatically " - "be completed over multiple turns before executing the next " - "TURN block."; - f.Paragraph(temp); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("type"); - f.TagText("h4", "TYPE [name]"); - temp = "Apply the set of orders stored in the "; - temp += f.Link("#template", "template") + " [name] to the " - "current unit."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Apply the template 'Scout' to the current unit."; - temp2 = "TYPE Scout"; - f.CommandExample(temp, temp2); - - if(Globals->USE_WEAPON_ARMOR_COMMAND) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("weapon"); - f.TagText("h4", "WEAPON [item] ..."); - f.TagText("h4", "WEAPON"); - temp = "This command allows you to set a list of preferred weapons " - "for a unit. After searching for weapons on the preferred " - "list, the standard weapon precedence takes effect if a weapon " - "hasn't been set. The second form clears the preferred weapon " - "list."; - f.Paragraph(temp); - f.Paragraph("Examples"); - temp = "Set the unit to select double bows, then longbows then " - "crossbows"; - temp2 = "WEAPON DBOW LBOW XBOW"; - f.CommandExample(temp, temp2); - temp = "Clear the preferred weapon list."; - temp2 = "WEAPON"; - f.CommandExample(temp, temp2); - } - if (Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) { - f.Enclose(1, "LI"); - f.PutStr("Bank orders."); - f.Enclose(1, "UL"); - f.TagText("LI" , "Interest is calculated."); - temp = f.Link("#bank","BANK") + " DEPOSIT orders are processed."; - f.TagText("LI", temp); - temp = f.Link("#bank","BANK") + " WITHDRAW orders are processed."; - f.TagText("LI", temp); - f.Enclose(0, "UL"); - f.Enclose(0, "LI"); - } - - if(Globals->ALLOW_WITHDRAW) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("withdraw"); - f.TagText("h4", "WITHDRAW [item]"); - f.TagText("h4", "WITHDRAW [quantity] [item]"); - temp = "Use unclaimed funds to aquire basic items that you need. " - "If you do not have sufficient unclaimed, or if you try " - "withdraw any other than a basic item, an error will be given. " - "Withdraw can NOT be used in the Nexus (to prevent building " - "towers and such there). The first form is the same as " - "WITHDRAW 1 [item] in the second form."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Withdraw 5 stone."; - temp2 = "WITHDRAW 5 stone"; - f.CommandExample(temp, temp2); - temp = "Withdraw 1 iron."; - temp2 = "WITHDRAW iron"; - f.CommandExample(temp, temp2); - if(Globals->TESTGAME_ENABLED) { - f.ClassTagText("div", "rule", ""); - f.LinkRef("wishdraw"); - f.TagText("h4", "WISHDRAW [item]"); - f.TagText("h4", "WISHDRAW [quantity] [item]"); - temp = "This order is enabled in testgames only. " - "It allows you to withdraw most items, without paying the usual cost " - "associated with doing so. All items which may be given between units " - "may be wishdrawn, including some (but not all) monsters. Wishdraw takes place after Withdraw. " - "Note that units with no men in them may not execute their orders, so a wishdrawing unit should have at least one man at the withdraw phase. Please " - "note that misuse of this order may create situations which were never " - "intended to occur in Atlantis, such as mage units with multiple men. " - "Because it is enabled for testing purposes, please be careful with its " - "use, and use it only to wishdraw things which could be gained using some " - "other method."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Wishdraw 5 stone."; - temp2 = "WISHDRAW 5 stone"; - f.CommandExample(temp, temp2); - temp = "Wishdraw 1 mithril sword."; - temp2 = "WISHDRAW mithril_sword"; - f.CommandExample(temp, temp2); - - f.ClassTagText("div", "rule", ""); - f.LinkRef("wishskill"); - f.TagText("h4", "WISHSKILL [skill] [days of knowledge] [days of experience]"); - temp = "This order is enabled in testgames only. " - "It allows you to change the skills your unit has, without paying the usual cost " - "associated with doing so. This order should limit skill levels to the maximum allowed for the unit, " - "but it makes no guarantee to do so in all circumstances - so as with Wishdraw, use " - "this order with caution. In particular, this skill will NOT work as usual " - "with the leadership and heroship skills, and I have not checked whether " - "it prevents non-heroes studying hero skills. Usual prerequisites required for skills are ignored " - "in the execution of this order. Because it is enabled for testing purposes, please be careful with its " - "use, and use it only to wishskill skills which could be gained using some " - "other method in the game."; - f.Paragraph(temp); - f.Paragraph("Examples:"); - temp = "Wishskill level 5 mining."; - temp2 = "WISHSKILL mining 180 90"; - f.CommandExample(temp, temp2); - temp = "Wishskill level 4 summon wind."; - temp2 = "WISHSKILL summon_wind 90 90"; - f.CommandExample(temp, temp2); - } - } - - f.ClassTagText("div", "rule", ""); - f.LinkRef("work"); - f.TagText("h4", "WORK"); - temp = "Spend the month performing manual work for wages."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Work all month."; - temp2 = "WORK"; - f.CommandExample(temp, temp2); - - f.LinkRef("sequenceofevents"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Sequence of Events"); - temp = "Each turn, the following sequence of events occurs:"; - f.Paragraph(temp); - f.Enclose(1, "OL"); - f.Enclose(1, "li"); - f.PutStr("Instant orders."); - f.Enclose(1, "ul"); - temp = f.Link("#turn", "TURN") + ", "; - temp = f.Link("#form", "FORM") + ", "; - temp = f.Link("#all", "ALL") + ", "; - temp = f.Link("#label", "LABEL") + ", "; - temp = f.Link("#template", "TEMPLATE") + " and "; - temp += f.Link("#type", "TYPE") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#address", "ADDRESS") + ", "; - if(Globals->USE_WEAPON_ARMOR_COMMAND) - temp += f.Link("#armour", "ARMOUR") + ", "; - temp += f.Link("#autotax", "AUTOTAX") + ", "; - temp += f.Link("#avoid", "AVOID") + ", "; - temp += f.Link("#behind", "BEHIND") + ", "; - temp += f.Link("#claim", "CLAIM") + ", "; - temp += f.Link("#combat", "COMBAT") + ", "; - temp += f.Link("#combat", "COMMAND") + ", "; - if(Globals->FOOD_ITEMS_EXIST) - temp += f.Link("#consume", "CONSUME") + ", "; - temp += f.Link("#declare", "DECLARE") + ", "; - temp += f.Link("#describe", "DESCRIBE") + ", "; - temp += f.Link("#disable", "DISABLE") + ", "; - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) - temp += f.Link("#faction", "FACTION") + ", "; - temp += f.Link("#fightas", "FIGHTAS") + " 0, "; - temp += f.Link("#guard", "GUARD") + " 0, "; - temp += f.Link("#hold", "HOLD") + ", "; - temp += f.Link("#name", "NAME") + ", "; - temp += f.Link("#noaid", "NOAID") + ", "; - if(move_over_water) - temp += f.Link("#nocross", "NOCROSS") + ", "; - temp += f.Link("#option", "OPTION") + ", "; - temp += f.Link("#password", "PASSWORD") + ", "; - if(Globals->USE_PREPARE_COMMAND) - temp += f.Link("#prepare", "PREPARE") + ", "; - temp += f.Link("#reveal", "REVEAL") + ", "; - temp += f.Link("#share", "SHARE") + ", "; - temp += f.Link("#show", "SHOW") + ", "; - temp += f.Link("#spoils", "SPOILS") + ", "; - if(!Globals->USE_WEAPON_ARMOR_COMMAND) - temp += "and "; - temp += f.Link("#tactics", "TACTICS"); - if(Globals->USE_WEAPON_ARMOR_COMMAND) { - temp += ", and "; - temp += f.Link("#weapon", "WEAPON"); - } - temp += " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#find", "FIND") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#leave", "LEAVE") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#enter", "ENTER") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#promote", "PROMOTE") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr("Combat is processed."); - f.Enclose(1, "ul"); - temp = f.Link("#attack", "ATTACK") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - if (has_stea) { - f.Enclose(1, "li"); - f.PutStr("Steal orders."); - f.Enclose(1, "ul"); - temp = f.Link("#steal", "STEAL") + " and "; - temp += f.Link("#assassinate", "ASSASSINATE") + - " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - f.Enclose(1, "li"); - f.PutStr("Give orders."); - f.Enclose(1, "ul"); - temp = f.Link("#destroy", "DESTROY") + " and "; - temp += f.Link("#give", "GIVE") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#exchange", "EXCHANGE") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - - if(Globals->ARCADIA_MAGIC) { - f.Enclose(1, "li"); - f.PutStr("Instant Magic"); - f.Enclose(1, "ul"); - f.TagText("li", "Old spells are cancelled."); - temp = "Spells are "; - temp += f.Link("#cast", "CAST"); - temp += " (except for Teleportation spells)."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - if(!Globals->LATE_TAX) { - f.Enclose(1, "li"); - f.PutStr("Tax orders."); - f.Enclose(1, "ul"); - temp = f.Link("#pillage","PILLAGE") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#tax","TAX") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - if(!Globals->ARCADIA_MAGIC) { - f.Enclose(1, "li"); - f.PutStr("Instant Magic"); - f.Enclose(1, "ul"); - f.TagText("li", "Old spells are cancelled."); - temp = "Spells are "; - temp += f.Link("#cast", "CAST"); - temp += " (except for Teleportation spells)."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - - f.Enclose(1, "li"); - f.PutStr("Market orders."); - f.Enclose(1, "ul"); - temp = f.Link("#guard","GUARD") + " 1 orders are processed."; - f.TagText("li", temp); - if(Globals->TOWNS_EXIST) { - temp = f.Link("#sell","SELL") + " orders are processed."; - f.TagText("li", temp); - } - temp = f.Link("#buy","BUY") + " orders are processed."; - f.TagText("li", temp); - if(Globals->SEND_COST >= 0) { - temp = f.Link("#send","SEND") + " orders are processed."; - f.TagText("li", temp); - } - temp = f.Link("#quit","QUIT") + " and "; - temp += f.Link("#restart", "RESTART") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#forget","FORGET") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - if (Globals->ALLOW_WITHDRAW) { - f.Enclose(1, "li"); - f.PutStr("Withdraw orders."); - f.Enclose(1, "ul"); - temp = f.Link("#withdraw","WITHDRAW") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - - if(Globals->LATE_TAX) { - f.Enclose(1, "li"); - f.PutStr("Tax orders."); - f.Enclose(1, "ul"); - temp = f.Link("#pillage","PILLAGE") + " orders are processed."; - f.TagText("li", temp); - temp = f.Link("#tax","TAX") + " orders are processed."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - } - - f.Enclose(1, "li"); - f.PutStr("Movement orders."); - f.Enclose(1, "ul"); - if(may_sail) { - temp = f.Link("#sail","SAIL") + " orders are processed."; - f.TagText("li", temp); - } - temp = f.Link("#advance","ADVANCE") + " and "; - temp += f.Link("#move", "MOVE") + " orders are processed (including any " - "combat resulting from these orders)."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - f.Enclose(1, "li"); - f.PutStr("Month long orders."); - f.Enclose(1, "ul"); - temp = f.Link("#teach", "TEACH") + ", "; - temp += f.Link("#study", "STUDY") + ", "; - if(!(SkillDefs[S_ENTERTAINMENT].flags & SkillType::DISABLED)) - temp += f.Link("#entertain", "ENTERTAIN") + ", "; - temp += f.Link("#work", "WORK") + ", "; - temp += f.Link("#produce", "PRODUCE") + ", and "; - temp += f.Link("#build", "BUILD") + " orders are processed."; - f.TagText("li", temp); - temp = "Costs associated with these orders (such as study fees) are " - "collected."; - f.TagText("li", temp); - f.Enclose(0, "ul"); - f.Enclose(0, "li"); - temp = "Goods from "; - temp += f.Link("#send", "SEND") + "and " + f.Link("#produce", "PRODUCE"); - temp += " orders are credited."; - f.TagText("li", temp); - temp = "Teleportation spells are "; - temp += f.Link("#cast", "CAST") + "."; - f.TagText("li", temp); - if (qm_exist) { - temp = f.Link("#transport", "TRANSPORT") + " and " + - f.Link("#distribute", "DISTRIBUTE") + " orders are processed."; - f.TagText("li", temp); - } - f.TagText("li", "Maintenance costs are assessed."); - f.Enclose(0, "OL"); - temp = "Where there is no other basis for deciding in which order units " - "will be processed within a phase, units that appear higher on the " - "report get precedence."; - f.Paragraph(temp); - f.LinkRef("reportformat"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Report Format"); - temp = "The most important sections of the turn report are the \"Events " - "During Turn\" section which lists what happened last month, and " - "the \"Current Status\" section which gives the description of each " - "region in which you have units."; - f.Paragraph(temp); - temp = "Your units in the Current Status section are flagged with a " - "\"*\" character. Units belonging to other factions are flagged " - "with a \"-\" character. You may be informed which faction they " - "belong to, if "; - if(has_obse) - temp += "you have high enough Observation skill or "; - temp += "they are revealing that information."; - f.Paragraph(temp); - temp = "Objects are flagged with a \"+\" character. The units listed " - "under an object (if any) are inside the object. The first unit " - "listed under an object is its owner."; - f.Paragraph(temp); - temp = "If you can see a unit, you can see any large items it is " - "carrying. This means all items other than silver"; - if(!(ItemDefs[I_HERBS].flags & ItemType::DISABLED)) - temp += ", herbs,"; - temp += " and other small items (which are of zero size units, and are " - "small enough to be easily concealed). Items carried by your own " - "units of course will always be listed."; - f.Paragraph(temp); - temp = "At the bottom of your turn report is an Orders Template. This " - "template gives you a formatted orders form, with all of your " - "units listed. You may use this to fill in your orders, or write " - "them on your own. The "; - temp += f.Link("#option", "OPTION") + " order gives you the option of " - "giving more or less information in this template, or turning it " - "of altogether. You can precede orders with an '@' sign in your " - "orders, in which case they will appear in your template on the " - "next turn's report."; - f.Paragraph(temp); - f.LinkRef("hintsfornew"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Hints for New Players"); - temp = "Make sure to use the correct #ATLANTIS and UNIT lines in your " - "orders."; - f.Paragraph(temp); - temp = "Always have a month's supply of spare cash in every region in " - "which you have units, so that even if they are deprived of " - "income for a month (due to a mistake in your orders, for " - "example), they will not starve to death. It is very frustrating " - "to have half your faction wiped out because you neglected to " - "provide enough money for them to live on."; - f.Paragraph(temp); - temp = "Be conservative with your money. "; - if(Globals->LEADERS_EXIST) { - temp += "Leaders especially are very hard to maintain, as they " - "cannot usually earn enough by "; - temp += f.Link("#work", "WORK") + "ing to pay their maintenance " - "fee. "; - } - temp += "Even once you have recruited men, notice that it is " - "expensive for them to "; - temp += f.Link("#study", "STUDY") + " (and become productive units), " - "so be sure to save money to that end."; - f.Paragraph(temp); - temp = "Don't leave it until the last minute to send orders. If " - "there is a delay in the mailer, your orders will not arrive " - "on time, and turns will NOT be rerun, nor will it be possible " - "to change the data file for the benefit of players whose orders " - "weren't there by the deadline. If you are going to send your " - "orders at the last minute, send a preliminary set earlier in the " - "week so that at worst your faction will not be left with no " - "orders at all."; - f.Paragraph(temp); - - if(Globals->HAVE_EMAIL_SPECIAL_COMMANDS) { - f.LinkRef("specialcommands"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Special Commands"); - temp = "These special commands have been added via the scripts " - "processing the email to help you interact with the game " - "and submit times and rumors. Please read over these new " - "commands and their uses. Also note that all commands sent " - "to the server are logged, including orders submissions, so " - "if you have a problem, or if you attempt to abuse the system, " - "it will get noticed and it will be tracked down."; - f.Paragraph(temp); - f.LinkRef("_create"); - f.ClassTagText("div", "rule", ""); - f.TagText("h4", "#create \"faction name\" \"password\""); - temp = "This will create a new faction with the desired name and " - "password, and it will use the player's \"from\" address as " - "the email address of record (this, of course, can be changed " - "from within the game)."; - f.Paragraph(temp); - temp = "The \"\" characters are required. If they are missing, the " - "server will not create the faction."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Join the game as the faction named \"Mighty Ducks\" with the " - "password of \"quack\""; - temp2="#create \"Mighty Ducks\" \"quack\""; - f.CommandExample(temp, temp2); - - f.LinkRef("_resend"); - f.ClassTagText("div", "rule", ""); - f.TagText("h4", "#resend [faction] \"password\""); - temp = "The faction number and your current password (if you have " - "one) are required. The most recent turn report will be sent to " - "the address of record."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "You are faction 999 with password \"quack\" and need another " - "copy of the last turn (because your harddrive crashed)"; - temp2 = "#resend 999 \"quack\""; - f.CommandExample(temp, temp2); - - f.LinkRef("_times"); - f.ClassTagText("div", "rule", ""); - f.TagText("h4", "#times [faction] \"password\""); - f.PutStr("[body of article]"); - f.TagText("h4", "#end"); - temp = "Everything between the #times and #end lines is included " - "in your article. Your article will be marked as being " - "sent by your fation, so you need not include that " - "attribution in the article."; - if (Globals->TIMES_REWARD) { - temp += " You will receive $"; - temp += Globals->TIMES_REWARD; - temp += " for submitting the article."; - } - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Faction 999 wants to declare war on everyone"; - temp2 = "#times 999 \"quack\"\n"; - temp2 += "The Mighty Ducks declare war on the world!!\n"; - temp2 += "Quack!\n"; - temp2 += "#end"; - f.CommandExample(temp, temp2); - temp = "And it would appear something like:"; - temp2 = "---------------------------------\n"; - temp2 += "The Mighty Ducks declare war on the world!!\n"; - temp2 += "Quack!\n\n"; - temp2 += "[Article submitted by The Mighty Ducks (999)]\n"; - temp2 += "---------------------------------"; - f.CommandExample(temp, temp2); - - f.LinkRef("_rumor"); - f.ClassTagText("div", "rule", ""); - f.TagText("h4", "#rumor [faction] \"password\""); - f.PutStr("[body of rumor]"); - f.TagText("h4", "#end"); - temp = "Submit a rumor for publication in the next news. These " - "articles are not attributed (unlike times articles) and will " - "appear in the rumor section of the next news in a random order."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Start a malicious rumor"; - temp2 = "#rumor 999 \"quack\"\n"; - temp2 += "Oleg is a running-dog lackey of Azthar Spleenmonger.\n"; - temp2 += "#end"; - f.CommandExample(temp, temp2); - - f.LinkRef("_remind"); - f.ClassTagText("div", "rule", ""); - f.TagText("h4", "#remind [faction] \"password\""); - temp = "This order will have the server find the most recent set of " - "orders you have submitted for the current turn and mail them " - "back to your address of record."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Remind faction 999 of its last order set."; - temp2 = "#remind 999 \"quack\""; - f.CommandExample(temp, temp2); - - f.LinkRef("_email"); - f.ClassTagText("div", "rule", ""); - f.TagText("h4", "#email [unit]"); - f.PutStr("[text of email]"); - temp = "This command allows you to send email to the owner of a unit " - "even when you cannot see that unit's faction affiliation. You " - "will not be told who the unit belongs to, but will simply " - "forward your email to them. When you use this command, they " - "will recieve YOUR email and can contact you if they choose. It " - "is provided simply as a courtesy to players to help with " - "diplomacy in first contact situations."; - f.Paragraph(temp); - temp = "There is no need for a \"#end\" line (such as is used in " - "times and rumor submissions -- the entire email message you " - "send will be forwarded to the unit's master."; - f.Paragraph(temp); - f.Paragraph("Example:"); - temp = "Send an email to the owner of unit 9999"; - temp2 = "#email 9999\n"; - temp2 += "Greetings. You've entered the Kingdom of Foo.\n"; - temp2 += "Please contact us.\n\n"; - temp2 += "Lord Foo\n"; - temp2 += "foo@some.email"; - f.CommandExample(temp, temp2); - temp = "Faction X, the owner of 9999 would receive:"; - temp2 = "From: Foo <foo@some.email>\n"; - temp2 += "Subject: Greetings!\n\n"; - temp2 += "#email 9999\n"; - temp2 += "Greetings. You've entered the Kingdom of Foo.\n"; - temp2 += "Please contact us.\n\n"; - temp2 += "Lord Foo\n"; - temp2 += "foo@some.email"; - f.CommandExample(temp, temp2); - } - f.LinkRef("credits"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Credits"); - temp = "Atlantis was originally created and programmed by Russell " - "Wallace. Russell Wallace created Atlantis 1.0, and partially " - "designed Atlantis 2.0 and Atlantis 3.0."; - f.Paragraph(temp); - temp = "Geoff Dunbar designed and programmed Atlantis 2.0, 3.0, and 4.0 " - "up through version 4.0.4 and created the Atlantis Project to " - "freely release and maintain the Atlantis source code."; - f.Paragraph(temp); - temp = "Larry Stanbery created the Atlantis 4.0.4+ derivative."; - f.Paragraph(temp); - temp = f.Link("mailto:jtraub@dragoncat.net", "JT Traub"); - temp += " took over the source code and merged the then forking versions " - "of 4.0.4c and 4.0.4+ back into 4.0.5 along with modifications of his " - "own and has been maintaining the code."; - f.Paragraph(temp); - temp = "Various things have happened since and the codebase now " - "appears to be largely run by someone's spleen."; - f.Paragraph(temp); - temp = "This version of the code is based on Atlantis 5.0.0 as " - "available at August 2003 and has since been substantially " - "modified by Bradley Steel."; - f.Paragraph(temp); - temp = "Acknowledgement must go to Ursala Le Guin's Earthsea books, " - "on which some aspects of the magic system in this game are " - "based - although the majority comes from the development of the " - "Atlantis community mentioned below."; - f.Paragraph(temp); - temp = "The server and website on which the Arcadia games are " - "hosted were set up by Piotr Jakubowicz."; - f.Paragraph(temp); - temp = "The satellite helper program, Atlantis Little Helper, " - "was kindly modified by its developer Max Shariy to be " - "compatible with the changes in Arcadia III."; - f.Paragraph(temp); - - temp = "Development of the code is open and there is a egroup devoted to " - "it located at "; - temp += f.Link("http://groups.yahoo.com/group/atlantisdev", - "The YahooGroups AtlantisDev egroup"); - temp += ". Please join this egroup if you work on the code and share your " - "changes back into the codebase as a whole"; - f.Paragraph(temp); - temp = "Please see the CREDITS file in the source distribution for a " - "complete (hopefully) list of all contributers."; - f.Paragraph(temp); - - - //Arcadia Stuff - //Riding defence not included because no weapon is enabled which has a riding attack. - f.LinkRef("appendixa"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix A"); - f.TagText("h3", "FAQ"); - - f.Paragraph(""); - - temp = "Q: Is there any way of displaying my report other than as text?

"; - temp += "A: Max Shariy has written a program called Atlantis Little Helper, which is " - "compatible with the Nylandor version of Atlantis. It is available from " - "http://members.shaw.ca/mshariy/ah.html. There are a number of other clients " - "written for Atlantis games in general, but they will not support all the " - "features of Nylandor. There are some minor details in ALH which are set to " - "the default values of Atlantis games, rather than Nylandor. Namely, " - "the weights " - "and capacities of some monsters (including dragons and balrogs) have been " - "changed, and pearls are no longer a trade good."; - f.Paragraph(temp); - - temp = "Q: If a unit has a horse but no riding skill, can he ride?

"; - temp += "A: The riding skill only affects combat, so out of combat, he can ride. However, " - "he will not be able to use the horse to ride in combat."; - f.Paragraph(temp); - - temp = "Q: My unit has Capacity: 0/40/100/0. What do all the numbers mean?

"; - temp += "A: The first number is the total weight the unit can fly with. If the unit weighs more " - "than this, it will not be able to fly. The second is for riding movement, and the third " - "for walking movement. Thus, if the unit in question has a weight of 40 or less, it will " - "ride when given the MOVE or ADVANCE order. However, if it weighs 60, it will walk, and if it weighs " - "101 or more, it will not be able to move. The fourth number listed is 'swimming' capacity, " - "which allows units to travel across an ocean without a boat. In almost all instances, this " - "number will be zero."; - f.Paragraph(temp); - - temp = "Q: If my unit has reached its maximum knowledge level, can it still study?

"; - temp += "A: Yes. Further study will provide the same experience as using the skill normally; " - "this is usually 10, but will be less if the unit does not specialise in that skill " - "(leaders are counted as specialising in all non-magic skills). However, it would " - "obviously be better for the unit to get practise for real, so that you do not have " - "to pay study costs."; - f.Paragraph(temp); - - temp = "Q: If something doesn't make sense, where do I go for help?

"; - temp += "A: Ask on the game's yahoogroup. If you are playing, you should have already signed " - "up, but the address is http://groups.yahoo.com/group/arcadia-pbm/ just in case."; - f.Paragraph(temp); - - temp = "Q: Do I have to submit times articles?

"; - temp += "A: No, but it is strongly requested. The times is the main place for roleplay and " - "interaction between players. The Arcadia series of Atlantis was begun as an attempt " - "to get away from the 'big-game' sydnrome of having many players who do not know each " - "other, and interact only through their units. By storytelling in the times, everyone " - "benefits from the creation of a world with many facets."; - f.Paragraph(temp); - - temp = "Q: My mage never has enough energy to cast spells. What should I do?

"; - temp += "A: Magic skills can be split into two sections - the foundations, and the spells. " - "Studying spells gives you more choices as to what to cast. Studying foundations gives " - "your mage more energy with which to cast them. The skill 'inner strength' also helps " - "increase a mage's energy, though it is not technically a foundation skill. If you find " - "you have more energy than you are using, study some more spells. Remember, you can " - "cast as many spells as you like per turn, plus use other spells in battle, as long " - "as you have sufficient energy."; - f.Paragraph(temp); - - temp = "Q: After years of studying I finally got a staff of fire. But my mage keeps casting storms instead!

"; - temp += "A: Your mage will use his 'combat' spell (set with the COMBAT order) in battle. He will only use battle items, " - "such as a staff of fire or lightning, if he has no COMBAT spell set. To clear your combat spell, issue " - "the order 'COMBAT' with no arguments."; - f.Paragraph(temp); - - temp = "Q: I cast a ranged spell and specified the region it was to be cast in, but I got the error message 'No region specified'.

"; - temp += "A: Pay close attention to the spell template. If it has the word REGION, UNIT, UNITS, DIRECTION, or similar " - "present, then those words must be used when writing the order. For instance, the spell " - "description for farsight may say to use the format 'CAST Farsight REGION '. With " - "this template, one possible cast order would be 'CAST Farsight REGION 5 7 1'. The order 'CAST " - "Farsight 5 7 1' will NOT work."; - f.Paragraph(temp); - - temp = "Q: Do I have to use the full spell name when casting?

"; - temp += "A: No, the abbrevation will work as well. For instance, 'CAST Bird_Lore DIRECTION NE' and " - "'CAST BIRD DIRECTION NE' do exactly the same thing. Also, for spells which require " - "a region to be specified, not specifying a region will cause the spell to default to " - "the mage's current location (eg 'CAST Blizzard' will cause a blizzard to be cast " - "on the mage's current location)."; - f.Paragraph(temp); - - temp = "Q: Is there any way to reduce the amount of orders I have to write?

"; - temp += "A: Yes and no. The '@' and 'TURN/ENDTURN' commands are very useful in reducing " - "order writing, as are the TYPE, TEMPLATE and SHARE commands. Also, fine setting " - "of spoils flags before a battle can often save a lot more time after the battle, " - "not having to transfer your spoils from lots of different units. " - "For instance, if you want a unit to cast earthlore every turn, use the order " - "@CAST Earth_Lore, which will cause the order to be included into your orders " - "template for next turn. Then write your next orders based on your order template " - "(if you are using ALH to write orders, it will do this automatically). If you " - "are already using all these commands, then no, there is little else you can do."; - f.Paragraph(temp); - - temp = "Q: Can I prevent enemy ships entering an ocean region?

"; - temp += "A: Uncertain. Remind me to answer this, if you need to know!"; /*No. Units which are guarding can usually prevent units from unfriendly factions " - "entering a hex (unless they wish to initiate a battle). However, this does not work " - "at sea, and an enemy can always sail into the hex. Of course, if you set them hostile " - "you will attack them as soon as they do so. Ships sailing along rivers can be stopped " - "by unfriendly guards, however the ship will move one hexside in the region being guarded " - "and then stop, rather than being prevented from entering the region.";*/ - f.Paragraph(temp); - - temp = "Q: A spell description says it costs 10 energy to cast on 4 men. How much will it cost to cast on one man?

"; - temp += "A: All spell costs are worked out on a per man basis, but the skill description " - "may not reflect this in order to give you are more accurate measure of the cost for " - "casting on multiple men. In this case, the cost for one man would be 10/4 = 2.5, rounded " - "up to a cost of 3 to cast on one man (and 5 energy to cast on two, 8 on 3, etc.). "; - f.Paragraph(temp); - - temp = "Q: Is Arcadia bug-free?

"; - temp += "A: No. Arcadia is based on Atlantis V5, which is now close to bug-free. However, there have been many " - "modifications made for the Arcadia series, and while testing has been done to reduce the number of bugs, there " - "are certainly some remaining. If you become aware of a bug in the program (either harmful OR beneficial) please " - "let your GM know about it, and it will be fixed as soon as possible. In serious " - "cases the gamefile may be modified to remove the result of the bug, or the turn " - "may be rerun. The existance of bugs (hopefully rare) is the price " - "players pay for playing in games with dynamic rules - which are, we like " - "to believe, superior to the original."; - f.Paragraph(temp); - - temp = "Q: If two mages both have fog as their combat spell, will they both cast it?

"; - temp += "A: No. There are a few combat spells which are not cumulative - these include fog, darkness, " - "concealment, and their counter-spells. To save energy, only the best skilled mage from each army will cast " - "these spells in combat; however if this mage runs out of energy, then the second mage " - "will cast instead. " /*Note though, that if the spell fizzles, the second mage will not attempt " - "to cast during that combat round. */ "Shield spells do not follow this pattern - multiple shields may " - "be cast, in case the first shield is destroyed."; - f.Paragraph(temp); - - temp = "Q: If my mage is set to cast 'banish demons', but there are no demons present, what happens?

"; - temp += "A: The mage will realise that his spell will do nothing, and will not cast it. This saves his " - "energy, but also means he is not going to get much battle experience in the spell. " - "This applies to all offensive spells which only target certain creatures; if they cannot hit " - "anyone, they will not get cast."; - f.Paragraph(temp); - - temp = "Q: I am having trouble with TEACH and BUILD orders for units on ships. What's going on?

"; - temp += "A: Unit aliases (such as 'NEW 1') are cleared whenever a unit moves from its original hex. " - "Because SAIL takes place before TEACH orders, this means that if a 'NEW' unit sails, any " - "attempt to teach it (such as TEACH NEW 1) will fail. This only applies to newly formed units, " - "and unfortunately there is not yet a way around it. Additionally, although BUILD orders are " - "processed after SAIL orders, any unit which is on a moving ship and attempts to BUILD will " - "fail his order. This is a side-effect of the way in which BUILD orders are processed, and cannot be avoided." - "If you intended the structure to be built in the region the ship is leaving, then you should " - "give the unit a LEAVE or ENTER order in addition to the BUILD order. If you wanted to BUILD " - "a structure in the region the ship is sailing to, you must wait until the next month, when your " - "builders can disembark and BUILD a structure."; - f.Paragraph(temp); - - temp = "Q: What riding skill do monsters have?

"; - temp += "A: When trying to catch a monster to initiate a battle, the monster will have an effective riding " - "skill of 4 if it flies, 2 if it rides, or 0 if it can only walk or swim. However, when the monster " - "is attempting to initiate a battle, it will have an effective riding skill of 6, 3 or 0 in these cases."; - f.Paragraph(temp); - - temp = "Q: Do roads increase wages in regions where they are built.

"; - temp += "A: This is a common feature in many Atlantis games, but is not enabled " - "in Arcadia."; - f.Paragraph(temp); - - temp = "Q: The spell description for some summoned creatures says they have a maintenance cost which decreases at " - " higher skill levels. How do I know how much it will be?

"; - temp += "A: The cost quoted is accurate at skill level 1. Every level above this reduces the cost by 10%, so the " - "maintenance will be 90% of the quoted value at level 2, down to 50% at level 6. Note that if the maintenance " - "cost is fractional, it will be rounded up, but only after any other effects are taken into account."; - f.Paragraph(temp); - - temp = "Q: What determines the rate at which a settlement grows?

"; - temp += "A: Settlements (villages, towns and cities) will stay at their initial population until someone " - "produces, buys or sells in the region. Producing in the region can change the population " - "slightly; this occurs equally in all regions regardless of the presence of a settlement. " - "Buying and selling items can make a big difference to the population of the settlement. " - "Generally, there is a mimimum amount that must be traded before the settlement will grow " - "at all, and every additional bit will help it to grow more. But there is also a maximum rate " - "at which a settlement will grow, so there is no point selling more than two to three times " - "the minimum amount needed. For all growth calculations, selling a food item has double the " - "effect of selling a non-food item (such as stone), and trade items count triple when bought " - "or sold. If trade in the settlement stops, the population will gradually " - "decline over time, but will never fall below 80% of the biggest size the settlement reached. " - "Also, settlements which demand few foodstuffs (grain, livestock and fish) are easier to grow than " - "a settlement of the same size that demands more foodstuffs."; - f.Paragraph(temp); - - temp = "Q: What is the exact equation for growth of a settlement?

"; - temp += "A: Let T be the total demand for food items, multiplied by 2 (the bonus factor for food items), " - "plus the total demand and availability of trade items, multiplied by 3. " - "Let t be the total trade occuring in the settlement, given by the sum of all normal trades, " - "plus 2 times all food trades, plus 3 times all trades of 'trade items'. Let P be the population " - "of the settlement (this is slightly less than the total population of the region). Define M as " - "'P/120000 - 0.08'. If t < MT, the settlement will lose population equal to (P-Pt/MT)/20, but will " - "not drop below 80% of the greatest size the settlement has previously reached. If t > MT, the " - "city will grow by G*(1- exp(1-(t/MT)) ), where G is '3000 + P(120000-P)/24000000'."; - f.Paragraph(temp); - - temp = "Q: How many casualties will my mage's spell XXXX cause in a battle?

"; - temp += "Spell damages are generated randomly, so will always be different. However, " - "we can work out some averages for a particular spell. Summon tornado is quoted " - "as getting 2-100*lvl chances-to-attack. That is, at level 2 it gets 2-200 " - "chances-to-attack, or 101 on average. In most terrains, each chance to attack " - "has a 50% success rate, so he will on average make 50.5 attacks. In forests " - "or jungles, ranged and magic attacks suffer a -1 penalty, so the mage will " - "make 101/3 = 33.7 attacks on average.

" - "Each attack is a 'weather' attack made with skill 2. Men in the open defend " - "against magic attacks with skill 0, ie at a penalty of -2 relative to the " - "casting mage. Each attack thus has a 4:1, ie 80% chance of killing a man " - "in the open. Thus, this spell will, on average, kill about 40 men in most " - "terrains. In forests or jungles, the mage suffers a -1 skill penalty, so " - "only gets a 2:1, or 67% success rate for his 33.7 attacks, and will thus " - "kill about 22 men.

" - "Some creatures have a higher defence against weather attacks; for instance " - "skeletons have a defence of 3. Against an all-skeleton army, this mage " - "would (in normal terrain) have a 1:2 success rate, ie 33%, and would kill" - "about 50.5/3 ~ 17 skeletons. Men in towers get a +2 bonus " - "to magic defence (more if it has runewords or larger buildings), as well as the caster getting " - "a -1 penalty to chance-to-attack. So if the men in the previous example " - "were in a tower, the mage would attack for 33% (-1 penalty) of his " - "chances-to-attack, with a 50% (0 skill difference) kill rate per attack, " - "thus killing 101*0.33*0.5 ~ 17 men on average (down from 40). If these " - "fortified men were in a jungle (do this one yourself) this comes down " - "to 5.05 kills, on average."; - f.Paragraph(temp); - /* - temp = "Q: How are new dragons generated?

"; - temp += "A: You take a mummy and a daddy, and next month you have a baby ...

" - "Well, actually, dragons are flexible: you only need two dragons in a hex to produce " - "a baby, there is no worry about what sex they are. Three or four dragons will also " - "produce only one baby, but five dragons will produce two; eight dragons will produce " - "three, eleven dragons will produce four, etc. And if you have eleven dragons in your " - "territory producing babies, then you shouldn't be reading this. You should be running " - "for your life."; - f.Paragraph(temp);*/ -/* - temp = "Q: When do baby dragons become dragons?

"; - temp += "A: Twelve months after they are 'born', a baby dragon will turn into an adult " - "dragon, ready to terrorise your peasants and breed more babies. Baby dragons " - "cannot swim, so are less of a threat than adult dragons if there is ocean " - "between you and them. And don't forget - " - "away from Bashkeil, if two wandering dragons meet up, they are likely to decide " - "to wander together and merge into a single unit. Best to kill dragons while they're " - "on their own, else things can get nasty."; - f.Paragraph(temp); */ - - f.LinkRef("appendixb"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix B"); - f.TagText("h3", "Monster Table"); - - f.Paragraph(""); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Monster"); - f.TagText("th", "Movement"); - f.TagText("th", "Attacks"); - f.TagText("th", "Hits"); - f.TagText("th", "Attack Skill"); - f.TagText("th", "Defence Skill*"); - f.TagText("th", "Magic Skill"); - f.TagText("th", "Spoils**"); - f.TagText("th", "Possible Spoils"); - - f.Enclose(0, "tr"); - - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[i].type & IT_MONSTER)) continue; - if(ItemDefs[i].type & IT_ILLUSION) continue; - MonType *mp = FindMonster(ItemDefs[i].abr, 0); - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(ItemDefs[i].fly) f.PutStr("Flying"); - else if(ItemDefs[i].ride) f.PutStr("Riding"); - else f.PutStr("Foot"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(mp->numAttacks); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(mp->hits); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(mp->attackLevel); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(AString(mp->defense[ATTACK_COMBAT])+AString(mp->defense[ATTACK_RANGED]) + " " + - AString(mp->defense[ATTACK_ENERGY])+AString(mp->defense[ATTACK_SPIRIT])+AString(mp->defense[ATTACK_WEATHER])); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(mp->special == NULL) f.PutStr(" "); - else f.PutStr("Yes"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(mp->silver); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - switch(mp->spoiltype) { - case -1: - f.PutStr("Silver"); - break; - case IT_NORMAL: - //hardcoded values, could be generalised. Applies to BS modded spoils code. - if(mp->silver < 20) f.PutStr("Silver"); - else if(mp->silver < 30) f.PutStr("Silver and food items"); - else if(mp->silver < 60) f.PutStr("Silver and primary normal items"); - else f.PutStr("Silver, normal and trade items"); - break; - case IT_ADVANCED: - if(mp->silver < 100) f.PutStr("Silver"); - else if(mp->silver < 200) f.PutStr("Silver, IRWD, FLOA, MITH, ROOT, MUSH"); - else if(mp->silver < 400) f.PutStr("Silver and advanced items except DBOW, MARM"); - else if(mp->silver < 500) f.PutStr("Silver and advanced items except MARM"); - else f.PutStr("Silver and advanced items"); - break; - case IT_MAGIC: - default: - temp = "Silver"; - for(int j=0; jspoiltype)) continue; - if(ItemDefs[j].type & IT_SPECIAL) continue; - if(ItemDefs[j].baseprice > mp->silver) continue; - temp += ", "; - temp += ItemDefs[j].abr; - } - f.PutStr(temp); - break; - } - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - temp = "* The defence skill lists five numbers, against (in order) melee attacks, " - "ranged attacks, energy attacks, spirit attacks, and weather attacks."; - f.Paragraph(temp); - temp = "** Spoils are randomly generated. On average, you will get half the amount listed in " - "silver, and an amount of goods valued, by the game engine, at equal to this " - "amount (if the monster is capable of dropping goods). However, being randomly " - "generated, you may get more or less spoils than expected."; - f.Paragraph(temp); - - f.LinkRef("appendixc"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix C"); - f.TagText("h3", "Item Table"); - - f.Paragraph(""); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Abbr"); - f.TagText("th", "Item"); - f.TagText("th", "Weight (capacity)"); - f.TagText("th", "Type"); - f.TagText("th", "Skill (level)"); - f.TagText("th", "Material"); - f.TagText("th", "Months"); - f.TagText("th", "Magic Skill (level)"); - f.TagText("th", "Material"); - f.TagText("th", "Withdraw Value*"); - f.Enclose(0, "tr"); - SkillType *mS; -// int numtrade = 0; - - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if((ItemDefs[i].type & IT_MAN) || (ItemDefs[i].type & IT_MONSTER)) continue; - if(ItemDefs[i].type & IT_SPECIAL) continue; - pS = FindSkill(ItemDefs[i].pSkill); - mS = FindSkill(ItemDefs[i].mSkill); - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].abr); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = ItemDefs[i].weight; - cap = ItemDefs[i].walk - ItemDefs[i].weight; - if(ItemDefs[i].walk || (ItemDefs[i].hitchItem != -1)) { - temp += " ("; - if(ItemDefs[i].hitchItem == -1) - temp += cap; - else { - temp += (cap + ItemDefs[i].hitchwalk); - temp += " with "; - temp += ItemDefs[ItemDefs[i].hitchItem].name; - } - temp += ")"; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = " "; - int any = 0; - if(ItemDefs[i].type & IT_NORMAL) { - temp += "normal"; - any = 1; - } - if(ItemDefs[i].type & IT_ADVANCED) { - if(any) temp += ", "; - else any = 1; - temp += "advanced"; - } - if(ItemDefs[i].type & IT_MAGIC) { - if(any) temp += ", "; - else any = 1; - temp += "magic"; - } - if(ItemDefs[i].type & IT_WEAPON) { - if(any) temp += ", "; - else any = 1; - temp += "weapon"; - } - if(ItemDefs[i].type & IT_ARMOR) { - if(any) temp += ", "; - else any = 1; - temp += "armour"; - } - if(ItemDefs[i].type & IT_MOUNT) { - if(any) temp += ", "; - else any = 1; - temp += "mount"; - } - if(ItemDefs[i].type & IT_TRADE) { - if(any) temp += ", "; - else any = 1; - temp += "trade"; - } - if(ItemDefs[i].type & IT_TOOL) { - if(any) temp += ", "; - else any = 1; - temp += "tool"; - } - if(ItemDefs[i].type & IT_FOOD) { - if(any) temp += ", "; - else any = 1; - temp += "food"; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(pS != NULL) { - if(ItemDefs[i].pLevel > 1) f.PutStr(AString(pS->name) + " (" + ItemDefs[i].pLevel + ")"); - else f.PutStr(pS->name); - } else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - comma = 0; - temp = ""; - if (ItemDefs[i].flags & ItemType::ORINPUTS) - temp = "Any of : "; - for(j = 0; j < (int) (sizeof(ItemDefs->pInput) / - sizeof(ItemDefs->pInput[0])); j++) { - k = ItemDefs[i].pInput[j].item; - if(k < 0 || (ItemDefs[k].flags&ItemType::DISABLED)) - continue; - if(comma) temp += ", "; - temp += ItemDefs[i].pInput[j].amt; - temp += " "; - if(ItemDefs[i].pInput[j].amt > 1) - temp += ItemDefs[k].names; - else - temp += ItemDefs[k].name; - comma = 1; - } - if(temp == "") temp = " "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(ItemDefs[i].pMonths) { - temp = ItemDefs[i].pMonths; - } else { - temp = " "; - } - f.PutStr(temp); - f.Enclose(0, "td"); - - f.Enclose(1, "td align=\"left\" nowrap"); - if(mS != NULL) { - if(ItemDefs[i].mLevel > 1) f.PutStr(AString(mS->abbr) + " (" + ItemDefs[i].mLevel + ")"); - else f.PutStr(mS->abbr); - } else f.PutStr(" "); - f.Enclose(0, "td"); - - f.Enclose(1, "td align=\"left\" nowrap"); - comma = 0; - temp = ""; - if (ItemDefs[i].flags & ItemType::ORINPUTS) - temp = "Any of : "; - for(j = 0; j < (int) (sizeof(ItemDefs->mInput) / - sizeof(ItemDefs->mInput[0])); j++) { - k = ItemDefs[i].mInput[j].item; - if(k < 0 || (ItemDefs[k].flags&ItemType::DISABLED)) - continue; - if(comma) temp += ", "; - temp += ItemDefs[i].mInput[j].amt; - temp += " "; - if(ItemDefs[i].mInput[j].amt > 1) - temp += ItemDefs[k].names; - else - temp += ItemDefs[k].name; - comma = 1; - } - if(temp == "") temp = " "; - f.PutStr(temp); - f.Enclose(0, "td"); - - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr((ItemDefs[i].baseprice*5+1)/2); - f.Enclose(0, "td"); - - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - f.PutStr(""); - f.PutStr("* Only normal items can be WITHDRAWN, however, all items have internal values used for markets, monsters and magic spells. They are listed here for all items, whether or not they may be WITHDRAWN."); - - - f.LinkRef("appendixd"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix D"); - f.TagText("h3", "Weapon Table"); - - f.Paragraph(""); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Weapon"); - f.TagText("th", "Skill Required*"); - f.TagText("th", "Attack Type"); - f.TagText("th", "Attack Bonus"); - f.TagText("th", "Armour Piercing"); - f.TagText("th", "Num Attacks"); - - f.Enclose(0, "tr"); - int asterix = 0; - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[i].type & IT_WEAPON)) continue; - - WeaponType *pW = FindWeapon(ItemDefs[i].abr); - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(pW->flags & WeaponType::NEEDSKILL) { - pS = FindSkill(pW->baseSkill); - temp = pS->name; - pS = FindSkill(pW->orSkill); - if(pS) temp += AString(" or ") + pS->name; - } else temp = " "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - f.PutStr(AttType(pW->attackType)); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(pW->mountBonus) f.PutStr(AString(pW->attackBonus+pW->mountBonus/2) + "**"); - else f.PutStr(pW->attackBonus); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(pW->weapClass == ARMORPIERCING) f.PutStr("Yes"); - else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(pW->numAttacks == WeaponType::NUM_ATTACKS_HALF_SKILL) { - f.PutStr("half skill level***"); - asterix = 1; - } - else if(pW->numAttacks == WeaponType::NUM_ATTACKS_SKILL) f.PutStr("skill level"); - else if(pW->numAttacks > 0) f.PutStr(AString(pW->numAttacks) + " per round"); - else f.PutStr(AString("1 every ") + AString(-(pW->numAttacks)) + " rounds"); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - temp = "* If no skill is required, then the weapon bonus is added onto the unit's combat " - "skill (if any) and the unit's riding skill, if they have an appropriate mount and " - "are in appropriate terrain. If the weapon requires a longbow or crossbow skill, then " - "the wielder defends with a skill of zero. Otherwise the wielder defends with his " - "attack skill."; - f.Paragraph(temp); - /* - temp = "** This weapon provides a bonus of 4 to defence, and an average bonus of 4 to attack. However, the wielder's attack skill " - "is modified by whether or not a soldier he attacks is riding; if he is, then this weapon " - "gets a bonus of 2 (attack bonus = 6), if the target is not riding (or is a monster), then " - "there is a penalty of 2 (attack bonus = 2)."; - f.Paragraph(temp); - */ - if(asterix) { - temp = "*** Number of attacks is equal to the unit's skill level, divided by 2, and rounded up."; - f.Paragraph(temp); - } - - - - f.LinkRef("appendixe"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix E"); - f.TagText("h3", "Armour Table"); - - f.Paragraph(""); - temp = "Armour has a fixed chance to block enemy attacks against the wearer. The percentage for each " - "armour is given in the item description, rounded to the nearest percent. This table lists instead " - "the 'survivability' for each armour - that is, how many attacks are needed, on average, for one attack to " - "pass through the armour and kill the wearer (ie a '4' in the table means that there is a 1 in 4 chance " - "of an attack killing the wearer). Note that this is an average - some soldiers may survive " - "more hits than shown here, and others may die with the first hit."; - f.Paragraph(temp); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Armour"); - f.TagText("th", "Normal"); - f.TagText("th", "Armour-Piercing"); - f.TagText("th", "Magical"); - - f.Enclose(0, "tr"); - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(!(ItemDefs[i].type & IT_ARMOR)) continue; - ArmorType *at = FindArmor(ItemDefs[i].abr); - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(ItemDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(at->from == at->saves[PIERCING]) f.PutStr("infinite"); - else { - int ones = at->from / (at->from - at->saves[PIERCING]); - int tenths = (10*at->from) / (at->from - at->saves[PIERCING]); - tenths -= 10*ones; - temp = AString(ones); - if(tenths) temp += AString(".") + tenths; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(at->from == at->saves[ARMORPIERCING]) f.PutStr("infinite"); - else { - int ones = at->from / (at->from - at->saves[ARMORPIERCING]); - int tenths = (10*at->from) / (at->from - at->saves[ARMORPIERCING]); - tenths -= 10*ones; - temp = AString(ones); - if(tenths) temp += AString(".") + tenths; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"center\" nowrap"); - if(at->from == at->saves[MAGIC_ENERGY]) f.PutStr("infinite"); - else { - int ones = at->from / (at->from - at->saves[MAGIC_ENERGY]); - int tenths = (10*at->from) / (at->from - at->saves[MAGIC_ENERGY]); - tenths -= 10*ones; - temp = AString(ones); - if(tenths) temp += AString(".") + tenths; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - f.LinkRef("appendixf"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix F"); - f.TagText("h3", "Terrain Table"); - - temp = "Properties of individual regions are generated randomly, according to " - "the parameters in the table below. Note that the population and wages " - "of a region will increase if a settlement (village, town or city) " - "is present. The population of the region and of the settlement are " - "calculated separately, but you will only ever see the combined population " - "on your report. A settlement with less than 20,000 people is called a " - "village and increases wages by 1; a settlement with 20,000-39,999 people " - "is called a town and increases wages by 2, and a settlement with " - "40,000+ people is called a city and increases wages by 3. The population " - "of a region may be increased by up to 50% of its initial value due to " - "production in the region; the population of a settlement may be " - "increased through trading goods in the market."; - f.Paragraph(temp); - - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Terrain"); - f.TagText("th", "Move Cost*"); - f.TagText("th", "Population"); - f.TagText("th", "Wages"); - f.TagText("th", "Tax Income"); - f.TagText("th", "Grain/Livestock"); - f.TagText("th", "Normal Resources**"); - f.TagText("th", "Advanced Resources**"); - - - f.Enclose(0, "tr"); - for(i = 0; i < R_NUM; i++) { - if(TerrainDefs[i].flags & TerrainType::DISABLED) continue; - if(i == R_NEXUS) continue; - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(TerrainDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(TerrainDefs[i].movepoints); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = AString(TerrainDefs[i].pop*Globals->POP_LEVEL/2) + "-" + (TerrainDefs[i].pop*Globals->POP_LEVEL); - if(TerrainDefs[i].pop == 0) temp = AString('-'); - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = AString(TerrainDefs[i].wages) + "-" + (TerrainDefs[i].wages+2); - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = AString((TerrainDefs[i].wages-5)*TerrainDefs[i].pop/4) + "-" + (TerrainDefs[i].wages-3)*TerrainDefs[i].pop/2; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = AString(TerrainDefs[i].economy) + "-" + (2*TerrainDefs[i].economy-1); - if(TerrainDefs[i].economy == 0) temp = AString('-'); - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = ""; - first = 1; - for(unsigned int c = 0; c < sizeof(TerrainDefs[i].prods)/sizeof(Product); c++) { - if(TerrainDefs[i].prods[c].product > -1 && (ItemDefs[TerrainDefs[i].prods[c].product].type & IT_NORMAL)) { - if(first) first = 0; - else { - temp += ", "; - } - temp += AString(TerrainDefs[i].prods[c].amount) + "-" + (2*TerrainDefs[i].prods[c].amount-1); - temp += AString(" ") + ItemDefs[TerrainDefs[i].prods[c].product].names; - if(TerrainDefs[i].prods[c].chance != 100) temp += AString(" (") + TerrainDefs[i].prods[c].chance + "%)"; - } - } - if(first) temp = " "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = ""; - first = 1; - for(unsigned int c = 0; c < sizeof(TerrainDefs[i].prods)/sizeof(Product); c++) { - if(TerrainDefs[i].prods[c].product > -1 && !(ItemDefs[TerrainDefs[i].prods[c].product].type & IT_NORMAL)) { - if(first) first = 0; - else { - temp += ", "; - } - temp += AString(TerrainDefs[i].prods[c].amount) + "-" + (2*TerrainDefs[i].prods[c].amount-1); - temp += AString(" ") + ItemDefs[TerrainDefs[i].prods[c].product].names; - if(TerrainDefs[i].prods[c].chance != 100) temp += AString(" (") + TerrainDefs[i].prods[c].chance + "%)"; - } - } - if(first) temp = " "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - temp = "* This is the move cost for units walking, riding, or (for ocean and lakes) " - "swimming. Flying units have a cost of 1 to enter any terrain type. All units " - "have their movement cost doubled in bad weather (winter, monsoons). Units may " - "not enter a region during a blizzard. Sailing ships to the centre of any (" - "lake or ocean) region costs 2 movepoints in bad weather or 5 in a blizzard, " - "while sailing to edge terrain costs 1 in bad weather or 3 in a blizzard. Sailing " - "in good weather always costs one movement point."; - f.Paragraph(temp); - - temp = "** If a percentage is listed after a resource, then that resource is not " - "always present in that region type. The percentage listed is the approximate " - "chance of finding that resource in that terrain type."; - f.Paragraph(temp); - - f.LinkRef("appendixg"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix G"); - f.TagText("h3", "Guard Table"); - - f.PutStr("WARNING: Not updated from Arcadia III."); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Settlement"); - f.TagText("th", "Guards"); - f.TagText("th", "Armour"); - f.TagText("th", "Skills"); - f.TagText("th", "Items"); - - f.Enclose(0, "tr"); - for(i = 0; i < 7; i++) { - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - switch(i) { - case 0: f.PutStr("Village"); - break; - case 1: f.PutStr("Town"); - break; - case 2: f.PutStr("City"); - break; - case 3: f.PutStr("City (West)"); - break; - case 4: f.PutStr("City (North)"); - break; - case 5: f.PutStr("City (East)"); - break; - case 6: f.PutStr("City (South)"); - break; - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(i<3) f.PutStr(AString(20*(i+1))); - else f.PutStr(AString(1)); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(i<2) f.PutStr("none"); - else f.PutStr("leather"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(i < 3) { - temp = AString("Combat ") + (i+1) + ", Observation " + (i+2); - if(i) temp += AString(", Tactics ") + i; - f.PutStr(temp); - } else { - switch(i) { - case 3: - f.PutStr("Combat 3, Tactics 2, Fire 3"); - break; - case 4: - f.PutStr("Combat 3, Tactics 2"); - break; - case 5: - f.PutStr("Combat 3, Tactics 2, Instill Courage 3"); - break; - case 6: - f.PutStr("Combat 3, Tactics 2, Aura of Fear 2"); - break; - } - } - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = " "; - if(i == 4) { - temp = "32 wolves, 4 eagles"; - } else if(i == 5) { - temp = "100 illusory imps"; - } - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - - f.LinkRef("appendixh"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix H"); - f.TagText("h3", "Skill Table"); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Skill"); - f.TagText("th", "Study Cost"); - f.TagText("th", "Cast"); - f.TagText("th", "Combat"); - f.TagText("th", "Baseskill"); - f.TagText("th", "Requirements"); - - - f.Enclose(0, "tr"); - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(SkillDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(SkillDefs[i].cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(SkillDefs[i].flags & SkillType::CAST) f.PutStr("Yes"); - else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(SkillDefs[i].flags & SkillType::COMBAT) f.PutStr("Yes"); - else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(SkillDefs[i].baseskill == -1) f.PutStr(" "); - else f.PutStr(SkillDefs[SkillDefs[i].baseskill].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - temp = ""; - first = 1; - for(unsigned int c = 0; c < sizeof(SkillDefs[i].depends)/sizeof(SkillDepend); c++) { - if(SkillDefs[i].depends[c].skill != NULL) { - pS = FindSkill(SkillDefs[i].depends[c].skill); - if(pS && !(pS->flags & SkillType::DISABLED)) { - if(first) first = 0; - else { - temp += ", "; - } - temp += AString(pS->name) + " (" + SkillDefs[i].depends[c].level + ")"; - } - } - } - if(first) temp = " "; - f.PutStr(temp); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - - - f.LinkRef("appendixi"); - f.ClassTagText("div", "rule", ""); - f.TagText("h2", "Appendix I"); - f.TagText("h3", "Combat Skill Table"); - - f.Enclose(1, "center"); - f.Enclose(1, "table border=\"1\""); - f.Enclose(1, "tr"); - f.TagText("th", "Skill"); - f.TagText("th", "Combat Cost"); - f.TagText("th", "Type"); - f.TagText("th", "Attack Type"); - f.TagText("th", "Attacks per level"); - f.TagText("th", "Effect"); - - - f.Enclose(0, "tr"); - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) continue; - if(!(SkillDefs[i].flags & SkillType::COMBAT)) continue; - - SpecialType *spd = FindSpecial(SkillDefs[i].special); - - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(SkillDefs[i].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(AString(SkillDefs[i].combat_first) + " / " + SkillDefs[i].combat_cost); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(spd) f.PutStr(spd->specialname); - else f.PutStr(" "); - f.Enclose(0, "td"); - int type = -1; - int min = 0; - int max = 0; - if(spd) { - for(int j = 0; j < 4; j++) { - if(spd->damage[j].type != -1) { - if(type == -1) type = spd->damage[j].type; - else type = NUM_ATTACK_TYPES+1; - min += spd->damage[j].minnum; - max += spd->damage[j].value * 2; - } - } - } - f.Enclose(1, "td align=\"left\" nowrap"); - if(spd) f.PutStr(AttType(type)); - else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(spd && (min || max)) f.PutStr(AString(min) + "-" + max); - else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - if(spd && spd->damage[0].effect) { - EffectType *ep = FindEffect(spd->damage[0].effect); - f.PutStr(ep->name); - } else f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - } - //add frenzy in specially - f.Enclose(1, "tr"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(SkillDefs[S_FRENZY].name); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("passive"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("improved"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr("2-12*"); - f.Enclose(0, "td"); - f.Enclose(1, "td align=\"left\" nowrap"); - f.PutStr(" "); - f.Enclose(0, "td"); - f.Enclose(0, "tr"); - - f.Enclose(0, "table"); - f.Enclose(0, "center"); - - temp = "* Dependent on skill level, not random (ie exactly 2 at level 1, " - "up to exactly 12 per level (or 72 total) at level 6)."; - f.Paragraph(temp); - - - f.Paragraph(""); - f.Enclose(0, "body"); - f.Enclose(0, "html"); - return 1; -} diff --git a/arcadia/hexside.cpp b/arcadia/hexside.cpp deleted file mode 100644 index 642b19622..000000000 --- a/arcadia/hexside.cpp +++ /dev/null @@ -1,328 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "object.h" -#include "gamedata.h" -#include "game.h" - -int LookupHexside(AString *token) -{ - for (int i = 0; i < NHEXSIDES; i++) { - if (*token == HexsideDefs[i].name) return i; - } - return -1; -} - -int ParseHexside(AString *token) -{ - int r = -1; - for (int i=H_DUMMY+1; iPutStr(HexsideDefs[type].name); - f->PutInt(bridge); - f->PutStr(road); - f->PutInt(harbour); -} - -void Hexside::Readin(Ainfile *f) -{ - AString *temp; - - temp = f->GetStr(); - type = LookupHexside(temp); - delete temp; - - bridge = f->GetInt(); - road = f->GetInt(); /* Hexside Patch 030825 BS */ - harbour = f->GetInt(); -} - -AString *HexsideDescription(int type) -{ - if(HexsideDefs[type].flags & ObjectType::DISABLED) - return NULL; - - HexsideType *h = &HexsideDefs[type]; - AString *temp = new AString; - *temp += AString(h->name) + ": "; - *temp += "This is a terrain edge feature."; - - if(h->sailable) { - switch(h->sailable) { - case 3: *temp += " All ships"; - break; - case 2: *temp += " Deep water ships"; - break; - case 1: *temp += " Shallow water ships"; - default: - break; - } - *temp += " can sail here."; - } - - if(h->movementmultiplier) { - *temp += " The movement cost to walk or ride across this edge is"; - if(h->movementmultiplier < 0) { - *temp += AString(" decreased by ") + (-50*h->movementmultiplier) + "%, then rounded up."; - } else { - *temp += AString(" increased by ") + (50*h->movementmultiplier) + "%, rounded up."; - } - } - - if(h->blockeffect) { - if(h->blockeffect == 1) { - *temp += " This edge cannot be crossed by walking or riding units, unless a bridge is present."; - } else if(h->blockeffect > 1) { - *temp += " This edge cannot be crossed by walking or riding units."; - } else { - *temp += " This feature allows walking and riding units to cross a "; - int comma = 0; - int last = 0; - for(int i=0; istealthpen) { - *temp += " Units which cross this feature will suffer a malus of 2 to " - "their stealth rating until the next magic round."; - } - - if(h->advancepen) { - *temp += " Walking and riding units which cross this feature to fight a battle (while advancing or aiding others) " - "will suffer a malus of "; - *temp += AString(h->advancepen) + " to their attack and defence skills."; - } - - int buildable = 1; - SkillType *pS = NULL; - if(h->item == -1 || h->skill == NULL) buildable = 0; - if (buildable) pS = FindSkill(h->skill); - if (pS && (pS->flags & SkillType::DISABLED)) buildable = 0; - if(h->item != I_WOOD_OR_STONE && - (ItemDefs[h->item].flags & ItemType::DISABLED)) - buildable = 0; - if(h->item == I_WOOD_OR_STONE && - (ItemDefs[I_WOOD].flags & ItemType::DISABLED) && - (ItemDefs[I_STONE].flags & ItemType::DISABLED)) - buildable = 0; - if(!buildable) { - *temp += " This feature cannot be built by players."; - } else { - *temp += AString(" This feature is built using ") + - SkillStrs(pS) + " " + h->level + " and requires " + - h->cost + " "; - if(h->item == I_WOOD_OR_STONE) { - *temp += "wood or stone"; - } else { - *temp += ItemDefs[h->item].name; - } - *temp += " to build."; - if(type == H_ROAD) *temp += " This feature may be built on any edge between two land regions."; - if(type == H_BRIDGE) *temp += " This feature may be built on any edge containing a feature which may be bridged."; - if(type == H_HARBOUR) *temp += " This feature may only be built on a beach, and will replace the beach when completed."; - } - - return temp; -} - - -void Unit::CrossHexside(ARegion *fromreg, ARegion *toreg) -{ - if(!Globals->HEXSIDE_TERRAIN) return; - int dir = -1; - for(int i=0; ineighbors[i] == toreg) dir = i; - } - if(dir == -1) return; - Hexside *h = fromreg->hexside[dir]; - - if(HexsideDefs[h->type].stealthpen) SetFlag(FLAG_VISIB,1); - else if(h->road < 0 && HexsideDefs[H_ROAD].stealthpen) SetFlag(FLAG_VISIB,1); - else if(h->bridge < 0 && HexsideDefs[H_BRIDGE].stealthpen) SetFlag(FLAG_VISIB,1); - - if(HexsideDefs[h->type].advancepen) movementmalus += HexsideDefs[h->type].advancepen; - else if(h->road < 0) movementmalus += HexsideDefs[H_ROAD].advancepen; - else if(h->bridge < 0) movementmalus += HexsideDefs[H_BRIDGE].advancepen; -} - - -/* -void Game::SetupObjectMirrors() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - if (o->mirrornum>-1 && !(o->mirror) && r->neighbors[o->hexside]) { - forlist(&r->neighbors[o->hexside]->objects) { - Object *obj = (Object *) elem; - if(obj->num == o->mirrornum && o->num == obj->mirrornum) { - obj->mirror = o; - o->mirror = obj; - } - } - } - } - } - -} -*/ - - -/* -/* Hexside Patch 030825 BS *//* -void Game::HexsideCompatibility(ARegion *r, Object *obj) -{ -// If building a hexside object should remove any other hexside object, do it here. -/* Harbour Removes Beach *//* - if(obj->type==O_HARBOUR) { - forlist(&r->objects) { - Object *o = (Object *) elem; - if (o->hexside==obj->hexside && o->type == O_BEACH) { - if (o->mirror) o->mirror->region->objects.Remove(o->mirror); - r->objects.Remove(o); - } - } - } -} - - - -/* Hexside Patch 030825 BS *//* -int Game::HexsideCanGoThere(ARegion * r,Object * obj,Unit * u) -{ - int dir = obj->hexside; - if(!r->neighbors[dir]) return 0; - -// No hexside can have two of the same object except ships. - if(!obj->IsBoat()) { - forlist (&r->objects) { - Object *o = (Object *) elem; - if (o->type == obj->type) { - if (o->hexside == obj->hexside) { - if (o->incomplete != ObjectDefs[o->type].cost) { // is ok if structure has not been started - if (o->num != obj->num) return 0; // is ok if structure is this structure - } - } - } - } - } -/* Object Specific Stuff. May code into gamedata.cpp at some stage */ -/* Ship may be built on sailable hexside object of correct depth, or ocean ships on ocean edge*//* - if (obj->IsBoat()) { - if(TerrainDefs[r->neighbors[dir]->type].similar_type == R_OCEAN && ObjectDefs[obj->type].sailable > 1) return 1; - forlist (&r->objects) { - Object *o = (Object *) elem; - if (o->hexside == dir) { - if (!o->IsBoat() && ObjectDefs[o->type].sailable == 3) return 1; - if (!o->IsBoat() && ObjectDefs[o->type].sailable == ObjectDefs[obj->type].sailable) return 1; - if (!o->IsBoat() && ObjectDefs[o->type].sailable && ObjectDefs[obj->type].sailable == 3) return 1; - } - } - return 0; - } - - - -/* Bridge cannot go to ocean and must go over river or ravine *//* - if (obj->type == O_BRIDGE) { - if(TerrainDefs[r->neighbors[dir]->type].similar_type == R_OCEAN) return 0; - forlist (&r->objects) { - Object *o = (Object *) elem; - if (o->type == O_RIVER || O_RAVINE) { - if (o->hexside == dir) return 1; - } - } - return 0; - } -/* Road cannot go to ocean *//* - if (obj->type == O_ROAD) { - if(TerrainDefs[r->neighbors[dir]->type].similar_type == R_OCEAN) return 0; - return 1; - } -/* Wall cannot go to river edge. To do: Should not go to river mouth */ /* - if (obj->type == O_IWALL) { - forlist (&r->objects) { - Object *o = (Object *) elem; - if (o->type == O_RIVER) { - if (o->hexside == dir) return 0; - } - } - return 1; - } -/* Harbour must go on beach */ /* - if (obj->type == O_HARBOUR) { - forlist (&r->objects) { - Object *o = (Object *) elem; - if (o->type == O_BEACH) { - if (o->hexside == dir) return 1; - } - } - return 0; - } -/* Anything else should not be built */ /* -return 0; -} - - - -*/ diff --git a/arcadia/hexside.h b/arcadia/hexside.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/arcadia/html/arcadia.css b/arcadia/html/arcadia.css deleted file mode 100644 index 1777033d5..000000000 --- a/arcadia/html/arcadia.css +++ /dev/null @@ -1,18 +0,0 @@ -BODY { - font-family: arial, sans-serif; - background: black; - color: #B19275; - -} - -DIV.rule { - background: url(bar.jpg) no-repeat top; - height: 23px; - color: white; -} - -TD.fixed { font-family: monospace; } - -A:visited { color: white; } -A:active { color: white; } -A:link { color: white; } diff --git a/arcadia/html/intro.html b/arcadia/html/intro.html deleted file mode 100644 index 7b8976eb3..000000000 --- a/arcadia/html/intro.html +++ /dev/null @@ -1 +0,0 @@ -This is a test … for me, to pray that I get CVS access diff --git a/arcadia/html/styles.css b/arcadia/html/styles.css deleted file mode 100644 index 1777033d5..000000000 --- a/arcadia/html/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -BODY { - font-family: arial, sans-serif; - background: black; - color: #B19275; - -} - -DIV.rule { - background: url(bar.jpg) no-repeat top; - height: 23px; - color: white; -} - -TD.fixed { font-family: monospace; } - -A:visited { color: white; } -A:active { color: white; } -A:link { color: white; } diff --git a/arcadia/items.cpp b/arcadia/items.cpp deleted file mode 100644 index 42e533d76..000000000 --- a/arcadia/items.cpp +++ /dev/null @@ -1,1504 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include -#include "items.h" -#include "skills.h" -#include "object.h" -#include "gamedata.h" - -#ifndef DEBUG -//#define DEBUG -#endif - -BattleItemType *FindBattleItem(char *abbr) -{ - if (abbr == NULL) return NULL; - for (int i = 0; i < NUMBATTLEITEMS; i++) { - if (BattleItemDefs[i].abbr == NULL) continue; - if (AString(abbr) == BattleItemDefs[i].abbr) - return &BattleItemDefs[i]; - } - return NULL; -} - -ArmorType *FindArmor(char *abbr) -{ - if (abbr == NULL) return NULL; - for (int i = 0; i < NUMARMORS; i++) { - if (ArmorDefs[i].abbr == NULL) continue; - if (AString(abbr) == ArmorDefs[i].abbr) - return &ArmorDefs[i]; - } - return NULL; -} - -WeaponType *FindWeapon(char *abbr) -{ - if (abbr == NULL) return NULL; - for (int i = 0; i < NUMWEAPONS; i++) { - if (WeaponDefs[i].abbr == NULL) continue; - if (AString(abbr) == WeaponDefs[i].abbr) - return &WeaponDefs[i]; - } - return NULL; -} - -MountType *FindMount(char *abbr) -{ - if (abbr == NULL) return NULL; - for (int i = 0; i < NUMMOUNTS; i++) { - if (MountDefs[i].abbr == NULL) continue; - if (AString(abbr) == MountDefs[i].abbr) - return &MountDefs[i]; - } - return NULL; -} - -MonType *FindMonster(char *abbr, int illusion) -{ - if (abbr == NULL) return NULL; - AString tag = (illusion ? "i" : ""); - tag += abbr; - - for (int i = 0; i < NUMMONSTERS; i++) { - if (MonDefs[i].abbr == NULL) continue; - if (tag == MonDefs[i].abbr) - return &MonDefs[i]; - } - return NULL; -} - -ManType *FindRace(char *abbr) -{ - if (abbr == NULL) return NULL; - for (int i = 0; i < NUMMAN; i++) { - if (ManDefs[i].abbr == NULL) continue; - if (AString(abbr) == ManDefs[i].abbr) - return &ManDefs[i]; - } - return NULL; -} - -AString EthnicityString(int type) -{ - switch(type) { - case RA_HUMAN: return AString("Human"); - case RA_ELF: return AString("Elvish"); - case RA_DWARF: return AString("Dwarven"); - case RA_OTHER: return AString("Independent"); - case RA_NA: return AString("Chaotic"); - default: return AString("Buggy"); - } -} - -AString AttType(int atype) -{ - switch(atype) { - case ATTACK_COMBAT: return AString("melee"); - case ATTACK_ENERGY: return AString("energy"); - case ATTACK_SPIRIT: return AString("spirit"); - case ATTACK_WEATHER: return AString("weather"); - case ATTACK_RIDING: return AString("riding"); - case ATTACK_RANGED: return AString("ranged"); - case NUM_ATTACK_TYPES: return AString("non-resistable"); - default: return AString("unknown"); - } -} - -static AString DefType(int atype) -{ - if(atype == NUM_ATTACK_TYPES) return AString("all"); - return AttType(atype); -} - -int LookupItem(AString *token) -{ - for(int i = 0; i < NITEMS; i++) { - if (ItemDefs[i].type & IT_ILLUSION) { - if (*token == (AString("i") + ItemDefs[i].abr)) return i; - } else { - if (*token == ItemDefs[i].abr) return i; - } - } - return -1; -} - -int ParseAllItems(AString *token) -{ - int r = -1; - for(int i = 0; i < NITEMS; i++) { - if (ItemDefs[i].type & IT_ILLUSION) { - if ((*token == (AString("i") + ItemDefs[i].name)) || - (*token == (AString("i") + ItemDefs[i].names)) || - (*token == (AString("i") + ItemDefs[i].abr))) { - r = i; - break; - } - } else { - if ((*token == ItemDefs[i].name) || - (*token == ItemDefs[i].names) || - (*token == ItemDefs[i].abr)) { - r = i; - break; - } - } - } - return r; -} - -int ParseEnabledItem(AString *token) -{ - int r = -1; - for (int i=0; ipInput)/sizeof(Materials); c++) { - int i = ItemDefs[item].pInput[c].item; - if(i != -1) return 0; - } - return 1; -} - -AString ItemString(int type, int num, int flags, int unitclass) -{ - AString temp; - if (num == 1) { - if (flags & FULLNUM) - temp += AString(num) + " "; - if((ItemDefs[type].type & IT_MAN) && unitclass != U_NORMAL) { - temp += ItemDefs[type].name; - switch(unitclass) { - case U_SPECIALIST: - temp += " specialist"; - break; - case U_LEADER: - temp += " leader"; - break; - case U_MAGE: - case U_GUARDMAGE: - temp += " hero"; - break; - } - temp += AString(" [") + ItemDefs[type].abr + "]"; - } else { - temp += - AString((flags & ALWAYSPLURAL) ? - ItemDefs[type].names: ItemDefs[type].name) + - " [" + ItemDefs[type].abr + "]"; - } - } else { - if (num == -1) { - temp += AString("unlimited ") + ItemDefs[type].names + " [" + - ItemDefs[type].abr + "]"; - } else { - if((ItemDefs[type].type & IT_MAN) && unitclass != U_NORMAL && unitclass != U_GUARD) { - temp += AString(num) + " " + ItemDefs[type].name; - switch(unitclass) { - case U_SPECIALIST: - temp += " specialists"; - break; - case U_LEADER: - temp += " leaders"; - break; - case U_MAGE: - case U_GUARDMAGE: - temp += " heros"; - break; - } - temp += AString(" [") + ItemDefs[type].abr + "]"; - } else { - temp += AString(num) + " " + ItemDefs[type].names + " [" + - ItemDefs[type].abr + "]"; - } - } - } - return temp; -} - -AString EffectStr(char *effect) -{ - AString temp, temp2; - int comma = 0; - int i; - - EffectType *ep = FindEffect(effect); - - temp += ep->name; - - if(ep->attackVal) { - temp2 += AString(ep->attackVal) + " to attack"; - comma = 1; - } - - for(i = 0; i < 4; i++) { - if(ep->defMods[i].type == -1) continue; - if(comma) temp2 += ", "; - temp2 += AString(ep->defMods[i].val) + " versus " + - DefType(ep->defMods[i].type) + " attacks"; - comma = 1; - } - - if(comma) { - temp += AString(" (") + temp2 + ")"; - } - - if(comma) { - if(ep->flags & EffectType::EFF_ONESHOT) { - temp += " until the end of the combat round"; //Arcadia battle combat mod. - } else { - temp += " for the rest of the battle"; - } - } - temp += "."; - - if(ep->cancelEffect != NULL) { - if(comma) temp += " "; - EffectType *up = FindEffect(ep->cancelEffect); - temp += AString("This effect cancels out the effects of ") + - up->name + "."; - } - return temp; -} - -AString ShowSpecial(char *special, int level, int expandLevel, int fromItem) -{ - AString temp; - int comma = 0; - int i; - int last = -1; - int val; - - SpecialType *spd = FindSpecial(special); - temp += spd->specialname; - temp += AString(" in battle"); - if(expandLevel) - temp += AString(" at a skill level of ") + level; - temp += "."; - if (fromItem) - temp += " This spell only affects the possessor of the item."; //BS mod, ability changed to spell. - - if((spd->targflags & SpecialType::HIT_BUILDINGIF) || - (spd->targflags & SpecialType::HIT_BUILDINGEXCEPT)) { - temp += " This ability will "; - if(spd->targflags & SpecialType::HIT_BUILDINGEXCEPT) { - temp += "not "; - } else { - temp += "only "; - } - - temp += "target units which are inside the following structures: "; - for(i = 0; i < 3; i++) { - if(spd->buildings[i] == -1) continue; - if(ObjectDefs[spd->buildings[i]].flags & ObjectType::DISABLED) - continue; - if(last == -1) { - last = i; - continue; - } - temp += AString(ObjectDefs[spd->buildings[last]].name) + ", "; - last = i; - comma++; - } - if(comma) { - temp += "or "; - } - temp += AString(ObjectDefs[spd->buildings[last]].name) + "."; - } - if((spd->targflags & SpecialType::HIT_SOLDIERIF) || - (spd->targflags & SpecialType::HIT_SOLDIEREXCEPT) || - (spd->targflags & SpecialType::HIT_MOUNTIF) || - (spd->targflags & SpecialType::HIT_MOUNTEXCEPT)) { - temp += " This ability will "; - if((spd->targflags & SpecialType::HIT_SOLDIEREXCEPT) || - (spd->targflags & SpecialType::HIT_MOUNTEXCEPT)) { - temp += "not "; - } else { - temp += "only "; - } - temp += "target "; - if((spd->targflags & SpecialType::HIT_MOUNTIF) || - (spd->targflags & SpecialType::HIT_MOUNTEXCEPT)) { - temp += "units mounted on "; - } - comma = 0; - last = -1; - for(i = 0; i < 7; i++) { - if(spd->targets[i] == -1) continue; - if(ItemDefs[spd->targets[i]].flags & ItemType::DISABLED) continue; - if(last == -1) { - last = i; - continue; - } - temp += ItemString(spd->targets[last], 1, ALWAYSPLURAL) + ", "; - last = i; - comma++; - } - if(comma) { - temp += "or "; - } - temp += ItemString(spd->targets[last], 1, ALWAYSPLURAL) + "."; - } - if((spd->targflags & SpecialType::HIT_EFFECTIF) || - (spd->targflags & SpecialType::HIT_EFFECTEXCEPT)) { - temp += " This ability will "; - if(spd->targflags & SpecialType::HIT_EFFECTEXCEPT) { - temp += "not "; - } else { - temp += "only "; - } - temp += "target creatures which are currently affected by "; - EffectType *ep; - for(i = 0; i < 3; i++) { - if(spd->effects[i] == NULL) continue; - if(last == -1) { - last = i; - continue; - } - ep = FindEffect(spd->effects[last]); - temp += AString(ep->name) + ", "; - last = i; - comma++; - } - if(comma) { - temp += "or "; - } - ep = FindEffect(spd->effects[last]); - temp += AString(ep->name) + "."; - } - if(spd->targflags & SpecialType::HIT_ILLUSION) { - temp += " This ability will only target illusions."; - } - if(spd->targflags & SpecialType::HIT_NOMONSTER) { - temp += " This ability cannot target monsters."; - } - if(spd->targflags & SpecialType::HIT_MONSTEREXCEPT) { - temp += " This ability will only target monsters other than "; - comma = 0; - last = -1; - for(i = 0; i < 7; i++) { - if(spd->targets[i] == -1) continue; - if(ItemDefs[spd->targets[i]].flags & ItemType::DISABLED) continue; - if(last == -1) { - last = i; - continue; - } - temp += ItemString(spd->targets[last], 1, ALWAYSPLURAL) + ", "; - last = i; - comma++; - } - if(comma) { - temp += "or "; - } - temp += ItemString(spd->targets[last], 1, ALWAYSPLURAL) + "."; - } - if(spd->targflags & SpecialType::HIT_OWN_ARMY) { - temp += " This ability target's the caster's own army."; - } - if(spd->effectflags & SpecialType::FX_NOBUILDING) { - temp += AString(" The bonus given to units inside buildings is ") + - "not effective against this ability."; - } - - if(spd->effectflags & SpecialType::FX_SHIELD) { - if(!fromItem) temp += " This ability provides a shield against all "; - else temp += AString(" This spell provides the wielder with a defence bonus of ") + level + " against all "; - comma = 0; - last = -1; - for(i = 0; i < 4; i++) { - if(spd->shield[i] == -1) continue; - if(last == -1) { - last = i; - continue; - } - temp += DefType(spd->shield[last]) + ", "; - last = i; - comma++; - } - if(comma) { - temp += "and "; - } - if(fromItem) temp += DefType(spd->shield[last]) + " attacks."; - else { - temp += DefType(spd->shield[last]) + " attacks against the entire" + - " army at a level equal to the skill level of the ability."; - if(Globals->ARCADIA_MAGIC) temp += " If this shield is destroyed, " - "the casting mage will lose an extra point of energy."; - } - } - if(spd->effectflags & SpecialType::FX_DEFBONUS) { - temp += " This ability provides "; - comma = 0; - last = -1; - for(i = 0; i < 4; i++) { - if(spd->defs[i].type == -1) continue; - if(last == -1) { - last = i; - continue; - } - val = spd->defs[last].val; - if(expandLevel) { - if(spd->effectflags & SpecialType::FX_USE_LEV) - val *= level; - } - - temp += AString("a defensive bonus of ") + val; - if(!expandLevel) { - temp += " per skill level"; - } - temp += AString(" versus ") + DefType(spd->defs[last].type) + - " attacks, "; - last = i; - comma++; - } - if(comma) { - temp += "and "; - } - val = spd->defs[last].val; - if(expandLevel) { - if(spd->effectflags & SpecialType::FX_USE_LEV) - val *= level; - } - temp += AString("a defensive bonus of ") + val; - if(!expandLevel) { - temp += " per skill level"; - } - temp += AString(" versus ") + DefType(spd->defs[last].type) + - " attacks"; - temp += " to the casting mage."; - } - - /* Now the damages */ - int damages = 0; - for(i = 0; i < 4; i++) { - if(spd->damage[i].type == -1) continue; - damages = 1; - temp += AString(" A mage with this ability gets between ") + - spd->damage[i].minnum + " and "; - val = spd->damage[i].value * 2; - if(expandLevel) { - if(spd->effectflags & SpecialType::FX_USE_LEV) - val *= level; - } - temp += AString(val); - if(!expandLevel) { - temp += " times the skill level of the mage"; - } - temp += AString(" chances-to-attack with a ") + AttType(spd->damage[i].type) + " attack."; - if(spd->damage[i].effect) { - temp += " Each successful attack causes the target to be effected by "; - temp += EffectStr(spd->damage[i].effect); - } - } - if(damages) temp += " For every chance-to-attack, the mage has a 50% chance, under normal " - "conditions, of making an attack. This chance may be modified by some " - "terrains, defensive structures, spells or formation maneuvres."; - - return temp; -} - -static AString MonResist(int type, int val, int full) -{ - AString temp = "This monster "; - if(full) { - temp += AString("has a resistance of ") + val; - } else { - temp += "is "; - if(val < 1) temp += "very susceptible"; - else if(val == 1) temp += "susceptible"; - else if(val > 1 && val < 3) temp += "typically resistant"; - else if(val > 2 && val < 5) temp += "slightly resistant"; - else temp += "very resistant"; - } - temp += " to "; - temp += AttType(type); - temp += " attacks."; - return temp; -} - -static AString WeapClass(int wclass) -{ - switch(wclass) { - case SLASHING: return AString("slashing"); - case PIERCING: return AString("piercing"); - case CRUSHING: return AString("crushing"); - case CLEAVING: return AString("cleaving"); - case ARMORPIERCING: return AString("armour-piercing"); - case MAGIC_ENERGY: return AString("energy"); - case MAGIC_SPIRIT: return AString("spirit"); - case MAGIC_WEATHER: return AString("weather"); - default: return AString("unknown"); - } -} - -static AString WeapType(int flags, int wclass) -{ - AString type; - if(flags & WeaponType::RANGED) type = "ranged"; - if(flags & WeaponType::LONG) type = "long"; - if(flags & WeaponType::SHORT) type = "short"; - type += " "; - type += WeapClass(wclass); - return type; -} - -AString *ItemDescription(int item, int full) -{ - int i; - AString skname; - SkillType *pS; - - if(ItemDefs[item].flags & ItemType::DISABLED) - return NULL; - - AString *temp = new AString; - int illusion = (ItemDefs[item].type & IT_ILLUSION); - - *temp += AString(illusion?"illusory ":"")+ ItemDefs[item].name + " [" + - (illusion?"I":"") + ItemDefs[item].abr + "], weight " + - ItemDefs[item].weight; - - if (ItemDefs[item].walk) { - int cap = ItemDefs[item].walk - ItemDefs[item].weight; - if(cap) { - *temp += AString(", walking capacity ") + cap; - } else { - *temp += ", can walk"; - } - } - if((ItemDefs[item].hitchItem != -1 )&& - !(ItemDefs[ItemDefs[item].hitchItem].flags & ItemType::DISABLED)) { - int cap = ItemDefs[item].walk - ItemDefs[item].weight + - ItemDefs[item].hitchwalk; - if(cap) { - *temp += AString(", walking capacity ") + cap + - " when hitched to a " + - ItemDefs[ItemDefs[item].hitchItem].name; - } - } - if (ItemDefs[item].ride) { - int cap = ItemDefs[item].ride - ItemDefs[item].weight; - if(cap) { - *temp += AString(", riding capacity ") + cap; - } else { - *temp += ", can ride"; - } - } - if (ItemDefs[item].swim) { - int cap = ItemDefs[item].swim - ItemDefs[item].weight; - if(cap) { - *temp += AString(", swimming capacity ") + cap; - } else { - *temp += ", can swim"; - } - } - if (ItemDefs[item].fly) { - int cap = ItemDefs[item].fly - ItemDefs[item].weight; - if(cap) { - *temp += AString(", flying capacity ") + cap; - } else { - *temp += ", can fly"; - } - } - - if(Globals->ALLOW_WITHDRAW) { - if(ItemDefs[item].type & IT_NORMAL && item != I_SILVER) { - *temp += AString(", costs ") + (ItemDefs[item].baseprice*5/2) + - " silver to withdraw"; - } - } - *temp += "."; - - if(ItemDefs[item].type & IT_MAN) { - ManType *mt = FindRace(ItemDefs[item].abr); - int found = 0; - *temp += " This race may study "; - if(mt->speciallevel != mt->defaultlevel) { - unsigned int c; - unsigned int len = sizeof(mt->skills) / sizeof(mt->skills[0]); - for(c = 0; c < len; c++) { - pS = FindSkill(mt->skills[c]); - if (!pS || (pS->flags & SkillType::DISABLED)) continue; - if(found) *temp += ", "; - if(found && c == len - 1) *temp += "and "; - found = 1; - *temp += SkillStrs(pS); - } - if(found) { - *temp += AString(" to level ") + mt->speciallevel + - " and all others to level " + mt->defaultlevel + "."; - } else { - *temp += AString("all skills to level ") + mt->defaultlevel + "."; - } - } else { - *temp += AString("all skills to level ") + mt->defaultlevel + "."; - } - - if(Globals->REAL_EXPERIENCE) { - found = 0; - if(mt->specialexperlevel == mt->defaultexperlevel) *temp += AString(" This race may also gain ") + mt->defaultexperlevel + " levels in all skills due to experience."; - else { - //this will be wrong in the case of different levels, but no skills found. - *temp += AString(" This race may also gain ") + mt->specialexperlevel + " levels due to experience in "; - unsigned int c; - unsigned int len = sizeof(mt->skills) / sizeof(mt->skills[0]); - for(c = 0; c < len; c++) { - pS = FindSkill(mt->skills[c]); - if (!pS || (pS->flags & SkillType::DISABLED)) continue; - if(found) *temp += ", "; - if(found && c == len - 1) *temp += "and "; - found = 1; - *temp += SkillStrs(pS); - } - if(!found) *temp += "no skills"; - *temp += AString(", and ") + mt->defaultexperlevel + - " level due to experience in all other skills."; - } - } - } - if(ItemDefs[item].type & IT_MONSTER) { - *temp += " This is a monster."; - MonType *mp = FindMonster(ItemDefs[item].abr, - (ItemDefs[item].type & IT_ILLUSION)); - *temp += AString(" This monster attacks with a combat skill of ") + - mp->attackLevel + "."; - for(int c = 0; c < NUM_ATTACK_TYPES; c++) { - *temp += AString(" ") + MonResist(c,mp->defense[c], full); - } - if(mp->special && mp->special != NULL) { - *temp += AString(" ") + - "Monster can cast " + - ShowSpecial(mp->special, mp->specialLevel, 1, 0); - } - if(full) { - int hits = mp->hits; - int atts = mp->numAttacks; - int regen = mp->regen; - if(!hits) hits = 1; - if(!atts) atts = 1; - *temp += AString(" This monster has ") + atts + " melee " + - ((atts > 1)?"attacks":"attack") + " per round and takes " + - hits + " " + ((hits > 1)?"hits":"hit") + " to kill."; - if (regen > 0) { - *temp += AString(" This monsters regenerates ") + regen + - " hits per round of battle."; - } - *temp += AString(" This monster has a tactics score of ") + - mp->tactics + ", a stealth score of " + mp->stealth + - ", and an observation score of " + mp->obs + "."; - } - if((ItemDefs[item].type & IT_UNDEAD) && Globals->MAGE_UNDEAD_INVINCIBLE ) { - *temp += " When controlled by a hero, this monster has a "; - *temp += AString(Globals->MAGE_UNDEAD_INVINCIBLE) + "% chance of " - "coming back to life following a battle in which it is slain."; - } - - if(mp->silver) { - *temp += " This monster might have "; - if(mp->spoiltype != -1) { - if(mp->spoiltype & IT_MAGIC) { - *temp += "magic items and "; - } else if(mp->spoiltype & IT_ADVANCED) { - *temp += "advanced items and "; - } else if(mp->spoiltype & IT_NORMAL) { - *temp += "normal or trade items and "; - } - } - *temp += "silver as treasure."; - } - } - - if(ItemDefs[item].type & IT_WEAPON) { - WeaponType *pW = FindWeapon(ItemDefs[item].abr); - *temp += " This is a "; - *temp += WeapType(pW->flags, pW->weapClass) + " weapon."; - if(pW->flags & WeaponType::NEEDSKILL) { - pS = FindSkill(pW->baseSkill); - if (pS) { - *temp += AString(" Knowledge of ") + SkillStrs(pS); - pS = FindSkill(pW->orSkill); - if(pS) - *temp += AString(" or ") + SkillStrs(pS); - *temp += " is needed to wield this weapon."; - } - } else - *temp += " No skill is needed to wield this weapon."; - - int flag = 0; - if(pW->attackBonus != 0) { - *temp += " This weapon grants a "; - *temp += ((pW->attackBonus > 0) ? "bonus of " : "penalty of "); - *temp += abs(pW->attackBonus); - *temp += " on attack"; - flag = 1; - } - if(pW->defenseBonus != 0) { - if(flag) { - if(pW->attackBonus == pW->defenseBonus) { - *temp += " and defense."; - flag = 0; - } else { - *temp += " and a "; - } - } else { - *temp += " This weapon grants a "; - flag = 1; - } - if(flag) { - *temp += ((pW->defenseBonus > 0)?"bonus of ":"penalty of "); - *temp += abs(pW->defenseBonus); - *temp += " on defense."; - flag = 0; - } - } - if(flag) *temp += "."; - if(pW->mountBonus && full) { - *temp += " This weapon "; - if(pW->attackBonus != 0 || pW->defenseBonus != 0) - *temp += "also "; - *temp += "grants a "; - *temp += ((pW->mountBonus > 0)?"bonus of ":"penalty of "); - *temp += abs(pW->mountBonus); - *temp += " against mounted opponents."; - } - - if(pW->flags & WeaponType::NOFOOT) - *temp += " Only mounted troops may use this weapon."; - else if(pW->flags & WeaponType::NOMOUNT) - *temp += " Only foot troops may use this weapon."; - - if(pW->flags & WeaponType::RIDINGBONUS) { - *temp += " Wielders of this weapon, if mounted, get their riding " - "skill bonus on combat attack and defense."; - } else if(pW->flags & WeaponType::RIDINGBONUSDEFENSE) { - *temp += " Wielders of this weapon, if mounted, get their riding " - "skill bonus on combat defense."; - } - - if(pW->flags & WeaponType::NODEFENSE) { - *temp += " Defenders are treated as if they have an " - "effective combat skill of 0."; - } - - if(pW->flags & WeaponType::NOATTACKERSKILL) { - *temp += " Attackers do not get skill bonus on defense."; - } - - if(pW->flags & WeaponType::ALWAYSREADY) { - *temp += " Wielders of this weapon never miss a round to ready " - "their weapon."; - } else { - *temp += " There is a 50% chance that the wielder of this weapon " - "gets a chance to attack in any given round."; - } - - if(full) { - int atts = pW->numAttacks; - *temp += AString(" This weapon attacks versus the target's ") + - "defense against " + AttType(pW->attackType) + " attacks."; - *temp += AString(" This weapon allows "); - if(atts > 0) { - if(atts >= WeaponType::NUM_ATTACKS_HALF_SKILL) { - int max = WeaponType::NUM_ATTACKS_HALF_SKILL; - char *attd = "half the skill level (rounded up)"; - if(atts >= WeaponType::NUM_ATTACKS_SKILL) { - max = WeaponType::NUM_ATTACKS_SKILL; - attd = "the skill level"; - } - *temp += "a number of attacks equal to "; - *temp += attd; - *temp += " of the attacker"; - int val = atts - max; - if(val > 0) *temp += AString(" plus ") + val; - } else { - *temp += AString(atts) + ((atts==1)?" attack ":" attacks"); - } - *temp += " per round."; - } else { - atts = -atts; - *temp += "1 attack every "; - if(atts == 1) *temp += "round ."; - else *temp += AString(atts) + " rounds."; - } - } - } - - if(ItemDefs[item].type & IT_ARMOR) { - *temp += " This is a type of armour."; - ArmorType *pA = FindArmor(ItemDefs[item].abr); - *temp += " This armour will protect its wearer "; - for(i = 0; i < NUM_WEAPON_CLASSES; i++) { - if(i == NUM_WEAPON_CLASSES - 1) { - *temp += ", and "; - } else if(i > 0) { - *temp += ", "; - } - int percent = (int)(((float)pA->saves[i]*100.0) / - (float)pA->from+0.5); - *temp += AString(percent) + "% of the time versus " + - WeapClass(i) + " attacks"; - } - *temp += "."; - - if(pA->flags & ArmorType::ONLYONEHIT) { - *temp += " The wearer of this armour will be killed by a single successful attack, " - "even if they would usually have multiple hitpoints."; - } - -// if(full) { - if(pA->flags & ArmorType::USEINASSASSINATE) { - *temp += " This armour may be worn during assassination " - "attempts."; - } - if(pA->flags & ArmorType::DEFINASSASSINATE) { - *temp += " This armour may be worn by the victim during an assassination " - "attempt."; - } -// } - } - - if(ItemDefs[item].type & IT_TOOL) { - int comma = 0; - int last = -1; - *temp += " This is a tool."; - *temp += " This item increases the production of "; - for(i = NITEMS - 1; i > 0; i--) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(ItemDefs[i].mult_item == item) { - last = i; - break; - } - } - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(ItemDefs[i].mult_item == item) { - if(comma) { - if(last == i) { - if(comma > 1) *temp += ","; - *temp += " and "; - } else { - *temp += ", "; - } - } - comma++; - if(i == I_SILVER) { - *temp += "entertainment"; - } else { - *temp += ItemString(i, 1); - } - *temp += AString(" by ") + ItemDefs[i].mult_val; - } - } - *temp += "."; - } - - if(ItemDefs[item].type & IT_TRADE) { - *temp += " This is a trade good."; - if(full) { - if(Globals->RANDOM_ECONOMY) { - int maxbuy, minbuy, maxsell, minsell; - if(Globals->MORE_PROFITABLE_TRADE_GOODS) { - minsell = (ItemDefs[item].baseprice*250)/100; - maxsell = (ItemDefs[item].baseprice*350)/100; - minbuy = (ItemDefs[item].baseprice*100)/100; - maxbuy = (ItemDefs[item].baseprice*190)/100; - } else { - minsell = (ItemDefs[item].baseprice*150)/100; - maxsell = (ItemDefs[item].baseprice*200)/100; - minbuy = (ItemDefs[item].baseprice*100)/100; - maxbuy = (ItemDefs[item].baseprice*150)/100; - } - *temp += AString(" This item can be bought for between ") + - minbuy + " and " + maxbuy + " silver."; - *temp += AString(" This item can be sold for between ") + - minsell+ " and " + maxsell+ " silver."; - } else { - *temp += AString(" This item can be bought and sold for ") + - ItemDefs[item].baseprice + " silver."; - } - } - } - - if(ItemDefs[item].type & IT_MOUNT) { - *temp += " This is a mount."; - MountType *pM = FindMount(ItemDefs[item].abr); - if(pM->skill == NULL) { - *temp += " No skill is required to use this mount."; - } else { - pS = FindSkill(pM->skill); - if (!pS || (pS->flags & SkillType::DISABLED)) - *temp += " This mount is unridable."; - else { - *temp += AString(" This mount requires ") + - SkillStrs(pS) + " of at least level " + pM->minBonus + - " to ride in combat."; - } - } - *temp += AString(" This mount gives a minimum bonus of +") + - pM->minBonus + " when ridden into combat."; - *temp += AString(" This mount gives a maximum bonus of +") + - pM->maxBonus + " when ridden into combat."; - if(full) { - if(ItemDefs[item].fly) { - *temp += AString(" This mount gives a maximum bonus of +") + - pM->maxHamperedBonus + " when ridden into combat in " + - "terrain which allows ridden mounts but not flying "+ - "mounts."; - } - if(pM->mountSpecial != NULL) { - *temp += AString(" When ridden, this mount causes ") + - ShowSpecial(pM->mountSpecial, pM->specialLev, 1, 0); - } - } - } - - if(item == I_HEALPOTION) { - *temp += AString(" This item may be used by any unit to attempt to heal up " - "to ") + Globals->HEALS_PER_MAN + " men at the end of any battle " - "which is won."; - } - - pS = FindSkill(ItemDefs[item].pSkill); - if(pS && !(pS->flags & SkillType::DISABLED)) { - unsigned int c; - unsigned int len; - *temp += AString(" Units with ") + SkillStrs(pS) + - " of at least level " + ItemDefs[item].pLevel + " may PRODUCE "; - if (ItemDefs[item].flags & ItemType::SKILLOUT) - *temp += "a number of this item equal to their skill level"; - else - *temp += "this item"; - len = sizeof(ItemDefs[item].pInput)/sizeof(Materials); - int count = 0; - int tot = len; - for(c = 0; c < len; c++) { - int itm = ItemDefs[item].pInput[c].item; - int amt = ItemDefs[item].pInput[c].amt; - if(itm == -1 || ItemDefs[itm].flags & ItemType::DISABLED) { - tot--; - continue; - } - if(count == 0) { - *temp += " from "; - if (ItemDefs[item].flags & ItemType::ORINPUTS) - *temp += "any of "; - } else if (count == tot) { - if(c > 1) *temp += ","; - *temp += " and "; - } else { - *temp += ", "; - } - count++; - *temp += ItemString(itm, amt); - } - if(ItemDefs[item].pOut) { - *temp += AString(" at a rate of ") + ItemDefs[item].pOut; - if(ItemDefs[item].pMonths) { - if(ItemDefs[item].pMonths == 1) { - *temp += " per man-month."; - } else { - *temp += AString(" per ") + ItemDefs[item].pMonths + - " man-months."; - } - } - } - } - - pS = FindSkill(ItemDefs[item].mSkill); - if(pS && !(pS->flags & SkillType::DISABLED)) { - unsigned int c; - unsigned int len; - *temp += AString(" Units with ") + SkillStrs(pS) + - " of at least level " + ItemDefs[item].mLevel + - " may attempt to create this item via magic"; - len = sizeof(ItemDefs[item].mInput)/sizeof(Materials); - int count = 0; - int tot = len; - for(c = 0; c < len; c++) { - int itm = ItemDefs[item].mInput[c].item; - int amt = ItemDefs[item].mInput[c].amt; - if(itm == -1 || ItemDefs[itm].flags & ItemType::DISABLED) { - tot--; - continue; - } - if(count == 0) { - *temp += " at a cost of "; - } else if (count == tot) { - if(c > 1) *temp += ","; - *temp += " and "; - } else { - *temp += ", "; - } - count++; - *temp += ItemString(itm, amt); - } - *temp += "."; - } - - if((ItemDefs[item].type & IT_BATTLE) && full) { - *temp += " This item is a miscellaneous combat item."; - BattleItemType *bt = FindBattleItem(ItemDefs[item].abr); - if(bt != NULL) { - if(bt->flags & BattleItemType::MAGEONLY) { - *temp += " This item may only be used by a mage"; - if(Globals->APPRENTICES_EXIST) { - *temp += " or an apprentice"; - } - *temp += "."; - } - if(bt->flags & BattleItemType::SPECIAL || bt->flags & BattleItemType::SHIELD) { - *temp += AString(" ") + "This item can cast " + - ShowSpecial(bt->special, bt->skillLevel, 1, 1); - } - if(bt->flags & BattleItemType::ENERGY) { - *temp += AString(" ") + "This item allows the " - "wielder to cast combat spells in battle without " - "draining their own energy supply."; - } - } - } - if((ItemDefs[item].flags & ItemType::CANTGIVE) && full) { - *temp += " This item cannot be given to other units."; - } - - if ((ItemDefs[item].max_inventory) && full) { - *temp += AString(" A unit may have at most ") + - ItemString(item, ItemDefs[item].max_inventory, FULLNUM) + "."; - } - - return temp; -} - -int IsSoldier(int item) -{ - if (ItemDefs[item].type & IT_MAN || ItemDefs[item].type & IT_MONSTER) - return 1; - return 0; -} - -Item::Item() -{ - selling = 0; -} - -Item::~Item() -{ -} - -AString Item::Report(int seeillusions, int unitclass) -{ - AString ret = ItemString(type,num, 0, unitclass); - if (seeillusions && (ItemDefs[type].type & IT_ILLUSION)) { - ret = ret + " (illusion)"; - } - return ret; -} - -void Item::Writeout(Aoutfile *f) -{ - AString temp; - if (type != -1) { - temp = AString(num) + " "; - if(ItemDefs[type].type & IT_ILLUSION) temp += "i"; - temp += ItemDefs[type].abr; - - } else temp = "-1 NO_ITEM"; - f->PutStr(temp); -} - -void Item::Readin(Ainfile *f) -{ - AString *temp = f->GetStr(); - AString *token = temp->gettoken(); - num = token->value(); - delete token; - token = temp->gettoken(); - type = LookupItem(token); - delete token; - delete temp; -} - -void ItemList::Writeout(Aoutfile *f) -{ - f->PutInt(Num()); - forlist (this) ((Item *) elem)->Writeout(f); -} - -void ItemList::Readin(Ainfile *f) -{ - int i = f->GetInt(); - for (int j=0; jReadin(f); - if (temp->num < 1) delete temp; - else Add(temp); - } -} - -int ItemList::GetNum(int t) -{ - forlist(this) { - Item *i = (Item *) elem; - if (i->type == t) return i->num; - } - return 0; -} - -int ItemList::Weight() -{ - int wt = 0; - int frac = 0; - forlist(this) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].weight == 0) frac += i->num; - else wt += ItemDefs[i->type].weight * i->num; - } - if (Globals->FRACTIONAL_WEIGHT > 0 && frac != 0) - wt += (frac/Globals->FRACTIONAL_WEIGHT); - return wt; -} - -int ItemList::CanSell(int t) -{ - forlist(this) { - Item *i = (Item *)elem; - if (i->type == t) return i->num - i->selling; - } - return 0; -} - -void ItemList::Selling(int t, int n) -{ - forlist(this) { - Item *i = (Item *)elem; - if (i->type == t) i->selling += n; - } -} - -AString ItemList::Report(int obs,int seeillusions,int nofirstcomma, int unitclass) -{ - AString temp; - for (int s = 0; s < 7; s++) { - temp += ReportByType(s, obs, seeillusions, nofirstcomma, unitclass); - if (temp.Len()) nofirstcomma = 0; - } - return temp; -} - -AString ItemList::BattleReport(int unitclass) -{ - AString temp; - forlist(this) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].combat) { - temp += ", "; - temp += i->Report(0, unitclass); - if (ItemDefs[i->type].type & IT_MONSTER) { - MonType *mp = FindMonster(ItemDefs[i->type].abr, 0); // BS mod so illusory creatures look "normal" - if(!mp) mp = FindMonster(ItemDefs[i->type].abr, (ItemDefs[i->type].type & IT_ILLUSION)); - temp += AString(" (Combat ") + mp->attackLevel + - "/" + mp->defense[ATTACK_COMBAT] + ", Attacks " + - mp->numAttacks + ", Hits " + mp->hits + - ", Tactics " + mp->tactics + ")"; - } - } - } - return temp; -} - -AString ItemList::ReportByType(int type, int obs, int seeillusions, - int nofirstcomma, int unitclass) -{ - AString temp; - forlist(this) { - int report = 0; - Item *i = (Item *) elem; - switch (type) { - case 0: - if (ItemDefs[i->type].type & IT_MAN) - report = 1; - break; - case 1: - if (ItemDefs[i->type].type & IT_MONSTER) - report = 1; - break; - case 2: - if ((ItemDefs[i->type].type & IT_WEAPON) || - (ItemDefs[i->type].type & IT_BATTLE) || - (ItemDefs[i->type].type & IT_ARMOR) || - (ItemDefs[i->type].type & IT_MAGIC)) - report = 1; - break; - case 3: - if (ItemDefs[i->type].type & IT_MOUNT) - report = 1; - if ((ItemDefs[i->type].type & IT_WEAPON) || - (ItemDefs[i->type].type & IT_BATTLE) || - (ItemDefs[i->type].type & IT_ARMOR) || - (ItemDefs[i->type].type & IT_MAGIC)) - report = 0; //don't rerun these if something is both (eg carpets) - break; - case 4: - if ((i->type == I_WAGON) || (i->type == I_MWAGON)) - report = 1; - break; - case 5: - report = 1; - if (ItemDefs[i->type].type & IT_MAN) - report = 0; - if (ItemDefs[i->type].type & IT_MONSTER) - report = 0; - if (i->type == I_SILVER) - report = 0; - if ((ItemDefs[i->type].type & IT_WEAPON) || - (ItemDefs[i->type].type & IT_BATTLE) || - (ItemDefs[i->type].type & IT_ARMOR) || - (ItemDefs[i->type].type & IT_MAGIC)) - report = 0; - if (ItemDefs[i->type].type & IT_MOUNT) - report = 0; - if ((i->type == I_WAGON) || - (i->type == I_MWAGON)) - report = 0; - break; - case 6: - if (i->type == I_SILVER) - report = 1; - } - if (report) { - if (obs == 2) { - if (nofirstcomma) nofirstcomma = 0; - else temp += ", "; - temp += i->Report(seeillusions, unitclass); - } else { - if (ItemDefs[i->type].weight) { - if (nofirstcomma) nofirstcomma = 0; - else temp += ", "; - temp += i->Report(seeillusions, unitclass); - } - } - } - } - return temp; -} - -void ItemList::SetNum(int t,int n) -{ -#ifdef DEBUG - if(t<0 || t >= NITEMS) { - Awrite("Item out of bounds."); - system("pause"); - return; - } -#endif - if (n) { - forlist(this) { - Item *i = (Item *) elem; - if (i->type == t) { - i->num = n; - return; - } - } - Item *i = new Item; - i->type = t; - i->num = n; - Add(i); - } else { - forlist(this) { - Item *i = (Item *) elem; - if (i->type == t) { - Remove(i); - delete i; - return; - } - } - } -} - -int ManType::CanProduce(int item) -{ - if(ItemDefs[item].flags & ItemType::DISABLED) return 0; - for (unsigned int i=0; i<(sizeof(skills)/sizeof(skills[0])); i++) { - if(skills[i] == NULL) continue; - if(ItemDefs[item].pSkill == skills[i]) return 1; - } - return 0; -} - -int ManType::CanUse(int item) -{ - if(ItemDefs[item].flags & ItemType::DISABLED) return 0; - // Check if the item is a mount - if(ItemDefs[item].type & IT_MOUNT) return 1; - - // Check if the item is a weapon - if(ItemDefs[item].type & IT_WEAPON) { - WeaponType *weapon = FindWeapon(ItemDefs[item].abr); - for (unsigned int i=0; i<(sizeof(skills)/sizeof(skills[0])); i++) { - if(skills[i] == NULL) continue; - if((weapon->baseSkill == skills[i]) - || (weapon->orSkill == skills[i])) return 1; - } - } - // Check if the item is an armor - if(ItemDefs[item].type & IT_ARMOR) { - ArmorType *armor = FindArmor(ItemDefs[item].abr); - int p = armor->from / armor->saves[3]; - if(p > 4) { - // puny armor not used by combative races - int mayWearArmor = 1; - for (unsigned int i=0; i<(sizeof(skills)/sizeof(skills[0])); i++) { - if(skills[i] == NULL) continue; - if(FindSkill(skills[i]) == FindSkill("COMB")) - mayWearArmor = 0; - } - if(mayWearArmor) return 1; - } else - if(p > 3) return 1; - else { - // heavy armor not be worn by sailors and sneaky races - int mayWearArmor = 1; - for (unsigned int i=0; i<(sizeof(skills)/sizeof(skills[0])); i++) { - if(skills[i] == NULL) continue; - if((FindSkill(skills[i]) == FindSkill("SAIL")) - || (FindSkill(skills[i]) == FindSkill("HUNT")) - || (FindSkill(skills[i]) == FindSkill("STEA")) - || (FindSkill(skills[i]) == FindSkill("LBOW"))) - mayWearArmor = 0; - } - if(mayWearArmor) return 1; - } - } - // Check if the item is a tool - for(int i=0; iChance / from - // - int from; - int saves[NUM_WEAPON_CLASSES]; -}; - -extern ArmorType *ArmorDefs; - -class MountType -{ - public: - char *abbr; - - // - // This is the skill needed to use this mount. - // - char *skill; - - // - // This is the minimum bonus (and minimal skill level) for this mount. - // - int minBonus; - - // - // This is the maximum bonus this mount will grant. - // - int maxBonus; - - // - // This is the max bonus a mount will grant if it can normally fly - // but the region doesn't allow flying mounts - int maxHamperedBonus; - - // If the mount has a special effect it generates when ridden in - // combat - char *mountSpecial; - int specialLev; -}; - -extern MountType *MountDefs; - -class BattleItemType -{ - public: - char *abbr; - - enum { - MAGEONLY = 0x1, - SPECIAL = 0x2, - SHIELD = 0x4, - ENERGY = 0x8 //currently only works if the item is also a weapon. - }; - - int flags; - char *special; - int skillLevel; -}; - -extern BattleItemType *BattleItemDefs; - -extern int ParseGiveableItem(AString *); -extern int ParseAllItems(AString *); -extern int ParseEnabledItem(AString *); -extern int ParseTransportableItem(AString *); -extern int LookupItem(AString *); -extern int IsPrimary(int item); - -extern BattleItemType *FindBattleItem(char *abbr); -extern ArmorType *FindArmor(char *abbr); -extern WeaponType *FindWeapon(char *abbr); -extern MountType *FindMount(char *abbr); -extern MonType *FindMonster(char *abbr, int illusion); -extern ManType *FindRace(char *abbr); -extern AString AttType(int atype); -extern AString EffectStr(char *effect); -extern AString EthnicityString(int atype); - -enum { - FULLNUM = 0x01, - ALWAYSPLURAL = 0x02 -}; -extern AString ItemString(int type, int num, int flags=0, int unitclass=0); //unit class should be set to U_NORMAL -extern AString *ItemDescription(int item, int full); - -extern int IsSoldier(int); - -class Item : public AListElem -{ - public: - Item(); - ~Item(); - - void Readin(Ainfile *); - void Writeout(Aoutfile *); - - AString Report(int, int); - - int type; - int num; - int selling; -}; - -class ItemList : public AList -{ - public: - void Readin(Ainfile *); - void Writeout(Aoutfile *); - - AString Report(int, int, int, int unitclass = 0); - AString BattleReport(int unitclass = 0); - AString ReportByType(int, int, int, int, int); - - int Weight(); - int GetNum(int); - void SetNum(int, int); /* type, number */ - int CanSell(int); - void Selling(int, int); /* type, number */ -}; - -extern AString ShowSpecial(char *special, int level, int expandLevel, - int fromItem); - -#endif diff --git a/arcadia/magic.cpp b/arcadia/magic.cpp deleted file mode 100644 index d54d31e5a..000000000 --- a/arcadia/magic.cpp +++ /dev/null @@ -1,629 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "game.h" -#include "gamedata.h" -#include "unit.h" - -int Unit::AgeDead() -{ -//delete non-magic skills - forlist(&skills) { - Skill *sk = (Skill *) elem; - if(!(SkillDefs[sk->type].flags & SkillType::MAGIC)) { - skills.Remove(sk); - delete sk; - } - } - int decays = getrandom(skills.Num()); - forlist_reuse(&skills) { - Skill *sk = (Skill *) elem; - if(decays == 0) { - if(sk->experience) { - if(sk->experience > 30) sk->experience -= 30; //sk->experience is an unsigned int so can't subtract 30 if less than 30. - else sk->experience = 0; - } else { - if(sk->days > 30) sk->days -= 30; - else { - skills.Remove(sk); - delete sk; - } - } - } - decays--; - } - - if(dead != 1 && !getrandom(5)) dead = 1; //this converts dead from factionnum (>1) to 1 with 20% chance per turn ... time lag of factional "loyalty" - - return skills.Num(); //>=1 stays undead, 0 disappears -} - -int Unit::MaxEnergy() -{ - int energi = 0; - - forlist(&skills) { - Skill *sk = (Skill *) elem; - if(SkillDefs[sk->type].flags & SkillType::FOUNDATION) { - int level = GetLevelByDays(sk->days,sk->experience) - resurrects; - if(level <= 0) continue; - energi += level * level; - if(IsASpeciality(sk->type)) { - energi += level * level; - } - } - } - //just in case: - if(energi<0) energy = 0; - return energi; -} - -int Unit::EnergyRecharge() -{ - int energi = 0; - - forlist(&skills) { - Skill *sk = (Skill *) elem; - if(SkillDefs[sk->type].flags & SkillType::FOUNDATION) { - int level = GetLevelByDays(sk->days,sk->experience) - resurrects; - if(level>0) energi += level; - if(IsASpeciality(sk->type)) energi += level; - } - } - - int inner = GetSkill(S_INNER_STRENGTH); - if(inner) { - energi *= (20 + inner); // 5% bonus - energi /= 20; - energi += inner; - Experience(S_INNER_STRENGTH, 3); //gets divided by 2 for non-specialists in the experience() code. - } - - if(mastery) { - energi += (energi+4)/10; //10% rounded to nearest integer. - } - //hardcoded maintenance values follow. - - //first, portal maintenance. - //note, that it is possible for a mage to use energy in a battle between the movement phase and the - //maintenance phase, thus potentially ending with negative energy here without losing portals. To avoid this, - //all energy checks in the battle code should use the method Unit::GetEnergy rather than accessing - //unit->energy directly. -//for consistency, the cost here must match the cost in Unit::GetEnergy(). These could perhaps be combined into a new method. - if(transferred > 0) { - int skill = GetSkill(S_CREATE_PORTAL); - if(skill < 1) skill = 1; - int cost = (transferred + 40 * skill - 1) / (40 * skill); - energi -= cost; - transferred = 0; - } - - //creature maintenance - energi -= EnergyMaintenance(energy + energi); - - return energi; -} - -int Unit::EnergyMaintenance(int maxallowed) -{ - float maxmaintenance = (float) maxallowed; - float energycost; - int illusions = items.GetNum(I_IRAT) + items.GetNum(I_IWOLF) + items.GetNum(I_ISKELETON) + items.GetNum(I_IIMP) + 10*(items.GetNum(I_IEAGLE) + items.GetNum(I_IDEMON) + - items.GetNum(I_IUNDEAD)) + 40*(items.GetNum(I_IGRYFFIN) + items.GetNum(I_ILICH) + items.GetNum(I_IBALROG)) + 80*items.GetNum(I_IDRAGON); - - energycost = (float) illusions/80; - energycost *= (float) (11 - GetSkill(S_ILLUSORY_CREATURES))/10; - if(energycost > maxmaintenance) { - Event("Does not have enough energy to maintain his illusions, which are dispelled"); - energycost = 0; - for(int i=0; i0) Experience(S_ILLUSORY_CREATURES, experience); - - // 5 per balrog. - int monsters = items.GetNum(I_BALROG); - float monstercost = (float) 5 * monsters; - monstercost *= (float) (11 - GetSkill(S_SUMMON_BALROG))/10; - experience = (int) (monstercost + 0.99); - if(monstercost + energycost > maxmaintenance) { - //don't want to create a wandering monster, because it allows for aimed balrog - //missiles. Better to just have the random escape chance, so people cannot control - //when they escape (short of forgetting the spell). - Event("Does not have enough energy to control his balrogs, which return whence they came."); - items.SetNum(I_BALROG,0); - experience = 0; - } else energycost += monstercost; - if(experience) Experience(S_SUMMON_BALROG, experience); - - // 3 per gryffin unless the spell is free to cast! - if(SkillDefs[S_GRYFFIN_LORE].cast_cost) { - monsters = items.GetNum(I_GRYFFIN); - monstercost = (float) 3 * monsters; - monstercost *= (float) (11 - GetSkill(S_GRYFFIN_LORE))/10; - experience = (int) (monstercost + 0.99); - if(monstercost + energycost > maxmaintenance) { - Event("Does not have enough energy to control his gryffins, which fly back to their home."); - items.SetNum(I_GRYFFIN,0); - experience = 0; - } else energycost += monstercost; - if(experience) Experience(S_GRYFFIN_LORE, experience); - } - //liches/undead/skeletons/wolves/eagles/dragons are free, because their cost is built into their recruitment cost. - - // 1 per demon - monsters = items.GetNum(I_DEMON); - monstercost = (float) monsters; - monstercost *= (float) (11 - GetSkill(S_SUMMON_DEMON))/10; - experience = (int) (monstercost + 0.99); - if(monstercost + energycost > maxmaintenance) { - Event("Does not have enough energy to control his demons, which return whence they came."); - items.SetNum(I_DEMON,0); - } else energycost += monstercost; - if(experience) Experience(S_SUMMON_DEMON, experience); - - // 1 per 10 imps - monsters = items.GetNum(I_IMP); - monstercost = (float) monsters / 10; - monstercost *= (float) (11 - GetSkill(S_SUMMON_IMPS))/10; - experience = (int) (2*monstercost + 0.99); - if(monstercost + energycost > maxmaintenance) { - Event("Does not have enough energy to control his imps, which return whence they came."); - items.SetNum(I_IMP,0); - } else energycost += monstercost; - if(experience) Experience(S_SUMMON_IMPS, experience); - - energycost += 0.99; //round up - - if(items.GetNum(I_WOLF)) Experience(S_WOLF_LORE,getrandom(3)); - if(items.GetNum(I_EAGLE)) Experience(S_BIRD_LORE,getrandom(3)); - if(items.GetNum(I_SKELETON)) Experience(S_NECROMANCY,getrandom(3)); - if(items.GetNum(I_UNDEAD)) Experience(S_RAISE_UNDEAD,getrandom(3)); - if(items.GetNum(I_LICH)) Experience(S_SUMMON_LICH,getrandom(3)); - - return (int) energycost; -} - -int Unit::MysticEvent() -{ - return 0; -/* //flat 33% chance of not getting an event (else mysticism is unattractive). - if(!getrandom(3)) return 0; - if(!Globals->ARCADIA_MAGIC) return 0; - - if(getrandom(MaxEnergy()) >= MysticEnergy() ) return 0; - - if(speciality == S_BASE_MYSTICISM && getrandom(2)) return 0; - //mystics are less likely to get mystic events - int mystic = GetSkill(S_BASE_MYSTICISM); - if(getrandom(mystic+5) > 5) return 0; //0% chance at level 1 to 45% chance at level 6. - - int chance = getrandom(100); - if(speciality != S_BASE_MYSTICISM) mystic -= 4; - - if(chance >= (60 - (mystic/2))) return 1; // most likely 38-43% - else if(chance >= (30 - mystic)) return 2; // 28-33% - else if(chance >= (10 - (mystic/2))) return 3; //17-22% - return 4; // least likely 7-12% -*/ -} - -void Game::RechargeMages() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if(u->type == U_MAGE) { - u->energy += u->EnergyRecharge(); - int maxenergy = u->MaxEnergy(); - if (u->energy > maxenergy) u->energy = maxenergy; - } - } - } - } -} - -void Game::SinkLandRegions() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - if (r->willsink) { - r->willsink--; - if(!r->willsink) { - AString temp = r->ShortPrint(®ions) + " has sunk beneath the ocean."; - SpecialError(r, temp); - r->Event("All land sunk beneath the ocean."); - r->SinkRegion(®ions); - } - } - } -} - -void Game::DistributeFog() -{ -//no allowance is made to check which of two casters of fog has higher level, as long as both are higher than the clearskies -//level of the region. This only needs to change if ever level 1 fog has an effect different to level 2 fog. - - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if(u->foggy) { - int fogskill = u->GetSkill(S_FOG); - if(fogskill == 0) fogskill = 1; //eg if backfire makes it follow someone else. - if(fogskill > r->clearskies) r->fog = fogskill - r->clearskies; - - if(u->foggy>1) { - //large casting - if(u->foggy > 2 && r->neighbors[u->foggy-3]) { - //centred on neighbouring region - if(fogskill > r->neighbors[u->foggy-3]->clearskies) - r->neighbors[u->foggy-3]->fog = fogskill - r->neighbors[u->foggy-3]->clearskies; - for(int k=0; k<6; k++) { - if(!r->neighbors[u->foggy-3]->neighbors[k]) continue; - if(fogskill > r->neighbors[u->foggy-3]->neighbors[k]->clearskies) - r->neighbors[u->foggy-3]->neighbors[k]->fog = fogskill - r->neighbors[u->foggy-3]->neighbors[k]->clearskies; - } - } else { - //centred on this region - for(int k=0; k<6; k++) { - if(!r->neighbors[k]) continue; - if(fogskill > r->neighbors[k]->clearskies) - r->neighbors[k]->fog = fogskill - r->neighbors[k]->clearskies; - } - } - } - } - } - } - } -} - -int Unit::GetCastCost(int skill, int extracost, int multiplier, int levelpenalty) -{ -//this needs to match the cost in the skillshows.cpp file. - - float cost = (float) SkillDefs[skill].cast_cost; - cost *= multiplier; - if(SkillDefs[skill].flags & SkillType::COSTVARIES) { - float leveleffect = (float) (2 + GetSkill(skill) - levelpenalty ) / 3; - cost /= leveleffect; - } - -/* if(extracost) { //This makes the second spell cost 50% more, the 3rd 100% more, etc. - cost = ((2+extracost)*cost)/2; - }*/ - - cost += 0.99; //round up. - - return (int) cost; -} - -int Unit::GetCombatCost(int skill, int multiplier) -{ - int cost = SkillDefs[skill].combat_cost; - cost *= multiplier; - - return cost; -} - -int Unit::GetFirstCombatCost(int skill, int multiplier) -{ - int cost = SkillDefs[skill].combat_first; - cost *= multiplier; - - return cost; -} - -void Game::GenerateVolcanic(ARegion *r) -{ - if( getrandom(10) ) return; - if(r->zloc != 1) return; - if(TerrainDefs[r->type].similar_type != R_OCEAN) return; - - ARegion *centre = regions.GetRegion( (regions.GetRegionArray(1)->x)/2, (regions.GetRegionArray(1)->y)/2, 1 ); - if(regions.GetDistance(centre,r) > 5) return; -/* - float maxx = regions.GetRegionArray(1)->x; - float maxy = regions.GetRegionArray(1)->y; - float top = (float) r->xloc - maxx/2; - float radiusx = top / maxx; - top = (float) r->yloc - maxy/2; - float radiusy = top / maxy; - float radius = radiusx*radiusx + radiusy*radiusy; - - if( radius > (float) 1/36 ) return; - //we are in a circle from the centre, radius one-third of the way to the edge. In total this is about 1/10th of the map. -*/ - - - - r->OceanToLand(); - for(int i=0; i<6; i++) { - Hexside *h = r->hexside[i]; - if(h->type == H_BEACH || h->type == H_HARBOUR) { - if(getrandom(100) < 15) h->type = H_ROCKS; //volcanic area has more rocks than usual. - } - } - - int type = getrandom(4); - - switch(type) { - case 0: - case 1: - r->type = R_MOUNTAIN; - break; - case 2: - r->type = R_SWAMP; - break; - case 3: - r->type = R_PLAIN; - break; - } - r->town = NULL; - - SpecialError(r, r->ShortPrint(®ions) + " rises out of the ocean."); - r->Event("Rises out of the ocean"); - r->SetName("Volcanic Island"); - - r->products.DeleteAll(); - r->SetupProds(); - - r->markets.DeleteAll(); - - r->population = 0; - r->basepopulation = 0; - r->wages = 0; - r->maxwages = 0; - r->money = 0; - r->willsink = 1 + getrandom(3); -} - - -/* Need to incorporate energy into unit report. Need to get energy recharging each turn. - -*/ - -void Game::SpecialErrors(ARegion *r) -{ - int sinking = 1; - if(r->willsink == 0 || r->willsink > 6) sinking = 0; - int foggy = r->fog; - if(foggy < 0) foggy = 0; //shouldn't be needed, but just in case. - int blizzard = 0; - if(r->weather == W_BLIZZARD && !r->clearskies) blizzard = 1; - if(sinking + foggy + blizzard == 0) return; - - - AString sinkstr = r->ShortPrint(®ions) + " will sink in " + r->willsink + " month"; - if(r->willsink > 1) sinkstr += "s"; - sinkstr += "."; - - AString fogstr = r->ShortPrint(®ions) + " is covered in fog, obscuring our view of other units."; - AString blizstr = r->ShortPrint(®ions) + " experienced an unnatural blizzard last month."; - - forlist(&r->objects) { - Object *o1 = (Object *) elem; - forlist(&o1->units) { - Unit *u1 = (Unit *) elem; - int first = 1; - int found = 0; - forlist(&r->objects) { - Object *o2 = (Object *) elem; - forlist(&o2->units) { - Unit *u2 = (Unit *) elem; - if(u2 == u1) { - found = 1; - break; - } else if(u2->faction == u1->faction) { - found = 1; - first = 0; - break; - } - } - if(found) break; - } - if(first) { - if(sinking) u1->Message(sinkstr); - if(foggy) u1->Message(fogstr); - if(blizzard) u1->Message(blizstr); - } - } - } -} - -void Game::SpecialError(ARegion *r, AString message, Faction *fac) -{ - forlist(&r->objects) { - Object *o1 = (Object *) elem; - forlist(&o1->units) { - Unit *u1 = (Unit *) elem; - if(u1->faction == fac) continue; - int first = 1; - int found = 0; - forlist(&r->objects) { - Object *o2 = (Object *) elem; - forlist(&o2->units) { - Unit *u2 = (Unit *) elem; - if(u2 == u1) { - found = 1; - break; - } else if(u2->faction == u1->faction) { - found = 1; - first = 0; - break; - } - } - if(found) break; - } - if(first) u1->Message(message); - } - } -} - -void Unit::WanderingExperience(int message) -{ - if(!Globals->ARCADIA_MAGIC) return; - if(type != U_MAGE) return; - if(dead) return; - - int skill = -1; - int options = 0; - for(int i=0; iIsNPC()) continue; - f->ethnicity = RA_NA; //in "chaos" - } - - forlist_reuse(®ions) { - ARegion *reg = (ARegion *)elem; - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - if(u->flags & FLAG_COMMANDER) { - if(u->faction->ethnicity == RA_NA) u->faction->ethnicity = u->GetEthnicity(); - else u->SetFlag(FLAG_COMMANDER,0); - } - } - } - } - - forlist_reuse(&factions) { - Faction *f = (Faction *) elem; - if(f->IsNPC()) continue; - if(f->ethnicity == RA_NA) { //in "chaos" - WorldEvent *event = new WorldEvent; - event->type = WorldEvent::CONVERSION; - event->fact1 = f->num; - event->fact2 = f->ethnicity; - event->reportdelay = 0; - worldevents.Add(event); - } - } -} - -void Game::SetupGuardsmenAttitudes() -{ - for(int i=0; i<4; i++) { - Faction *Guardfac; - switch(i) { - case 0: Guardfac = GetFaction(&factions, guardfaction); - break; - case 1: Guardfac = GetFaction(&factions, elfguardfaction); - break; - case 2: Guardfac = GetFaction(&factions, dwarfguardfaction); - break; - case 3: Guardfac = GetFaction(&factions, independentguardfaction); - break; - } - - Guardfac->attitudes.DeleteAll(); - - forlist(&factions) { - Faction *f = (Faction *) elem; - if(f->ethnicity != Guardfac->ethnicity) Guardfac->SetAttitude(f->num,A_UNFRIENDLY); - } - } -} - -//-------------------------- -//Quest stuff -//-------------------------- - -void Game::ResolveExits(ARegion *reg, Unit *u) -{ - Awrite("Reseeding Random Number Generator"); - if(!u) return; - seedrandom(u->num); -} - -void ARegionList::AddQuestLevel(int xSize, int ySize, char *name, int type) -//Note: this is not functional yet. -{ - int level = ++numLevels; - ARegionArray **pRegionArraysNew = new ARegionArray *[numLevels]; - for(int i=0; i<=numLevels-1; i++) { - pRegionArraysNew[i]=pRegionArrays[i]; - } - pRegionArrays = pRegionArraysNew; //memory loss here, how do I clear up the old one? - - - MakeRegions(level, xSize, ySize); - - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_QUEST; - - SetRegTypes(pRegionArrays[level], type); - - MakeUWMaze(pRegionArrays[level]); - - AddHexsides(pRegionArrays[level]); -// if (Globals->HEXSIDE_TERRAIN) AddBeaches(pRegionArrays[level]); - - CheckHexsides(pRegionArrays[level]); - FinalSetup(pRegionArrays[level]); -} diff --git a/arcadia/main.cpp b/arcadia/main.cpp deleted file mode 100644 index 221732738..000000000 --- a/arcadia/main.cpp +++ /dev/null @@ -1,188 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2000/MAR/14 Larry Stanbery Added a unit:faction map capability. -#include "gamedefs.h" -#include "game.h" -#include "items.h" -#include "skills.h" -#include "gamedata.h" - -void usage() -{ - Awrite("atlantis new"); - Awrite("atlantis run"); - Awrite("atlantis edit"); - Awrite(""); - Awrite("atlantis map "); - Awrite("atlantis mapunits"); - Awrite("atlantis genrules "); - Awrite(""); - Awrite("atlantis check "); -} - -int main(int argc, char *argv[]) -{ - Game game; - - initIO(); - - Awrite(AString("Atlantis Engine Version: ") + - ATL_VER_STRING(CURRENT_ATL_VER)); - Awrite(AString(Globals->RULESET_NAME) + ", Version: " + - ATL_VER_STRING(Globals->RULESET_VERSION)); - Awrite(""); - - if (argc == 1) { - usage(); - doneIO(); - return 0; - } - - game.ModifyTablesPerRuleset(); - - do { - if (AString(argv[1]) == "new") { - if(!game.NewGame()) { - Awrite( "Couldn't make the new game!" ); - break; - } - - if( !game.SaveGame() ) { - Awrite( "Couldn't save the game!" ); - break; - } - - if( !game.WritePlayers() ) { - Awrite( "Couldn't write the players file!" ); - break; - } - } else if (AString(argv[1]) == "stats") { - if( !game.OpenGame() ) { - Awrite( "Couldn't open the game file!" ); - break; - } - - if( !game.RunStatistics() ) { - Awrite( "Couldn't run the game file!" ); - break; - } - } else if (AString(argv[1]) == "map") { - if(argc != 4) { - usage(); - break; - } - - if( !game.OpenGame() ) { - Awrite( "Couldn't open the game file!" ); - break; - } - - if( !game.ViewMap( argv[2], argv[3] )) { - Awrite( "Couldn't write the map file!" ); - break; - } - } else if (AString(argv[1]) == "run") { - if( !game.OpenGame() ) { - Awrite( "Couldn't open the game file!" ); - break; - } - - if( !game.RunGame() ) { - Awrite( "Couldn't run the game!" ); - break; - } - - if( !game.SaveGame() ) { - Awrite( "Couldn't save the game!" ); - break; - } - } else if (AString(argv[1]) == "edit") { - if( !game.OpenGame() ) { - Awrite( "Couldn't open the game file!" ); - break; - } - - int saveGame = 0; - if( !game.EditGame( &saveGame ) ) { - Awrite( "Couldn't edit the game!" ); - break; - } - - if( saveGame ) { - if( !game.SaveGame() ) { - Awrite( "Couldn't save the game!" ); - break; - } - } - } else if( AString( argv[1] ) == "check" ) { - if(argc != 4) { - usage(); - break; - } - if(!Globals->ARCADIAN_CHECKER) { - game.DummyGame(); - if( !game.DoOrdersCheck( argv[ 2 ], argv[ 3 ] )) { - Awrite( "Couldn't check the orders!" ); - break; - } - } else { - - Awrite("Opening the game"); - if( !game.OpenGame() ) { - Awrite( "Couldn't open the game file!" ); - break; - } - - if( !game.DoOrdersCheckAll( argv[ 2 ], argv[ 3 ] )) { - Awrite( "Couldn't check the orders!" ); - break; - } - - } - } else if( AString( argv[1] ) == "mapunits" ) { - if( !game.OpenGame() ) { - Awrite( "Couldn't open the game file!" ); - break; - } - game.UnitFactionMap(); - } else if(AString(argv[1])== "genrules") { - if(argc != 5) { - usage(); - break; - } - if(!game.GenRules(argv[4], argv[3], argv[2])) { - Awrite("Unable to generate rules!"); - break; - } - } - } while( 0 ); - - doneIO(); - Awrite("Done."); - return 0; -} diff --git a/arcadia/map.cpp b/arcadia/map.cpp deleted file mode 100644 index ed7350d91..000000000 --- a/arcadia/map.cpp +++ /dev/null @@ -1,1501 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include -#include -#include "game.h" -#include "gamedata.h" - -#ifndef DEBUG -//#define DEBUG -#endif - -int ARegion::CheckSea(int dir, int range, int remainocean) -{ - if (type != R_OCEAN) return 0; - if (range-- < 1) return 1; - for (int d2 = -1; d2< 2; d2++) { - int direc = (dir + d2 + NDIRS) % NDIRS; - ARegion *newregion = neighbors[direc]; - if (!newregion) continue; - remainocean += newregion->CheckSea(dir, range, remainocean); - if (remainocean) break; - } - return remainocean; -} - - -void ARegionList::CreateAbyssLevel(int level, char *name) -{ - MakeRegions(level, 4, 4); - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_NEXUS; - - ARegion *reg = NULL; - for(int x = 0; x < 4; x++) { - for(int y = 0; y < 4; y++) { - reg = pRegionArrays[level]->GetRegion(x, y); - if(!reg) continue; - reg->SetName("Abyssal Plains"); - reg->type = R_DESERT; - reg->wages = -2; - } - } - - AddHexsides(pRegionArrays[level]); - - int tempx, tempy; - if(Globals->GATES_EXIST) { - int gateset = 0; - do { - tempx = getrandom(4); - tempy = getrandom(4); - reg = pRegionArrays[level]->GetRegion(tempx, tempy); - if(reg) { - gateset = 1; - numberofgates++; - reg->gate = -1; - } - } while(!gateset); - } - - FinalSetup(pRegionArrays[level]); - - ARegion *lair = NULL; - do { - tempx = getrandom(4); - tempy = getrandom(4); - lair = pRegionArrays[level]->GetRegion(tempx, tempy); - } while(!lair || lair == reg); - Object *o = new Object(lair); - o->num = lair->buildingseq++; - o->name = new AString(AString(ObjectDefs[O_BKEEP].name)+" ["+o->num+"]"); - o->type = O_BKEEP; - o->incomplete = 0; - o->inner = -1; - lair->objects.Add(o); -} - - -void ARegionList::CreateNexusLevel(int level, int xSize, int ySize, char *name) -{ - MakeRegions(level, xSize, ySize); - AddHexsides(pRegionArrays[level]); - - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_NEXUS; - - AString nex_name = Globals->WORLD_NAME; - nex_name += " Nexus"; - int x, y; - for(y = 0; y < ySize; y++) { - for(x = 0; x < xSize; x++) { - ARegion *reg = pRegionArrays[level]->GetRegion(x, y); - if(reg) { - reg->SetName(nex_name.Str()); - reg->type = R_NEXUS; - } - } - } - - FinalSetup(pRegionArrays[level]); - for(y = 0; y < ySize; y++) { - for(int x = 0; x < xSize; x++) { - ARegion *reg = pRegionArrays[level]->GetRegion(x, y); - if(reg && Globals->NEXUS_IS_CITY && Globals->TOWNS_EXIST) { - reg->MakeStartingCity(); - if(Globals->GATES_EXIST) { - numberofgates++; - } - } - } - } -} - -void ARegionList::CreateSurfaceLevel(int level, int xSize, int ySize, char *name) -{ - MakeRegions(level, xSize, ySize); - - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_SURFACE; - int sea = Globals->OCEAN; - if(Globals->SEA_LIMIT) - sea = sea * (100 + 2 * Globals->SEA_LIMIT) / 100; - - MakeLand(pRegionArrays[level], sea, Globals->CONTINENT_SIZE); - - CleanUpWater(pRegionArrays[level]); - - SetupAnchors(pRegionArrays[level]); - - GrowTerrain(pRegionArrays[level], 0); - - AssignTypes(pRegionArrays[level]); - - SeverLandBridges(pRegionArrays[level]); - - if (Globals->LAKES) RemoveCoastalLakes(pRegionArrays[level]); - - if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); - - FinalSetup(pRegionArrays[level]); - - AddHexsides(pRegionArrays[level]); - - if (Globals->HEXSIDE_TERRAIN) { - AddBeaches(pRegionArrays[level]); - if(!(HexsideDefs[H_RIVER].flags & HexsideType::DISABLED) ) AddRivers(pRegionArrays[level]); // Need to put in a check in case rivers are not enabled - } - -} - -void ARegionList::CreateIslandLevel(int level, int nPlayers, char *name) -{ - int xSize, ySize; - xSize = 20 + (nPlayers + 3) / 4 * 6 - 2; - ySize = xSize; - - MakeRegions(level, xSize, ySize); - - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_SURFACE; - - MakeCentralLand(pRegionArrays[level]); - MakeIslands(pRegionArrays[level], nPlayers); - RandomTerrain(pRegionArrays[level]); - - if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); - - AddHexsides(pRegionArrays[level]); - - if (Globals->HEXSIDE_TERRAIN) AddBeaches(pRegionArrays[level]); - FinalSetup(pRegionArrays[level]); -} - -void ARegionList::CreateUnderworldLevel(int level, int xSize, int ySize, - char *name) -{ - MakeRegions(level, xSize, ySize); - - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_UNDERWORLD; - - SetRegTypes(pRegionArrays[level], R_NUM); - - SetupAnchors(pRegionArrays[level]); - - GrowTerrain(pRegionArrays[level], 1); - - AssignTypes(pRegionArrays[level]); - - MakeUWMaze(pRegionArrays[level]); - - if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); - - AddHexsides(pRegionArrays[level]); - - if (Globals->HEXSIDE_TERRAIN) AddBeaches(pRegionArrays[level]); - - CheckHexsides(pRegionArrays[level]); - - FinalSetup(pRegionArrays[level]); - -} - -void ARegionList::CheckHexsides(ARegionArray *pRegs) -{ - int x, y; - for(x = 0; x < pRegs->x; x++) { - for(y = 0; y < pRegs->y; y++) { - ARegion *reg = pRegs->GetRegion(x, y); - if(!reg) continue; - for(int i=0; i<6; i++) { - if(!reg->hexside[i]) { - Awrite("bugger!"); -#ifdef DEBUG - system("pause"); -#endif - } - } - } - } -} - -void ARegionList::CreateUnderdeepLevel(int level, int xSize, int ySize, - char *name) -{ - MakeRegions(level, xSize, ySize); - - pRegionArrays[level]->SetName(name); - pRegionArrays[level]->levelType = ARegionArray::LEVEL_UNDERDEEP; - - SetRegTypes(pRegionArrays[level], R_NUM); - - SetupAnchors(pRegionArrays[level]); - - GrowTerrain(pRegionArrays[level], 1); - - AssignTypes(pRegionArrays[level]); - - MakeUWMaze(pRegionArrays[level]); - - if (Globals->GROW_RACES) GrowRaces(pRegionArrays[level]); - - AddHexsides(pRegionArrays[level]); - - if (Globals->HEXSIDE_TERRAIN) AddBeaches(pRegionArrays[level]); - FinalSetup(pRegionArrays[level]); -} - -void ARegionList::MakeRegions(int level, int xSize, int ySize) -{ - Awrite("Making a level..."); - - ARegionArray *arr = new ARegionArray(xSize, ySize); - pRegionArrays[level] = arr; - - // - // Make the regions themselves - // - int x, y; - for(y = 0; y < ySize; y++) { - for(x = 0; x < xSize; x++) { - if(!((x + y) % 2)) { - ARegion *reg = new ARegion; - reg->SetLoc(x, y, level); - reg->num = Num(); - - // - // Some initial values; these will get reset - // - reg->type = -1; - reg->race = -1; - reg->wages = -1; - - Add(reg); - arr->SetRegion(x, y, reg); - } - } - } - - SetupNeighbors(arr); - - Awrite(""); -} - -void ARegionList::SetupNeighbors(ARegionArray *pRegs) -{ - int x, y; - for(x = 0; x < pRegs->x; x++) { - for(y = 0; y < pRegs->y; y++) { - ARegion *reg = pRegs->GetRegion(x, y); - if(!reg) continue; - NeighSetup(reg, pRegs); - } - } -} - -void ARegionList::AddHexsides(ARegionArray *pRegs) -{ -Awrite("Adding Hexsides"); - - int x, y; - for(x = 0; x < pRegs->x; x++) { - for(y = 0; y < pRegs->y; y++) { - ARegion *reg = pRegs->GetRegion(x, y); - if(!reg) continue; -/* - for(int i=0; i<3; i++) { - if(reg->neighbors[i] && reg->neighbors[i]->hexside[i+3]) - reg->hexside[i] = reg->neighbors[i]->hexside[i+3]; - else reg->hexside[i] = new Hexside; - } - for(int i=3; i<6; i++) { - if(reg->neighbors[i] && reg->neighbors[i]->hexside[i-3]) - reg->hexside[i] = reg->neighbors[i]->hexside[i-3]; - else reg->hexside[i] = new Hexside; - }*/ - for(int i=0; i<6; i++) { - if(reg->hexside[i]) continue; - Hexside *temp = new Hexside; - reg->hexside[i] = temp; - if(i<3 && reg->neighbors[i]) reg->neighbors[i]->hexside[i+3] = temp; - if(i>2 && reg->neighbors[i]) reg->neighbors[i]->hexside[i-3] = temp; - } - - } - } -} - -void ARegionList::MakeIcosahedralRegions(int level, int xSize, int ySize) -{ - int scale, x2, y2; - - Awrite("Making an icosahedral level..."); - - scale = xSize / 10; - if (scale < 1) { - Awrite("Can't create an icosahedral level with xSize < 10!"); - return; - } - if (ySize < scale * 10) { - Awrite("ySize must be at least xSize!"); - return; - } - - // Create the arrays as the specified size, as some code demands that - // the RegionArray be multiples of 8 in each direction - ARegionArray *arr = new ARegionArray(xSize, ySize); - pRegionArrays[level] = arr; - - // but we'll only use up to multiples of 10, as that is required - // by the geometry of the resulting icosahedron. The best choice - // would be to satisfy both criteria by choosing a multiple of 40, - // of course (remember that sublevels are halved in size though)! - xSize = scale * 10; - ySize = xSize; - - // - // Make the regions themselves - // - int x, y; - for(y = 0; y < ySize; y++) { - for(x = 0; x < xSize; x++) { - if(!((x + y) % 2)) { - // These cases remove all the hexes that are cut out to - // make the world join up into a big icosahedron (d20). - if (y < 2) { - if (x) - continue; - } - else if (y <= 3 * scale) { - x2 = x % (2 * scale); - if (y < 3 * x2 && y <= 3 * (2 * scale - x2)) - continue; - } - else if (y < 7 * scale - 1) { - // Include all of this band - } - else if (y < 10 * scale - 2) { - x2 = (x + 2 * scale + 1) % (2 * scale); - y2 = 10 * scale - 1 - y; - if (y2 < 3 * x2 && y2 <= 3 * (2 * scale - x2)) - continue; - } - else { - if (x != 10 * scale - 1) - continue; - } - - ARegion *reg = new ARegion; - reg->SetLoc(x, y, level); - reg->num = Num(); - - // - // Some initial values; these will get reset - // - reg->type = -1; - reg->race = -1; // - reg->wages = -1; // initially store: name - reg->population = -1; // initially used as flag - reg->elevation = -1; - - Add(reg); - arr->SetRegion(x, y, reg); - } - } - } - - SetupIcosahedralNeighbors(arr); - - Awrite(""); -} - -void ARegionList::SetupIcosahedralNeighbors(ARegionArray *pRegs) -{ - int x, y; - - for(x = 0; x < pRegs->x; x++) { - for(y = 0; y < pRegs->y; y++) { - ARegion *reg = pRegs->GetRegion(x, y); - if(!reg) continue; - IcosahedralNeighSetup(reg, pRegs); - } - } -} - -void ARegionList::MakeLand(ARegionArray *pRegs, int percentOcean, - int continentSize) -{ - int total, ocean; - - total = 0; - for (int x=0; x < pRegs->x; x++) - for (int y=0; y < pRegs->y; y++) - if (pRegs->GetRegion(x, y)) - total++; - ocean = total; - - Awrite("Making land"); - while (ocean > (total * percentOcean) / 100) { - int sz = getrandom(continentSize); - sz = sz * sz; - - int tempx = getrandom(pRegs->x); - int yoff = pRegs->y / 40; - int yband = pRegs->y / 2 - 2 * yoff; - int tempy = (getrandom(yband)+yoff) * 2 + tempx % 2; - - ARegion *reg = pRegs->GetRegion(tempx, tempy); - if(!reg) continue; - ARegion *newreg = reg; - ARegion *seareg = reg; - - // Archipelago or Continent? - if (getrandom(100) < Globals->ARCHIPELAGO) { - // Make an Archipelago: - sz = sz / 5 + 1; - int first = 1; - int tries = 0; - for (int i=0; ineighbors[direc]; - while (!newreg) { - direc = getrandom(6); - newreg = reg->neighbors[direc]; - } - tries++; - for (int m = 0; m < 2; m++) { - seareg = newreg; - newreg = seareg->neighbors[direc]; - if (!newreg) break; - } - if (!newreg) break; - if (newreg) { - seareg = newreg; - newreg = seareg->neighbors[getrandom(NDIRS)]; - if (!newreg) break; - // island start point (~3 regions away from last island) - seareg = newreg; - if (first) { - seareg = reg; - first = 0; - } - if (seareg->type == -1) { - reg = seareg; - tries = 0; - reg->type = R_NUM; - ocean--; - } else { - if (tries > 5) break; - continue; - } - int growit = getrandom(20); - int growth = 0; - int growch = 2; - // grow this island - while (growit > growch) { - growit = getrandom(20); - tries = 0; - int newdir = getrandom(NDIRS); - while (direc == reg->GetRealDirComp(newdir)) - newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; - while ((!newreg) && (tries < 36)) { - while (direc == reg->GetRealDirComp(newdir)) - newdir = getrandom(NDIRS); - newreg = reg->neighbors[newdir]; - tries++; - } - if (!newreg) continue; - reg = newreg; - tries = 0; - if (reg->type == -1) { - reg->type = R_NUM; - growth++; - if (growth > growch) growch = growth; - ocean--; - } else continue; - } - } - } - } else { - // make a continent - if (reg->type == -1) { - reg->type = R_NUM; - ocean--; - } - for (int i=0; iyloc < yoff*2) && ((dir < 2) || (dir = NDIRS-1)) - && (getrandom(4) < 3)) continue; - if ((reg->yloc > (yband+yoff)*2) && ((dir < 5) && (dir > 1)) - && (getrandom(4) < 3)) continue; - ARegion *newreg = reg->neighbors[dir]; - if (!newreg) break; - int polecheck = 0; - for (int v=0; v < NDIRS; v++) { - ARegion *creg = newreg->neighbors[v]; - if (!creg) polecheck = 1; - } - if(polecheck) break; - reg = newreg; - if (reg->type == -1) { - reg->type = R_NUM; - ocean--; - } - } - } - } - - // At this point, go back through and set all the rest to ocean - SetRegTypes(pRegs, R_OCEAN); - Awrite(""); -} - -void ARegionList::MakeCentralLand(ARegionArray *pRegs) -{ - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if(!reg) continue; - // Initialize region to ocean. - reg->type = R_OCEAN; - // If the region is close to the edges, it stays ocean - if(i < 8 || i >= pRegs->x - 8 || j < 8 || j >= pRegs->y - 8) - continue; - // If the region is within 10 of the edges, it has a 50% - // chance of staying ocean. - if(i < 10 || i >= pRegs->x - 10 || j < 10 || j >= pRegs->y - 10) { - if(getrandom(100) > 50) continue; - } - - // Otherwise, set the region to land. - reg->type = R_NUM; - } - } -} - -void ARegionList::MakeIslands(ARegionArray *pArr, int nPlayers) -{ - // First, make the islands along the top. - int i; - int nRow = (nPlayers + 3) / 4; - for(i = 0; i < nRow; i++) - MakeOneIsland(pArr, 10 + i * 6, 2); - // Next, along the left. - nRow = (nPlayers + 2) / 4; - for(i = 0; i < nRow; i++) - MakeOneIsland(pArr, 2, 10 + i * 6); - // The islands along the bottom. - nRow = (nPlayers + 1) / 4; - for(i = 0; i < nRow; i++) - MakeOneIsland(pArr, 10 + i * 6, pArr->y - 6); - // And the islands on the right. - nRow = nPlayers / 4; - for(i = 0; i < nRow; i++) - MakeOneIsland(pArr, pArr->x - 6, 10 + i * 6); -} - -void ARegionList::MakeOneIsland(ARegionArray *pRegs, int xx, int yy) -{ - for(int i = 0; i < 4; i++) { - for(int j = 0; j < 4; j++) { - ARegion *pReg = pRegs->GetRegion(i + xx, j + yy); - if(!pReg) continue; - pReg->type = R_NUM; - } - } -} - -void ARegionList::CleanUpWater(ARegionArray *pRegs) -{ - Awrite("Converting Scattered Water"); - int dotter = 0; - for (int ctr = 0; ctr < Globals->SEA_LIMIT+1; ctr++) { - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - int remainocean = 0; - if((!reg) || (reg->type != R_OCEAN)) continue; - for (int d = 0; d < NDIRS; d++) { - remainocean += reg->CheckSea(d, Globals->SEA_LIMIT, remainocean); - } - if(dotter++%2000 == 0) Adot(); - if (remainocean > 0) continue; - reg->wages = 0; - if (getrandom(100) < Globals->LAKES) { - reg->type = R_LAKE; - } else reg->type = R_NUM; - } - } - } - Awrite(""); -} - -void ARegionList::RemoveCoastalLakes(ARegionArray *pRegs) -{ - Awrite("Removing coastal 'lakes'"); - for (int c = 0; c < 2; c++) { - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if ((!reg) || (reg->type != R_LAKE)) continue; - if (reg->IsCoastal() > 0) { - reg->type = R_OCEAN; - reg->wages = -1; - Adot(); - } else if (reg->wages <= 0) { // name the Lake - int wage1 = 0; - int count1 = 0; - int wage2 = 0; - int count2 = 0; - int temp = 0; - for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; - if (!newregion) continue; - // name after neighboring lake regions preferrentially - if ((newregion->wages > 0) && - (newregion->type == R_LAKE)) { - count1 = 1; - wage1 = newregion->wages; - break; - } - if ((TerrainDefs[newregion->type].similar_type != - R_OCEAN) && (newregion->wages > -1)) { - if (newregion->wages == wage1) count1++; - else if (newregion->wages == wage2) count2++; - else if (count2 == 0) { - wage2 = newregion->wages; - count2++; - } - if (count2 > count1) { - temp = wage1; - wage1 = wage2; - wage2 = temp; - int tmpin = count1; - count1 = count2; - count2 = tmpin; - } - } - } - if (count1 > 0) reg->wages = wage1; - } - } - } - } - Awrite(""); -} - -void ARegionList::SeverLandBridges(ARegionArray *pRegs) -{ - Awrite("Severing land bridges"); - // mark land hexes to delete - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if ((!reg) || (TerrainDefs[reg->type].similar_type == R_OCEAN)) - continue; - if (reg->IsCoastal() != 4) continue; - int tidych = Globals->SEVER_LAND_BRIDGES; - for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; - if ((!newregion) || - (TerrainDefs[newregion->type].similar_type == R_OCEAN)) - continue; - if (newregion->IsCoastal() == 4) tidych = tidych * 2; - } - if (getrandom(100) < (tidych)) reg->wages = -2; - } - } - // now change to ocean - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if ((!reg) || (reg->wages > -2)) continue; - reg->type = R_OCEAN; - reg->wages = -1; - Adot(); - } - } - Awrite(""); -} - -void ARegionList::AddBeaches(ARegionArray *pRegs) -{ -/* Hex Patch Dec '03 */ - Awrite("Adding Beaches"); - // - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if (!reg) continue; - if (!(reg->IsCoastal())) continue; - if (TerrainDefs[reg->type].similar_type==R_OCEAN) continue; - for(int k = 0; k<6; k++) { - if(reg->neighbors[k]) { - if(TerrainDefs[reg->neighbors[k]->type].similar_type==R_OCEAN) { - int coasttype = H_DUMMY; - if(!(HexsideDefs[H_BEACH].flags & HexsideType::DISABLED)) coasttype = H_BEACH; - if(!(HexsideDefs[H_HARBOUR].flags & HexsideType::DISABLED)) { - if(coasttype == H_DUMMY || getrandom(100) < 10) coasttype = H_HARBOUR; - } - if(!(HexsideDefs[H_ROCKS].flags & HexsideType::DISABLED)) { - if(coasttype == H_DUMMY || getrandom(100) < 10) coasttype = H_ROCKS; - } - reg->hexside[k]->type = coasttype; - } - } - } - } - } -} - - -void ARegionList::AddRivers(ARegionArray *pRegs) -{ - Awrite("Adding Rivers..."); - // This routine seeds river generation, calling int AddRiverSegment(reg,hexside, rivernum, 0) - // This routine relies on beaches, rocks and/or harbours being present to halt river creation. - - int chance = 0; - int numrivers = 0; - int numattempts = 0; - int hexside = -1; - -//southern half - for(int i = 0; i < pRegs->x; i++) { - for(int j = pRegs->y /2; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if (!reg) continue; // 50% eliminated here - if (reg->IsCoastal() ) continue; // > 50% eliminated here - if (reg->type == R_LAKE) continue; - - chance = WaterDistance(reg); - chance = chance*chance; //1,4,9,16 - hexside = getrandom(6); - - if(TerrainDefs[reg->type].similar_type == R_PLAIN ) chance = chance / 2; - if(TerrainDefs[reg->type].similar_type == R_MOUNTAIN ) chance = chance * 2; - if(TerrainDefs[reg->type].similar_type == R_DESERT ) chance = chance / 4; - - if( getrandom(15) < chance) { - numattempts++; -#ifdef DEBUG -cout << "attempt " << numattempts << endl; -#endif - numrivers += AddRiverSegment(reg,hexside,numattempts,0); - cout << endl; //used with "." in code to mark river length during generation. -#ifdef DEBUG -cout << "done" << endl; -#endif - } - } - } -#ifdef DEBUG -cout << "northern" << endl; -#endif -//northern half - for(int i = 0; i < pRegs->x; i++) { - for(int j = pRegs->y /2 - 1; j > -1; j--) { - ARegion *reg = pRegs->GetRegion(i, j); - if (!reg) continue; // 50% eliminated here - if (reg->IsCoastal() ) continue; // > 50% eliminated here - if (reg->type==R_LAKE) continue; - - chance = WaterDistance(reg); - chance = chance*chance; //1,4,9,16 - hexside = getrandom(6); - - if(TerrainDefs[reg->type].similar_type == R_PLAIN ) chance = chance / 2; - if(TerrainDefs[reg->type].similar_type == R_MOUNTAIN ) chance = chance * 2; - if(TerrainDefs[reg->type].similar_type == R_DESERT ) chance = chance / 4; - - if( getrandom(24) < chance) { - numattempts++; -#ifdef DEBUG -cout << "attempt " << numattempts << endl; -#endif - numrivers += AddRiverSegment(reg,hexside,numattempts,0); - cout << endl; //used with "." in code to mark river length during generation. -#ifdef DEBUG -cout << "done" << endl; -#endif - } - } - } -#ifdef DEBUG -cout << "clearing nums" << endl; -#endif - ClearRiverNums(pRegs); - Awrite(AString (numrivers) + " rivers added"); -} - -int ARegionList::WaterDistance(ARegion *reg) -{ - if( reg->IsCoastal() ) return 0; - for(int i=0; i<6; i++) { - if(reg->hexside[i]->type == H_RIVER) return 0; - } - - for(int k = 0; k<6; k++) { - if(reg->neighbors[k]) { - for(int i=0; i<6; i++) { - if(reg->hexside[i]->type == H_RIVER) return 0; - } - } - } - for(int k = 0; k<6; k++) { - if(reg->neighbors[k]) { - if(reg->neighbors[k]->IsCoastal() ) return 1; - } - } - - for(int k = 0; k<6; k++) { - if(reg->neighbors[k]) { - if (reg->neighbors[k]->neighbors[k]) { - if(reg->neighbors[k]->neighbors[k]->IsCoastal() ) return 2; - for(int i=0; i<6; i++) { - if(reg->hexside[i]->type == H_RIVER) return 2; - } - } - } - } - for(int k = 0; k<6; k++) { - if(reg->neighbors[k] && reg->neighbors[k]->neighbors[k]) { - if (reg->neighbors[k]->neighbors[k]->neighbors[k]) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k]->IsCoastal() ) return 3; - for(int i=0; i<6; i++) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k]->hexside[i]->type == H_RIVER) return 3; - } - } - if(k<5 && reg->neighbors[k]->neighbors[k]->neighbors[k+1]) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k+1]->IsCoastal() ) return 3; - for(int i=0; i<6; i++) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k+1]->hexside[i]->type == H_RIVER) return 3; - } - } - if(k>0 && reg->neighbors[k]->neighbors[k]->neighbors[k-1]) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k-1]->IsCoastal() ) return 3; - for(int i=0; i<6; i++) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k-1]->hexside[i]->type == H_RIVER) return 3; - } - } - if(k==0 && reg->neighbors[k]->neighbors[k]->neighbors[k+5]) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k+5]->IsCoastal() ) return 3; - for(int i=0; i<6; i++) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k+5]->hexside[i]->type == H_RIVER) return 3; - } - } - if(k==5 && reg->neighbors[k]->neighbors[k]->neighbors[k-5]) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k-5]->IsCoastal() ) return 3; - for(int i=0; i<6; i++) { - if(reg->neighbors[k]->neighbors[k]->neighbors[k-5]->hexside[i]->type == H_RIVER) return 3; - } - } - } - } - - return 4; -} - -void ARegionList::ClearRiverNums(ARegionArray *pRegs) -{ - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if (!reg) continue; - for(int i=0; i<6; i++) { - if(reg->hexside[i]->type == H_RIVER) reg->hexside[i]->bridge = 0; - } - } - } -} - -int ARegionList::AddRiverSegment(ARegion *reg,int hexside,int rivernum, int tries) -{ - cout << "."; - //make hexside a value from 0 to 5 - hexside %= 6; - if(hexside < 0) hexside += 6; - //if coastal/lake edge, return 1 - if(reg->hexside[hexside]->type == H_BEACH || reg->hexside[hexside]->type == H_ROCKS || reg->hexside[hexside]->type == H_HARBOUR) return 1; - //if river present, return 0 if same river, or 1 if different river. - if(reg->hexside[hexside]->type == H_RIVER) { - if(reg->hexside[hexside]->bridge == rivernum) return 0; - else return 1; - } - - // if tries > 100 return 0 - that is, this river is 100 segments long. Note that potentially, because of the way the code is - //recursed, this could take up to 2^100 operations to resolve :(. This occurs especially on small maps with no ocean to end the river, - //but could also be a problem on very big continents. - if(tries>100) return 0; - - //if either of the continuing options is this river, return. Else we can get rings at the start of rivers. - //only need to do this check for the sixth segment, ie tries == 5, but doing it always prevents multi-hex rings. - //Note, by not checking for other rivers this occasionally allows rivers to "split in two" - if it were changed to - //(add a river & return 1) if there is a different river, this would be eliminated. -#ifdef DEBUG -if(!reg->hexside[(hexside+1)%6]) cout << "no local"; -#endif - if(reg->hexside[(hexside+1)%6]->bridge == rivernum) return 0; -#ifdef DEBUG -if(reg->neighbors[(hexside+1)%6] && !reg->neighbors[(hexside+1)%6]->hexside[(hexside+5)%6] ) cout << "no neighbour hexside " << hexside << " " << (hexside-1)%6; -#endif - if(reg->neighbors[(hexside+1)%6] && reg->neighbors[(hexside+1)%6]->hexside[(hexside+5)%6]->bridge == rivernum) return 0; - - //otherwise, make a river segment here - CreateRiverSegment(reg,hexside,rivernum); - - int coin = getrandom(2); - if(coin) { - //go right -#ifdef DEBUG -cout << "heads" << endl; -#endif - if( AddRiverSegment(reg,(hexside+1)%6,rivernum,tries+1) == 1 ) return 1; - - //go left - else if (reg->neighbors[(hexside+1)%6] && - AddRiverSegment(reg->neighbors[(hexside+1)%6],(hexside+5)%6,rivernum,tries+1) == 1 ) return 1; - - // cannot proceed in either direction. Delete the river segment and continue - else { - DeleteRiverSegment(reg,hexside); - return 0; - } - } - - else { -#ifdef DEBUG -cout << "tails" << endl; -#endif - //go left - if (reg->neighbors[(hexside+1)%6] && AddRiverSegment(reg->neighbors[(hexside+1)%6],(hexside+5)%6,rivernum,tries+1) == 1 ) return 1; - //go right - else if( AddRiverSegment(reg,(hexside+1)%6,rivernum,tries+1) == 1 ) return 1; - - // cannot proceed in either direction. Delete the river segment and continue - else { - DeleteRiverSegment(reg,hexside); - return 0; - } - } -#ifdef DEBUG -cout << "bugs!" << endl; -#endif - //should never be called - DeleteRiverSegment(reg,hexside); - return 0; -} - -void ARegionList::CreateRiverSegment(ARegion *reg, int hexside, int rivernum) -{ - // create a river segment - //make hexside a value from 0 to 5 - hexside %= 6; - if(hexside < 0) hexside += 6; - - reg->hexside[hexside]->type = H_RIVER; - reg->hexside[hexside]->bridge = rivernum; -} - -void ARegionList::DeleteRiverSegment(ARegion *reg, int hexside) -{ - // delete a river segment - //make hexside a value from 0 to 5 - hexside %=6; - if(hexside < 0) hexside += 6; - - reg->hexside[hexside]->type = H_DUMMY; - reg->hexside[hexside]->bridge = 0; -} - - -void ARegionList::SetRegTypes(ARegionArray *pRegs, int newType) -{ - for(int i = 0; i < pRegs->x; i++) { - for(int j = 0; j < pRegs->y; j++) { - ARegion *reg = pRegs->GetRegion(i, j); - if(!reg) continue; - if(reg->type == -1) reg->type = newType; - } - } -} - -void ARegionList::SetupAnchors(ARegionArray *ta) -{ - // Now, setup the anchors - Awrite("Setting up the anchors"); - int skip = 250; - int f = 2; - if(Globals->TERRAIN_GRANULARITY) { - skip = Globals->TERRAIN_GRANULARITY; - while (skip > 5) { - f++; - skip -= 5; - if (skip < 1) skip = 1; - } - skip = 100 * ((skip+3) * f + 2) / (skip + f - 2); - } - int dotter = 0; - for (int x=0; x<(ta->x)/f; x++) { - for (int y=0; y<(ta->y)/(f*2); y++) { - if(getrandom(1000) > skip) continue; - ARegion *reg = 0; - for (int i=0; i<4; i++) { - int tempx = x * f + getrandom(f); - int tempy = y * f * 2 + getrandom(f)*2 + tempx%2; - reg = ta->GetRegion(tempx, tempy); - if (!reg) - continue; - if (reg->type == R_NUM) { - reg->type = GetRegType(reg); - reg->population = 1; - if (TerrainDefs[reg->type].similar_type != R_OCEAN) - reg->wages = AGetName(0); - break; - } - } - if(dotter++%30 == 0) Adot(); - } - } - - Awrite(""); -} - -void ARegionList::GrowTerrain(ARegionArray *pArr, int growOcean) -{ - Awrite("Growing Terrain..."); - for (int j=0; j<30; j++) { - int x, y; - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - reg->population = 1; - } - } - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - if ((j > 0) && (j < 21) && (getrandom(3) < 2)) continue; - if (reg->type == R_NUM) { - - // Check for Lakes - if (Globals->LAKES && - (getrandom(100) < (Globals->LAKES/10 + 1))) { - reg->type = R_LAKE; - break; - } - // Check for Odd Terrain - if (getrandom(1000) < Globals->ODD_TERRAIN) { - reg->type = GetRegType(reg); - if (TerrainDefs[reg->type].similar_type != R_OCEAN) - reg->wages = AGetName(0); - break; - } - - - int init = getrandom(6); - for (int i=0; ineighbors[(i+init) % NDIRS]; - if (t) { - if (t->population < 1) continue; - if(t->type != R_NUM && - (TerrainDefs[t->type].similar_type!=R_OCEAN || - (growOcean && (t->type != R_LAKE)))) { - if (j==0) t->population = 0; - reg->population = 0; - reg->race = t->type; - reg->wages = t->wages; - break; - } - } - } - } - } - } - - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - if(reg->type == R_NUM && reg->race != -1) - reg->type = reg->race; - } - } - } -} - -void ARegionList::RandomTerrain(ARegionArray *pArr) -{ - int x, y; - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - - if (reg->type == R_NUM) { - int adjtype = 0; - int adjname = -1; - for (int d = 0; d < NDIRS; d++) { - ARegion *newregion = reg->neighbors[d]; - if (!newregion) continue; - if ((TerrainDefs[newregion->type].similar_type != - R_OCEAN) && (newregion->type != R_NUM) && - (newregion->wages > 0)) { - adjtype = newregion->type; - adjname = newregion->wages; - } - } - if (adjtype && !Globals->CONQUEST_GAME) { - reg->type = adjtype; - reg->wages = adjname; - } else { - reg->type = GetRegType(reg); - reg->wages = AGetName(0); - } - } - } - } -} - -void ARegionList::MakeUWMaze(ARegionArray *pArr) -{ - int x, y; - - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - - for (int i=D_NORTH; i<= NDIRS; i++) { - int count = 0; - for(int j=D_NORTH; j< NDIRS; j++) - if(reg->neighbors[j]) count++; - if(count <= 1) break; - - ARegion *n = reg->neighbors[i]; - if (n) { - if (n->xloc < x || (n->xloc == x && n->yloc < y)) - continue; - if(!CheckRegionExit(reg, n)) { - count = 0; - for(int k = D_NORTH; kneighbors[k]) count++; - } - if(count <= 1) break; - n->neighbors[reg->GetRealDirComp(i)] = 0; - reg->neighbors[i] = 0; - } - } - } - } - } -} - -void ARegionList::AssignTypes(ARegionArray *pArr) -{ - // RandomTerrain() will set all of the un-set region types and names. - RandomTerrain(pArr); -} - -void ARegionList::UnsetRace(ARegionArray *pArr) -{ - int x, y; - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - reg->race = - 1; - } - } -} - -void ARegionList::RaceAnchors(ARegionArray *pArr) -{ - UnsetRace(pArr); - int x, y; - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - // Anchor distribution: depends on GROW_RACES value - int jiggle = 4 + 2 * Globals->GROW_RACES; - if((y + ((x % 2) * jiggle/2)) % jiggle > 1) continue; - int xoff = x + 2 - getrandom(3) - getrandom(3); - ARegion *reg = pArr->GetRegion(xoff, y); - if(!reg) continue; - - if((reg->type == R_LAKE) && (!Globals->LAKESIDE_IS_COASTAL)) - continue; - - reg->race = -1; - - if(TerrainDefs[reg->type].similar_type == R_OCEAN) { - // setup near coastal race here - int d = getrandom(NDIRS); - int ctr = 0; - ARegion *nreg = reg->neighbors[d]; - if(!nreg) continue; - while((ctr++ < 20) && (reg->race == -1)) { - if(TerrainDefs[nreg->type].similar_type != R_OCEAN) { - int rnum = - sizeof(TerrainDefs[nreg->type].coastal_races) / - sizeof(int); - reg->race = TerrainDefs[nreg->type].coastal_races[getrandom(rnum)]; - } else { - int dir = getrandom(NDIRS); - if(d == nreg->GetRealDirComp(dir)) continue; - if(!(nreg->neighbors[dir])) continue; - nreg = nreg->neighbors[dir]; - } - } - } else { - // setup noncoastal race here - int rnum = sizeof(TerrainDefs[reg->type].races)/sizeof(int); - reg->race = TerrainDefs[reg->type].races[getrandom(rnum)]; - } - } - } -} - -void ARegionList::GrowRaces(ARegionArray *pArr) -{ - RaceAnchors(pArr); - int a, x, y; - for(a = 0; a < 25; a++) { - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if((!reg) || (reg->race == -1)) continue; - - for(int dir = 0; dir < NDIRS; dir++) { - ARegion *nreg = reg->neighbors[dir]; - if ((!nreg) || (nreg->race != -1)) continue; - int iscoastal = 0; - int cnum = sizeof(TerrainDefs[reg->type].coastal_races) / - sizeof(int); - for(int i=0; irace == - TerrainDefs[reg->type].coastal_races[i]) - iscoastal = 1; - } - // Only coastal races may pass from sea to land - if ((TerrainDefs[nreg->type].similar_type == R_OCEAN) && - (!iscoastal)) - continue; - - int ch = getrandom(5); - if (iscoastal) { - if (TerrainDefs[nreg->type].similar_type == R_OCEAN) - ch += 2; - } else { - ManType *mt = FindRace(ItemDefs[reg->race].abr); - if (mt->terrain==TerrainDefs[nreg->type].similar_type) - ch += 2; - int rnum = sizeof(TerrainDefs[nreg->type].races) / - sizeof(int); - for(int i=0; itype].races[i] == reg->race) - ch++; - } - } - if (ch > 3) nreg->race = reg->race; - } - } - } - } -} - -void ARegionList::FinalSetup(ARegionArray *pArr) -{ - int x, y; - for(x = 0; x < pArr->x; x++) { - for(y = 0; y < pArr->y; y++) { - ARegion *reg = pArr->GetRegion(x, y); - if(!reg) continue; - if ((TerrainDefs[reg->type].similar_type == R_OCEAN) && - (reg->type != R_LAKE)) { - if(pArr->levelType == ARegionArray::LEVEL_UNDERWORLD) - reg->SetName("The Undersea"); - else if(pArr->levelType == ARegionArray::LEVEL_UNDERDEEP) - reg->SetName("The Deep Undersea"); - else { - AString ocean_name = Globals->WORLD_NAME; - ocean_name += " Ocean"; - reg->SetName(ocean_name.Str()); - } - } else { - if(pArr->levelType == ARegionArray::LEVEL_QUEST) {}//reg->SetName((*pArr->strName).Str()); - else if (reg->wages == -1) reg->SetName("Unnamed"); - else if(reg->wages != -2) - reg->SetName(AGetNameString(reg->wages)); - else - reg->wages = -1; - } - if(pArr->levelType != ARegionArray::LEVEL_QUEST) reg->Setup(); - else { //This bit shouldn't really be here, move somewhere appropriate - reg->race = -1; - reg->population = 0; - reg->basepopulation = 0; - reg->wages = 0; - reg->maxwages = 0; - reg->money = 0; - } - } - } -} - -void ARegionList::MakeShaft(ARegion *reg, ARegionArray *pFrom, - ARegionArray *pTo) -{ - if(TerrainDefs[reg->type].similar_type == R_OCEAN) return; - - int tempx = reg->xloc * pTo->x / pFrom->x + - getrandom(pTo->x / pFrom->x); - int tempy = reg->yloc * pTo->y / pFrom->y + - getrandom(pTo->y / pFrom->y); - // - // Make sure we get a valid region. - // - tempy += (tempx + tempy) % 2; - - ARegion *temp = pTo->GetRegion(tempx, tempy); - if (!temp) - return; - if(TerrainDefs[temp->type].similar_type == R_OCEAN) return; - - Object *o = new Object(reg); - o->num = reg->buildingseq++; - o->name = new AString(AString("Shaft [") + o->num + "]"); - o->type = O_SHAFT; - o->incomplete = 0; - o->inner = temp->num; - reg->objects.Add(o); - - o = new Object(temp); //was reg - fixed by BS. - o->num = temp->buildingseq++; - o->name = new AString(AString("Shaft [") + o->num + "]"); - o->type = O_SHAFT; - o->incomplete = 0; - o->inner = reg->num; - temp->objects.Add(o); -} - -void ARegionList::MakeShaftLinks(int levelFrom, int levelTo, int odds) -{ - ARegionArray *pFrom = pRegionArrays[levelFrom]; - ARegionArray *pTo = pRegionArrays[levelTo]; - - int x, y; - for(x = 0; x < pFrom->x; x++) { - for(y = 0; y < pFrom->y; y++) { - ARegion *reg = pFrom->GetRegion(x, y); - if(!reg) continue; - - if(getrandom(odds) != 0) continue; - - MakeShaft(reg, pFrom, pTo); - } - } -} - -void ARegionList::SetACNeighbors(int levelSrc, int levelTo, int maxX, int maxY) -{ - ARegionArray *ar = GetRegionArray(levelSrc); - - for(int x = 0; x < ar->x; x++) { - for(int y = 0; y < ar->y; y++) { - ARegion *AC = ar->GetRegion(x, y); - if(!AC) continue; - for (int i=0; ineighbors[i]) continue; - ARegion *pReg = GetStartingCity(AC, i, levelTo, maxX, maxY); - if(!pReg) continue; - AC->neighbors[i] = pReg; - pReg->MakeStartingCity(); - if(Globals->GATES_EXIST) { - numberofgates++; - } - } - } - } -} - -void ARegionList::InitSetupGates(int level) -{ - - if(!Globals->GATES_EXIST) return; - - ARegionArray *pArr = pRegionArrays[level]; - - int i, j, k; - for (i=0; ix / 8; i++) { - for (j=0; jy / 16; j++) { - for (k=0; k<5; k++) { - int tempx = i*8 + getrandom(8); - int tempy = j*16 + getrandom(8)*2 + tempx%2; - ARegion *temp = pArr->GetRegion(tempx, tempy); - if (temp && TerrainDefs[temp->type].similar_type != R_OCEAN && - temp->gate != -1) { - numberofgates++; - temp->gate = -1; - break; - } - } - } - } -} - -void ARegionList::FinalSetupGates() -{ - if(!Globals->GATES_EXIST) return; - - int *used = new int[numberofgates]; - - int i; - for (i=0; igate == -1) { - int index = getrandom(numberofgates); - while (used[index]) { - index++; - index = index % numberofgates; - } - r->gate = index+1; - used[index] = 1; - // setting up gatemonth - int nmon = (getrandom(3) - 1) + (getrandom(3) - 1) + ((index+1) % 12); - if (nmon > 11) nmon = nmon - 12; - if (nmon < 0) nmon = nmon + 12; - r->gatemonth = nmon; - } - } - delete used; -} diff --git a/arcadia/market.cpp b/arcadia/market.cpp deleted file mode 100644 index 2fe7c975c..000000000 --- a/arcadia/market.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "market.h" -#include "items.h" -#include "gameio.h" -#include "gamedata.h" - -Market::Market() -{ - activity = 0; -} - -Market::Market(int a, int b, int c, int d, int e, int f, int g, int h) -{ - type = a; - item = b; - price = c; - amount = d; - minpop = e; - maxpop = f; - minamt = g; - maxamt = h; - baseprice = price; - activity = 0; -} - -void Market::PostTurn(int population, int wages, int race) -{ - // Nothing to do to the markets. - if(!(Globals->VARIABLE_ECONOMY)) return; - - // - // Unlimited, unchanging market. - // - if (amount == -1) return; - - if (ItemDefs[item].type & IT_MAN) { - float ratio = ItemDefs[item].baseprice / - (float)Globals->BASE_MAN_COST; - if(wages < 10) wages = 10; //minimum cost of $40 for normal race. - price = (int)(wages * 4 * ratio); - if (ItemDefs[item].type & IT_LEADER) - amount = population / (25*Globals->POP_LEVEL); - else { - amount = population / (5*Globals->POP_LEVEL); - item = race; //allows for race of region to change. - } - return; - } - - int tarprice = price; - if (amount) { - int fluctuation = (baseprice * activity)/amount; - if (type == M_BUY) - tarprice = (2 * baseprice + fluctuation) / 2; - else - tarprice = (3 * baseprice - fluctuation) / 2; - } - price = price + (tarprice - price) / 5; - - if (population <= minpop) - amount = minamt; - else { - if (population >= maxpop) - amount = maxamt; - else { - amount = minamt + ((maxamt - minamt) * - (population - minpop)) / - (maxpop - minpop); - } - } -} - -void Market::Writeout(Aoutfile *f) -{ - f->PutInt(type); - if (item != -1) f->PutStr(ItemDefs[item].abr); - else f->PutStr("NO_ITEM"); - f->PutInt(price); - f->PutInt(amount); - f->PutInt(minpop); - f->PutInt(maxpop); - f->PutInt(minamt); - f->PutInt(maxamt); - f->PutInt(baseprice); -} - -void Market::Readin(Ainfile *f) -{ - AString *temp; - type = f->GetInt(); - - temp = f->GetStr(); - item = LookupItem(temp); - delete temp; - - price = f->GetInt(); - amount = f->GetInt(); - minpop = f->GetInt(); - maxpop = f->GetInt(); - minamt = f->GetInt(); - maxamt = f->GetInt(); - baseprice = f->GetInt(); -} - -AString Market::Report() -{ - AString temp; - temp += ItemString(item, amount) + " at $" + price; - return temp; -} - -void MarketList::PostTurn(int population, int wages, int race) -{ - forlist(this) { - ((Market *) elem)->PostTurn(population, wages, race); - } -} - -void MarketList::Writeout(Aoutfile *f) -{ - f->PutInt(Num()); - forlist (this) ((Market *) elem)->Writeout(f); -} - -void MarketList::Readin(Ainfile *f) -{ - int n = f->GetInt(); - for (int i=0; iReadin(f); - Add(m); - } -} diff --git a/arcadia/market.h b/arcadia/market.h deleted file mode 100644 index 4834d7c7a..000000000 --- a/arcadia/market.h +++ /dev/null @@ -1,69 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef MARKET_CLASS -#define MARKET_CLASS - -#include "alist.h" -#include "fileio.h" - -enum { - M_BUY, - M_SELL -}; - -class Market : public AListElem { -public: - Market(); - - /* type, item, price, amount, minpop, maxpop, minamt, maxamt */ - Market(int,int,int,int,int,int,int,int); - - int type; - int item; - int price; - int amount; - - int minpop; - int maxpop; - int minamt; - int maxamt; - - int baseprice; - int activity; - - void PostTurn(int,int,int); - void Writeout(Aoutfile * f); - void Readin(Ainfile * f); - AString Report(); -}; - -class MarketList : public AList { -public: - void PostTurn(int,int,int); - void Writeout(Aoutfile * f); - void Readin(Ainfile * f); -}; - -#endif diff --git a/arcadia/modify.cpp b/arcadia/modify.cpp deleted file mode 100644 index 15498cddd..000000000 --- a/arcadia/modify.cpp +++ /dev/null @@ -1,1111 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comment -// ---- ------ ------- -// 2001/Jul/08 Joseph Traub Moved functions t here from game.cpp -// -#include "game.h" -#include "gamedata.h" - -/** \file - * Functions which modify the game's data structures. - * To suit particular versions of Atlantis, it is sometimes necessary - * to alter objects, monsters, skills, etc. - * modify.cpp is where all of the relevant functions to do this are contained. - */ - -/// Enable a skill -/** Makes a skill available in play. -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -*/ -void Game::EnableSkill(int sk) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - SkillDefs[sk].flags &= ~SkillType::DISABLED; -} - -/// Enable a skill -/** Makes a skill unavailable in play. Please note that it is up to the GM -to disable any other skills that might be dependent upon this one in the skill -tree, and to generally make sure that the skill tree isn't messed up. -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -*/ -void Game::DisableSkill(int sk) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - SkillDefs[sk].flags |= SkillType::DISABLED; -} - -/// Change the dependency for a skill. -/** Makes a skill available in play. -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -\arg \c i The dependency array that will be changed. -\arg \c *dep The skill required in the dependency (eg. FORC, if sk is FIRE) -\arg \c lev The level of skill required in the dependency -*/ -void Game::ModifySkillDependancy(int sk, int i, char *dep, int lev) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - if(i < 0 || i >= (int)(sizeof(SkillDefs[sk].depends)/sizeof(SkillDepend))) - return; - if (dep && (FindSkill(dep) == NULL)) return; - if(lev < 0) return; - SkillDefs[sk].depends[i].skill = dep; - SkillDefs[sk].depends[i].level = lev; -} - -void Game::ModifyBaseSkills(int base, int sk1, int sk2, int sk3, int sk4, int sk5) -{ - if(base < 0 || base > (NSKILLS-1)) return; - if(SkillDefs[base].baseskill != base) return; - if(sk1 > -1 && sk1 < NSKILLS) SkillDefs[sk1].baseskill = base; - if(sk2 > -1 && sk2 < NSKILLS) SkillDefs[sk2].baseskill = base; - if(sk3 > -1 && sk3 < NSKILLS) SkillDefs[sk3].baseskill = base; - if(sk4 > -1 && sk4 < NSKILLS) SkillDefs[sk4].baseskill = base; - if(sk5 > -1 && sk5 < NSKILLS) SkillDefs[sk5].baseskill = base; -} - -/// Modify the flags for a skill. -/** Alters some flags on a skill. Some of the flags that can be set are: -SkillType::BATTLEREP, SkillType::MAGIC, SkillType::FOUNDATION. -You can set more than one flag by using the '|' or operator. See skills.h -for the full list. - -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -\arg \c flags The flags that are going to be set -*/ -void Game::ModifySkillFlags(int sk, int flags) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - SkillDefs[sk].flags = flags; -} - -/// Modify the cost (in silver) to study a skill for a month. -/** -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -\arg \c cost An amount of silver -*/ -void Game::ModifySkillCost(int sk, int cost) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - if(cost < 0) return; - SkillDefs[sk].cost = cost; -} - -/// Modify the special effects associated with skills. -/** Mostly associated with spells, eg. fireball, banish_demon, etc. -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -\arg \c special A special string, eg. "lightning", "clear_skies" -*/ -void Game::ModifySkillSpecial(int sk, char *special) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - if (special && (FindSpecial(special) == NULL)) return; - SkillDefs[sk].special = special; -} - -/// Modify the range of a skill. -/** This refers to the physical range within the game world. -See skills.h for the full list. -\arg \c sk One of the values from the NSKILLS enum in gamedata.h -\arg \c cost An amount of silver -*/ -void Game::ModifySkillRange(int sk, char *range) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - if (range && (FindRange(range) == NULL)) return; - SkillDefs[sk].range = range; -} - -void Game::ModifySkillName(int sk, char *name, char *abbr) -{ - if(sk < 0 || sk > (NSKILLS-1)) return; - SkillDefs[sk].name = name; - SkillDefs[sk].abbr = abbr; -} - - - - -/// Switch an item on so it can be used in-game. -/** -\arg \c item One of the values from the NITEMS enum in gamedata.h -*/ -void Game::EnableItem(int item) -{ - if(item < 0 || item > (NITEMS-1)) return; - ItemDefs[item].flags &= ~ItemType::DISABLED; -} - -/// Switch an item off so it cannot be used in-game. -/** -\arg \c item One of the values from the NITEMS enum in gamedata.h -*/ -void Game::DisableItem(int item) -{ - if(item < 0 || item > (NITEMS-1)) return; - ItemDefs[item].flags |= ItemType::DISABLED; -} - -/// Modify some of the flags that affect an item's behavior. -/** The flags are things like ItemType::NOMARKET, ItemType::NOTRANSPORT, etc. -\arg \c it One of the values from the NITEMS enum in gamedata.h -\arg \c flags A series of flags as defined in the ItemType class in items.h -*/ -void Game::ModifyItemFlags(int it, int flags) -{ - if(it < 0 || it > (NITEMS-1)) return; - ItemDefs[it].flags = flags; -} - -/// Set what type of Item this is. -/** The type is an enum, and can be things like IT_MAN | IT_LEADER, etc. -See the enum at line 46 of items.h for more details. -\arg \c it One of the values from the NITEMS enum in gamedata.h -\arg \c type The type of object as defined in the an enum in items.h -*/ -void Game::ModifyItemType(int it, int type) -{ - if(it < 0 || it > (NITEMS-1)) return; - ItemDefs[it].type = type; -} - -/// Change the weight of an item -/** Weight 0 items may still have a fractional weight - see the -FRACTIONAL_WEIGHT gamedef in rules.cpp -\arg \c it One of the values from the NITEMS enum in gamedata.h -\arg \c type The weight of the object -*/ -void Game::ModifyItemWeight(int it, int weight) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(weight < 0) weight = 0; - ItemDefs[it].weight = weight; -} - -/// Change the base price of an item -/** The base price can go up or down depending on the economy of a hex. -Prices tend to go up in cities, and down in the boonies. -\arg \c it One of the values from the NITEMS enum in gamedata.h -\arg \c type The base price of the object -*/ - -void Game::ModifyItemName(int it, char *name, char *names, char *abr) -{ - if(it < 0 || it > (NITEMS-1)) return; - ItemDefs[it].name = name; - ItemDefs[it].names = names; - ItemDefs[it].abr = abr; -} - -void Game::ModifyItemBasePrice(int it, int price) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(price < 0) price = 0; - ItemDefs[it].baseprice = price; -} - -/// Change how much an item will let a unit carry -/** A unit can only move at a speed if it has enough capacity to carry -all of its weight - -\arg \c it One of the values from the NITEMS enum in gamedata.h -\arg \c wlk How much the item can carry at walking speed -\arg \c rid How much the item can carry at riding speed -\arg \c fly How much the item can carry when flying -\arg \c swm How much the item can carry when swimming -*/ -void Game::ModifyItemCapacities(int it, int wlk, int rid, int fly, int swm) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(wlk < 0) wlk = 0; - if(rid < 0) rid = 0; - if(fly < 0) fly = 0; - if(swm < 0) swm = 0; - ItemDefs[it].walk = wlk; - ItemDefs[it].ride = rid; - ItemDefs[it].fly = fly; - ItemDefs[it].swim = swm; -} - -/// Change the item that gives you a bonus when producing this item -/** eg. This item would be wood, and the other item might be an I_AXE -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WOOD) -\arg \c item The tool, also one of the values from the NITEMS enum (eg. I_AXE) -\arg \c bonus How much is added to the production skill -*/ -void Game::ModifyItemProductionBooster(int it, int item, int bonus) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(item < -1 || item > (NITEMS-1)) return; - ItemDefs[it].mult_item = item; - ItemDefs[it].mult_val = bonus; -} - -/// Change the item that can be hitched to this item to pull it along -/** A hitched wagon (or other conveyance) will be pulled at walking speed, -unless of course you have enough horses to carry it. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WAGON) -\arg \c item The tool, also one of the values from the NITEMS enum (eg. I_HORS) -\arg \c capacity How much can be pulled along in the wagon -*/ -void Game::ModifyItemHitch(int it, int item, int capacity) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(item < -1 || item > (NITEMS-1)) return; - if(capacity < 0) return; - ItemDefs[it].hitchItem = item; - ItemDefs[it].hitchwalk = capacity; -} - -/// Change the skill required to produce this item -/** eg. This item would be wood, and the skill would be "LUMB" -Set this to NULL if the item cannot be produced through normal means. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WOOD) -\arg \c *sk The skill as a string, eg. "LUMB", "ARMO", etc. -\arg \c lev How much skill is needed to produce the item - (eg. PARM requires ARMO of level 3) -*/ -void Game::ModifyItemProductionSkill(int it, char *sk, int lev) -{ - if(it < 0 || it > (NITEMS-1)) return; - if (sk && (FindSkill(sk) == NULL)) return; - ItemDefs[it].pSkill = sk; - ItemDefs[it].pLevel = lev; -} - -/// Change the number of man hours required to produce 1 item -/** eg. PARM needs 3 man hours. This doesn't include the skill multiplier, -so a skill-3 unit will produce 3 times as much as this number. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WOOD) -\arg \c months The number of man months required to produce 1 item -\arg \c lev How much skill is needed to produce the item - (eg. PARM requires ARMO of level 3) -*/ -void Game::ModifyItemProductionOutput(int it, int months, int count) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(count < 0) count = 0; - if(months < 0) months = 0; - ItemDefs[it].pMonths = months; - ItemDefs[it].pOut = count; -} - -/// Change the raw materials required to produce 1 item -/** eg. 1 SWOR needs 1 IRON, 1 PARM needs 3 IRON. -Set the variable 'it' to -1 to require no item. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WOOD) -\arg \c i There can be up to 4 raw materials needed. Set i to 0, 1, 2 or 3 for each slot -\arg \c input Which raw material is required. This is one of the values from - the NITEMS enum -\arg \c amount How much of the raw material is needed to produce the item -*/ -void Game::ModifyItemProductionInput(int it, int i, int input, int amount) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(i < 0 || i >= (int)(sizeof(ItemDefs[it].pInput)/sizeof(Materials))) - return; - if(input < -1 || input > (NITEMS-1)) return; - if(amount < 0) amount = 0; - ItemDefs[it].pInput[i].item = input; - ItemDefs[it].pInput[i].amt = amount; -} - -/// Change the magical skill required to produce this item -/** eg. This item would be CARP, and the skill would be "CRMA" -If you have normal skills and magical skills, they are an either-or proposition -eg. you don't need both WEAP-3 and ESWO to create MSWO. Set this to NULL if -no magical skill can produce this item. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_CARP) -\arg \c *sk The skill as a string, eg. "CRMA", "CRRI", etc. -\arg \c lev How much skill is needed to produce the item -*/ -void Game::ModifyItemMagicSkill(int it, char *sk, int lev) -{ - if(it < 0 || it > (NITEMS-1)) return; - if (sk && (FindSkill(sk) == NULL)) return; - ItemDefs[it].mSkill = sk; - ItemDefs[it].mLevel = lev; -} - -/// Change the number of items produced per spell -/** eg. ESWO produces 5 MSWO per casting. Note that this is the opposite way -around to mundane items. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WOOD) -\arg \c count The number of items produced per casting -*/ -void Game::ModifyItemMagicOutput(int it, int count) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(count < 0) count = 0; - ItemDefs[it].mOut = count; -} - -/// Change the raw materials required to produce 1 item via magical means -/** eg. 1 MSWO needs 1 SWOR, 1 MARM needs 1 PARM. -Set the variable 'it' to -1 to require no item. -\arg \c it One of the values from the NITEMS enum in gamedata.h (eg. I_WOOD) -\arg \c i There can be up to 4 raw materials needed. Set i to 0, 1, 2 or 3 for each slot -\arg \c input Which raw material is required. This is one of the values from - the NITEMS enum -\arg \c amount How much of the raw material is needed to produce the item -*/ -void Game::ModifyItemMagicInput(int it, int i, int input, int amount) -{ - if(it < 0 || it > (NITEMS-1)) return; - if(i < 0 || i >= (int)(sizeof(ItemDefs[it].mInput)/sizeof(Materials))) - return; - if(input < -1 || input > (NITEMS-1)) return; - if(amount < 0) amount = 0; - ItemDefs[it].mInput[i].item = input; - ItemDefs[it].mInput[i].amt = amount; -} - -void Game::ModifyItemEscapeSkill(int it, char *sk, int val) -{ - if(it < 0 || it > (NITEMS-1)) return; - if (sk && (FindSkill(sk) == NULL)) return; - ItemDefs[it].esc_skill = sk; - ItemDefs[it].esc_val = val; -} - - - -/// Change the base skill levels for specialised and non-specialised skills. -/** For most races, this will be 3 for special skills, and 2 for non-special -For orcs, it's 4 and 1; for leaders it's 5 and 5 (although it could be 0 and 5) -\arg \c *r One of the races, eg. "ORC", "HELF", "LEAD" -\arg \c spec The level of any specialised skills that the race knows. -\arg \c def The default maximum level of any skill -*/ -void Game::ModifyRaceSkillLevels(char *r, int spec, int def) -{ - ManType *mt = FindRace(r); - if (mt == NULL) return; - if(spec < 0) spec = 0; - if(def < 0) def = 0; - mt->speciallevel = spec; - mt->defaultlevel = def; -} - -/// Change the number of hits it takes to kill a race in combat. -/** -\arg \c *r One of the races, eg. "ORC", "HELF", "LEAD" -\arg \c i How many hit points (should be 1 or more) -*/ -void Game::ModifyRaceHits(char *r, int num) -/* BS 030825 Multiple Hit Men */ -{ - ManType *mt = FindRace(r); - if (mt == NULL) return; - if(num < 1) num = 1; - mt->hits = num; -} - -/// Change the specialised skills that a race knows. -/** -\arg \c *r One of the races, eg. "ORC", "HELF", "LEAD" -\arg \c i Which slot is being changed (there are six, from 0-5) -\arg \c *sk The skill to be added to the race's specialised skill list, eg. "LUMB" -*/ -void Game::ModifyRaceSkills(char *r, int i, char *sk) -{ - ManType *mt = FindRace(r); - if (mt == NULL) return; - if(i < 0 || i >= (int)(sizeof(mt->skills) / sizeof(mt->skills[0]))) return; - if (sk && (FindSkill(sk) == NULL)) return; - mt->skills[i] = sk; -} - -void Game::ModifyRaceSkills(char *r, char *sk1, char *sk2, char *sk3, char *sk4, char *sk5, char *sk6) -{ - ManType *mt = FindRace(r); - if (mt == NULL) return; - if (sk1 && (FindSkill(sk1) == NULL)) sk1 = NULL; - if (sk2 && (FindSkill(sk1) == NULL)) sk2 = NULL; - if (sk3 && (FindSkill(sk1) == NULL)) sk3 = NULL; - if (sk4 && (FindSkill(sk1) == NULL)) sk4 = NULL; - if (sk5 && (FindSkill(sk1) == NULL)) sk5 = NULL; - if (sk6 && (FindSkill(sk1) == NULL)) sk6 = NULL; - mt->skills[0] = sk1; - mt->skills[1] = sk2; - mt->skills[2] = sk3; - mt->skills[3] = sk4; - mt->skills[4] = sk5; - mt->skills[5] = sk6; -} - -/// Change the attacking skill level for a monster (ie it's COMB skill) -/** -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c lev The attacking level of the monster. -*/ -void Game::ModifyMonsterAttackLevel(char *mon, int lev) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; -// if(lev < 0) return; //disabled by BS so that illusions could be modified. - pM->attackLevel = lev; -} - -/// Change the defensive level for a monster -/** defenseType can either be a number from 0-5, or an enum from items.h (line 36) -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c defenseType The type of attack being defended against (eg. ATTACK_COMBAT) -\arg \c level The new defense level of the monster -*/ -void Game::ModifyMonsterDefense(char *mon, int defenseType, int level) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; - if(defenseType < 0 || defenseType > (NUM_ATTACK_TYPES -1)) return; - pM->defense[defenseType] = level; -} - -/// Change a monster's number of attacks, number of hits, and rate of regeneration -/** -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c num The number of attacks -\arg \c hits The number of hits that the monster can take before dying -\arg \c regen The number of hits that the monster gets back per round of combat -*/ -void Game::ModifyMonsterAttacksAndHits(char *mon, int num, int hits, int regen) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; - if(num < 0) return; - if(hits < 0) return; - if(regen < 0) return; - pM->numAttacks = num; - pM->hits = hits; - pM->regen = regen; -} - -/// Change the offensive skills that a monster knows -/** Monsters can give their unit a stea, tact and obse score, although this is not -cumulative with the unit's current score. -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c tact The monster's tactics score -\arg \c stealth The monster's stealth score -\arg \c obs The monster's observation score -*/ -void Game::ModifyMonsterSkills(char *mon, int tact, int stealth, int obs) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; - if(tact < 0) return; - if(stealth < 0) return; - if(obs < 0) return; - pM->tactics = tact; - pM->stealth = stealth; - pM->obs = obs; -} - -/// Change the type or effectiveness of a monster's special attack -/** eg. Dragon's breath, balrog's hellfire spell. -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c *special The name of the special attack (eg. "hellfire", "black_wind") -\arg \c lev The level that the special is cast at -*/ -void Game::ModifyMonsterSpecial(char *mon, char *special, int lev) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; - if (special && (FindSpecial(special) == NULL)) return; - if(lev < 0) return; - pM->special = special; - pM->specialLevel = lev; -} - -/// Change the type or amount of spoils that a monster gives out -/** eg. balrogs give out magical items, wolves give silver, kobolds give normal items -Set the item type to -1 if you don't want items given out. -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c silver The base value of the silver and items that are given out -\arg \c spoilType The type of items that are given out as spoils -*/ -void Game::ModifyMonsterSpoils(char *mon, int silver, int spoilType) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; - if(spoilType < -1) return; - if(silver < 0) return; - pM->silver = silver; - pM->spoiltype = spoilType; -} - -/// Change how likely the monster is to beat things up, and how many will appear -/** This is expressed as a percentage chance of an attack (per turn?) -\arg \c *mon The monster being changed (eg. "BALR") -\arg \c num The maximum number of monsters that will appear -\arg \c hostileChance The percentage chance that a monster will attack someone -*/ -void Game::ModifyMonsterThreat(char *mon, int num, int hostileChance) -{ - MonType *pM = FindMonster(mon, 0); - if (pM == NULL) return; - if(num < 0) return; - if(hostileChance < 0 || hostileChance > 100) return; - pM->hostile = hostileChance; - pM->number = num; -} - -/// Modify the skills required to wield a weapon -/** There's no difference between baseskill or orskill - you can -wield it if you have either of them. -\arg \c *weap The name of the weapon, eg SWOR -\arg \c *baseSkill The primary skill required to wield the weapon -\arg \c *orSkill Another skill that can be used to wield the weapon -*/ -void Game::ModifyWeaponSkills(char *weap, char *baseSkill, char *orSkill) -{ - WeaponType *pw = FindWeapon(weap); - if (pw == NULL) return; - if (baseSkill && (FindSkill(baseSkill) == NULL)) return; - if (orSkill && (FindSkill(orSkill) == NULL)) return; - pw->baseSkill = baseSkill; - pw->orSkill = orSkill; -} - -/// Modify the flags that alter a weapon's behavior -/** The flags are things like WeaponType::NEEDSKILL, WeaponType::RANGED, etc. -There's a full list in items.h, line 200 on -\arg \c *weap The name of the weapon, eg SWOR -\arg \c *baseSkill The primary skill required to wield the weapon -\arg \c *orSkill Another skill that can be used to wield the weapon -*/ -void Game::ModifyWeaponFlags(char *weap, int flags) -{ - WeaponType *pw = FindWeapon(weap); - if (pw == NULL) return; - pw->flags = flags; -} - -/// Modify the class and type of a weapon's attack -/** -\arg \c *weap The name of the weapon, eg "SWOR" -\arg \c wclass The class of the weapon, eg. ARMOR_PIERCING, SLASHING -\arg \c attackType The type of attack, eg. ATTACK_RANGED, ATTACK_COMBAT -*/ -void Game::ModifyWeaponAttack(char *weap, int wclass, int attackType, - int numAtt) -{ - WeaponType *pw = FindWeapon(weap); - if (pw == NULL) return; - if(wclass < 0 || wclass > (NUM_WEAPON_CLASSES - 1)) return; - if(attackType < 0 || attackType > (NUM_ATTACK_TYPES - 1)) return; - pw->weapClass = wclass; - pw->attackType = attackType; - pw->numAttacks = numAtt; -} - -/// Modify the bonus that a weapon gets in attack, defense and -///when fighting mounted opponents -/** -\arg \c *weap The name of the weapon, eg "SWOR" -\arg \c attack The weapon's bonus to attack -\arg \c defense The weapon's bonus in defense -\arg \c vsMount The weapon's bonus against mounted opponents -*/ -void Game::ModifyWeaponBonuses(char *weap, int attack, int defense, int vsMount) -{ - WeaponType *pw = FindWeapon(weap); - if (pw == NULL) return; - pw->attackBonus = attack; - pw->defenseBonus = defense; - pw->mountBonus = vsMount; -} - -/// Modify the flags that govern an armor's behavior -/** Currently there's only one flag: ArmorType::USEINASSASSINATE -\arg \c *armor The armor's name, eg. "CLAR" -\arg \c flags The flags to apply to the armor. -*/ -void Game::ModifyArmorFlags(char *armor, int flags) -{ - ArmorType *pa = FindArmor(armor); - if (pa == NULL) return; - pa->flags = flags; -} - -/// Modify the divisor for the save chances in ModifyArmorSaveValue -/** eg. If this is 300, and the save for COMBAT is 100, then the armor -has 100 in 300 chances of protecting it's wearer vs. COMBAT attacks. -\arg \c *armor The armor's name, eg. "CLAR" -\arg \c from The saving throw's divisor -*/ -void Game::ModifyArmorSaveFrom(char *armor, int from) -{ - ArmorType *pa = FindArmor(armor); - if (pa == NULL) return; - if(from < 0) return; - pa->from = from; -} - -/// Modify the numerator for the armor's save chances -/** eg. If this is 100 for COMBAT, and the savefrom is 300, then the armor -has 100 in 300 chances of protecting it's wearer vs. COMBAT attacks. -\arg \c *armor The armor's name, eg. "CLAR" -\arg \c wclass The saving throw vs. a particular type of attack (eg. SLASHING) -\arg \c val The numerator in the saving throw. (eg. 100) -*/ -void Game::ModifyArmorSaveValue(char *armor, int wclass, int val) -{ - ArmorType *pa = FindArmor(armor); - if (pa == NULL) return; - if(wclass < 0 || wclass > (NUM_WEAPON_CLASSES - 1)) return; - if(val < 0 || val > pa->from) return; - pa->saves[wclass] = val; -} - - -void Game::ModifyArmorSaveAll(char *armor, int from, int melee, int armourpiercing, int magic) -{ - ArmorType *pa = FindArmor(armor); - if (pa == NULL) return; - if(from < 0 || melee < 0 || armourpiercing < 0 || magic < 0) return; - pa->from = from; - pa->saves[SLASHING] = melee; - pa->saves[CRUSHING] = melee; - pa->saves[CLEAVING] = melee; - pa->saves[PIERCING] = melee; - pa->saves[ARMORPIERCING] = armourpiercing; - pa->saves[MAGIC_ENERGY] = magic; - pa->saves[MAGIC_SPIRIT] = magic; - pa->saves[MAGIC_WEATHER] = magic; -} - -/// Modify the skill required to ride a mount -/** see line 2488 in gamedata.cpp -\arg \c *mount The mount name, eg. "HORS" -\arg \c *skill The skill's name eg. "RIDI" -*/ -void Game::ModifyMountSkill(char *mount, char *skill) -{ - MountType *pm = FindMount(mount); - if (pm == NULL) return; - if (skill && (FindSkill(skill) == NULL)) return; - pm->skill = skill; -} - -/// Modify the bonuses given when mounts are ridden into combat -/** -\arg \c *mount The mount name, eg. "HORS" -\arg \c min The minimum bonus given -\arg \c max The maximum bonus given -\arg \c hampered The bonus given when a mount is hampered - (eg. WING horses underground/in tunnels?) -*/ -void Game::ModifyMountBonuses(char *mount, int min, int max, int hampered) -{ - MountType *pm = FindMount(mount); - if (pm == NULL) return; - if(min < 0) return; - if(max < 0) return; -// if(hampered < min) return; - pm->minBonus = min; - pm->maxBonus = max; - pm->maxHamperedBonus = hampered; -} - -/// Modify the special attacks that a mount has -/** The only mount this is used for atm is the fear attacks - vs. mounted troops that camels get -\arg \c *mount The mount name, eg. "HORS" -\arg \c *special The special attack (eg. "spook_horses") -\arg \c level The level of the attack -*/ -void Game::ModifyMountSpecial(char *mount, char *special, int level) -{ - MountType *pm = FindMount(mount); - if (pm == NULL) return; - if (special && (FindSpecial(special) == NULL)) return; - if(level < 0) return; - pm->mountSpecial = special; - pm->specialLev = level; -} - -void Game::EnableObject(int obj) -{ - if(obj < 0 || obj > (NOBJECTS-1)) return; - ObjectDefs[obj].flags &= ~ObjectType::DISABLED; -} - -void Game::EnableHexside(int hex) -{ - if(hex < 0 || hex > (NHEXSIDES-1)) return; - HexsideDefs[hex].flags &= ~HexsideType::DISABLED; -} - -void Game::DisableObject(int obj) -{ - if(obj < 0 || obj > (NOBJECTS-1)) return; - ObjectDefs[obj].flags |= ObjectType::DISABLED; -} - -void Game::ModifyObjectFlags(int ob, int flags) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - ObjectDefs[ob].flags = flags; -} - -void Game::ModifyObjectDecay(int ob, int maxMaint, int maxMonthDecay, int mFact) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - if(maxMonthDecay > maxMaint) return; - if(maxMaint < 0) return; - if(maxMonthDecay < 0) return; - if(mFact < 0) return; - ObjectDefs[ob].maxMaintenance = maxMaint; - ObjectDefs[ob].maxMonthlyDecay = maxMonthDecay; - ObjectDefs[ob].maintFactor = mFact; -} - -void Game::ModifyObjectProduction(int ob, int it) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - if(it < -1 || it > (NITEMS -1)) return; - ObjectDefs[ob].productionAided = it; -} - -void Game::ModifyObjectMonster(int ob, int monster) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - if(monster < -1 || monster > (NITEMS -1)) return; - ObjectDefs[ob].monster = monster; -} - -void Game::ModifyObjectConstruction(int ob, int it, int num, char *sk, int lev) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - if((it < -1 && it != I_WOOD_OR_STONE) || it > (NITEMS -1)) - return; - if(num < 0) return; - if (sk && FindSkill(sk) == NULL) return; - if(lev < 0) return; - ObjectDefs[ob].item = it; - ObjectDefs[ob].cost = num; - ObjectDefs[ob].skill = sk; - ObjectDefs[ob].level = lev; -} - -void Game::ModifyObjectManpower(int ob, int prot, int cap, int sail, int mages) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - if(prot < 0) return; - if(cap < 0) return; - if(sail < 0) return; - if(mages < 0) return; - ObjectDefs[ob].protect = prot; - ObjectDefs[ob].capacity = cap; - ObjectDefs[ob].sailors = sail; - ObjectDefs[ob].maxMages = mages; -} - -void Game::ModifyObjectDefence(int ob, int co, int en, int sp, int we, int ri, int ra) -{ - if(ob < 0 || ob > (NOBJECTS-1)) return; - //if(val < 0) return; // we could conceivably have a negative value - // associated with a structure - ObjectDefs[ob].defenceArray[0] = co; - ObjectDefs[ob].defenceArray[1] = en; - ObjectDefs[ob].defenceArray[2] = sp; - ObjectDefs[ob].defenceArray[3] = we; - ObjectDefs[ob].defenceArray[4] = ri; - ObjectDefs[ob].defenceArray[5] = ra; -} - -void Game::ClearTerrainRaces(int t) -{ - if(t < 0 || t > R_NUM-1) return; - unsigned int c; - for(c = 0; c < sizeof(TerrainDefs[t].races)/sizeof(int); c++) { - TerrainDefs[t].races[c] = -1; - } - for(c = 0; c < sizeof(TerrainDefs[t].coastal_races)/sizeof(int); c++) { - TerrainDefs[t].coastal_races[c] = -1; - } -} - -void Game::ModifyTerrainRace(int t, int i, int r) -{ - if(t < 0 || t > (R_NUM -1)) return; - if(i < 0 || i >= (int)(sizeof(TerrainDefs[t].races)/sizeof(int))) return; - if(r < -1 || r > NITEMS-1) r = -1; - if(r != -1 && !(ItemDefs[r].type & IT_MAN)) r = -1; - TerrainDefs[t].races[i] = r; -} - -void Game::ModifyTerrainCoastRace(int t, int i, int r) -{ - if(t < 0 || t > (R_NUM -1)) return; - if(i < 0 || i >= (int)(sizeof(TerrainDefs[t].coastal_races)/sizeof(int))) - return; - if(r < -1 || r > NITEMS-1) r = -1; - if(r != -1 && !(ItemDefs[r].type & IT_MAN)) r = -1; - TerrainDefs[t].coastal_races[i] = r; -} - -void Game::ClearTerrainItems(int terrain) -{ - if(terrain < 0 || terrain > R_NUM-1) return; - - for(unsigned int c = 0; - c < sizeof(TerrainDefs[terrain].prods)/sizeof(Product); - c++) { - TerrainDefs[terrain].prods[c].product = -1; - TerrainDefs[terrain].prods[c].chance = 0; - TerrainDefs[terrain].prods[c].amount = 0; - } -} - -void Game::ModifyTerrainItems(int terrain, int i, int p, int c, int a) -{ - if(terrain < 0 || terrain > (R_NUM -1)) return; - if(i < 0 || i >= (int)(sizeof(TerrainDefs[terrain].prods)/sizeof(Product))) - return; - if(p < -1 || p > NITEMS-1) p = -1; - if(c < 0 || c > 100) c = 0; - if(a < 0) a = 0; - TerrainDefs[terrain].prods[i].product = p; - TerrainDefs[terrain].prods[i].chance = c; - TerrainDefs[terrain].prods[i].amount = a; -} - -void Game::ModifyTerrainWMons(int t, int freq, int smon, int bigmon, int hum) -{ - if(t < 0 || t > (R_NUM -1)) return; - if(freq < 0) freq = 0; - if(smon < -1 || smon > NITEMS-1) smon = -1; - if(bigmon < -1 || bigmon > NITEMS-1) bigmon = -1; - if(hum < -1 || hum > NITEMS-1) hum = -1; - TerrainDefs[t].wmonfreq = freq; - TerrainDefs[t].smallmon = smon; - TerrainDefs[t].bigmon = bigmon; - TerrainDefs[t].humanoid = hum; -} - -void Game::ModifyTerrainLairChance(int t, int chance) -{ - if(t < 0 || t > (R_NUM -1)) return; - if(chance < 0 || chance > 100) chance = 0; - // Chance is percent out of 100 that should have some lair - TerrainDefs[t].lairChance = chance; -} - -void Game::ModifyTerrainLair(int t, int i, int l) -{ - if(t < 0 || t > (R_NUM -1)) return; - if(i < 0 || i >= (int)(sizeof(TerrainDefs[t].lairs)/sizeof(int))) return; - if(l < -1 || l > NOBJECTS-1) l = -1; - TerrainDefs[t].lairs[i] = l; -} - -void Game::ModifyTerrainEconomy(int t, int pop, int wages, int econ, int move) -{ - if(t < 0 || t > (R_NUM -1)) return; - if(pop < 0) pop = 0; - if(wages < 0) wages = 0; - if(econ < 0) econ = 0; - if(move < 1) move = 1; - TerrainDefs[t].pop = pop; - TerrainDefs[t].wages = wages; - TerrainDefs[t].economy = econ; - TerrainDefs[t].movepoints = move; -} - -void Game::ModifyBattleItemFlags(char *item, int flags) -{ - BattleItemType *pb = FindBattleItem(item); - if (pb == NULL) return; - pb->flags = flags; -} - -void Game::ModifyBattleItemSpecial(char *item, char *special, int level) -{ - BattleItemType *pb = FindBattleItem(item); - if (pb == NULL) return; - if (special && (FindSpecial(special) == NULL)) return; - if(level < 0) return; - pb->special = special; - pb->skillLevel = level; -} - -void Game::ModifySpecialTargetFlags(char *special, int targetflags) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - sp->targflags = targetflags; -} - -void Game::ModifySpecialTargetObjects(char *special, int index, int obj) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - if(index < 0 || index > 3) return; - if((obj != -1 && obj < 1) || (obj > (NOBJECTS-1))) return; - sp->buildings[index] = obj; -} - -void Game::ModifySpecialTargetItems(char *special, int index, int item) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - if(index < 0 || index > 7) return; - if(item < -1 || item > (NITEMS-1)) return; - sp->targets[index] = item; -} - -void Game::ModifySpecialTargetEffects(char *special, int index, char *effect) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - if(index < 0 || index > 3) return; - if (effect && (FindEffect(effect) == NULL)) return; - sp->effects[index] = effect; -} - -void Game::ModifySpecialEffectFlags(char *special, int effectflags) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - sp->effectflags = effectflags; -} - -void Game::ModifySpecialShields(char *special, int index, int type) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - if(index < 0 || index > 4) return; - if(type < -1 || type > (NUM_ATTACK_TYPES)) return; - sp->shield[index] = type; -} - -void Game::ModifySpecialDefenseMods(char *special, int index, int type, int val) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - if(index < 0 || index > 4) return; - if(type < -1 || type > (NUM_ATTACK_TYPES)) return; - sp->defs[index].type = type; - sp->defs[index].val = val; -} - -void Game::ModifySpecialDamage(char *special, int index, int type, int min, - int val, int flags, int cls, char *effect) -{ - SpecialType *sp = FindSpecial(special); - if (sp == NULL) return; - if(index < 0 || index > 4) return; - if (effect && (FindEffect(effect) == NULL)) return; - if(type < -1 || type > NUM_ATTACK_TYPES) return; - if(cls < -1 || cls > (NUM_WEAPON_CLASSES)) return; //NUM_WEAPON_CLASSES is allowed for courage, which ignores armour completely - if(min < 0) return; - sp->damage[index].type = type; - sp->damage[index].minnum = min; - sp->damage[index].value = val; - sp->damage[index].flags = flags; - sp->damage[index].dclass = cls; - sp->damage[index].effect = effect; -} - -void Game::ModifyEffectFlags(char *effect, int flags) -{ - EffectType *ep = FindEffect(effect); - if (ep == NULL) return; - ep->flags = flags; -} - -void Game::ModifyEffectAttackMod(char *effect, int val) -{ - EffectType *ep = FindEffect(effect); - if (ep == NULL) return; - ep->attackVal = val; -} - -void Game::ModifyEffectDefenseMod(char *effect, int index, int type, int val) -{ - EffectType *ep = FindEffect(effect); - if (ep == NULL) return; - if(type < 0 || type > NUM_ATTACK_TYPES) return; - if(index < 0 || index > 4) return; - ep->defMods[index].type = type; - ep->defMods[index].val = val; -} - -void Game::ModifyEffectCancelEffect(char *effect, char *uneffect) -{ - EffectType *ep = FindEffect(effect); - if (ep == NULL) return; - if (uneffect && (FindEffect(uneffect) == NULL)) return; - ep->cancelEffect = uneffect; -} - -void Game::ModifyRangeFlags(char *range, int flags) -{ - RangeType *rp = FindRange(range); - if (rp == NULL) return; - rp->flags = flags; -} - -void Game::ModifyRangeClass(char *range, int rclass) -{ - RangeType *rp = FindRange(range); - if (rp == NULL) return; - if(rclass < 0 || rclass > (RangeType::NUMRANGECLASSES-1)) return; - rp->rangeClass = rclass; -} - -void Game::ModifyRangeMultiplier(char *range, int mult) -{ - RangeType *rp = FindRange(range); - if (rp == NULL) return; - if(mult < 1) return; - rp->rangeMult = mult; -} - -void Game::ModifyRangeLevelPenalty(char *range, int pen) -{ - RangeType *rp = FindRange(range); - if (rp == NULL) return; - if(pen < 0) return; - rp->crossLevelPenalty = pen; -} - -void Game::ModifyAttribMod(char *mod, int index, int flags, char *ident, - int type, int val) -{ - AttribModType *mp = FindAttrib(mod); - if (mp == NULL) return; - if (index < 0 || index > 5) return; - if (!ident) return; - if (type < 0 || type > AttribModItem::NUMMODTYPE-1) return; - - mp->mods[index].flags = flags; - mp->mods[index].ident = ident; - mp->mods[index].modtype = type; - mp->mods[index].val = val; -} diff --git a/arcadia/monsters.cpp b/arcadia/monsters.cpp deleted file mode 100644 index 286f93102..000000000 --- a/arcadia/monsters.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2001/Mar/03 Joseph Traub Moved some of the monster stuff here -// -#include "gamedata.h" -#include "game.h" - -void Game::CreateVMons() -{ - if(!Globals->LAIR_MONSTERS_EXIST) return; - - forlist(®ions) { - ARegion * r = (ARegion *) elem; - forlist(&r->objects) { - Object * obj = (Object *) elem; - if(obj->type != O_BKEEP) continue; - Faction *monfac = GetFaction( &factions, 2 ); - Unit *u = GetNewUnit( monfac, 0 ); - u->MakeWMon( "Arch Dragons", I_DRAGON, 6); - u->MoveUnit(obj); - } - } -} - -void Game::GrowVMons() -{ - if(!Globals->LAIR_MONSTERS_EXIST) return; - - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *obj = (Object *)elem; - if(obj->type != O_BKEEP) continue; - forlist(&obj->units) { - Unit *u = (Unit *)elem; - int men = u->GetMen(I_DRAGON); - if(men > 0) men += 2; - if(men > 4) men = 4; - u->items.SetNum(I_DRAGON, men); - } - } - } -} diff --git a/arcadia/monthorders.cpp b/arcadia/monthorders.cpp deleted file mode 100644 index e0a28d44f..000000000 --- a/arcadia/monthorders.cpp +++ /dev/null @@ -1,2323 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2000/MAR/14 Larry Stanbery Added production enhancement. -// 2000/MAR/21 Azthar Septragen Added roads. -// 2001/Feb/21 Joseph Traub Added FACLIM_UNLIMITED -#ifndef DEBUG -//#define DEBUG -#endif - - -#include "game.h" -#include "gamedata.h" - -void Game::SailShips(ARegion *r, int phase, AList * regs) -{ - //created 10 March 2004 to allow ships to move one region at a time - //during the move cycle - int tmpError = 0; - - forlist(&r->objects) { - Object * o = (Object *) elem; - Unit * u = o->GetOwner(); - if (u && u->movepoints == phase && u->monthorders && - u->monthorders->type == O_SAIL && - o->IsBoat()) { - if(o->incomplete < 1) { -// locations->Add(DoASailOrder(r,o,u)); - ARegionPtr * p = new ARegionPtr; - p->ptr = DoASailOrder(r,o,u); - regs->Add(p); - } else { - tmpError = 1; - } - } else { - tmpError = 2; - } - - if(tmpError && phase == 0 && u && u->movepoints == 0) { //ie no errors here on later phases, or in first phase if ship has already sailed into this region. - forlist(&o->units) { - Unit * u2 = (Unit *) elem; - if (u2->monthorders && u2->monthorders->type == O_SAIL) { - switch(tmpError) { - case 1: - u2->Error("SAIL: Ship is not finished.", u2->monthorders->quiet); - break; - case 2: - if(o->IsBoat()) u2->Error("SAIL: Owner must sail ship.", u2->monthorders->quiet); - else u2->Error("SAIL: That unit is not in a ship.", u2->monthorders->quiet); - break; - } - delete u2->monthorders; - u2->monthorders = 0; - } - } - } - } -} - -ARegion * Game::DoASailOrder(ARegion *reg, Object *ship, Unit *captain) -{ - AList facs; - int wgt = 0; - int slr = 0; - int movepoints = ObjectDefs[ship->type].speed; - int moved = 1; - - Unit * windmage = 0; - int windlevel = 0; - - int firstmove = 0; - if (captain->movepoints == 0) firstmove = 1; - - //get move direction - int dir; - int quiet; - if(captain->monthorders->type == O_SAIL) { - SailOrder * o = (SailOrder *) captain->monthorders; - quiet = o->quiet; - if (o->dirs.Num()) { - MoveDir * x = (MoveDir *) o->dirs.First(); - o->dirs.Remove(x); - dir = x->dir; - delete x; - } else goto done_sailing; - } else if(captain->monthorders->type == O_FOLLOW) { - FollowOrder * o = (FollowOrder *) captain->monthorders; - dir = o->dir; - quiet = o->quiet; - } else goto done_sailing; //this should never occur. - - - { - int shipclass = 1; - if(ObjectDefs[ship->type].capacity > 499) shipclass++; - if(ObjectDefs[ship->type].capacity > 1200) shipclass++; - - //check weight onboard (need to do this every move, because someone might get on with a moveenter command). Also check SWIN mages - forlist(&ship->units) { - Unit * unit = (Unit *) elem; - if (unit->guard == GUARD_GUARD) unit->guard = GUARD_NONE; - if (!GetFaction2(&facs,unit->faction->num)) { - FactionPtr * p = new FactionPtr; - p->ptr = unit->faction; - facs.Add(p); - } - wgt += unit->Weight(); - if (unit == captain || (unit->monthorders && unit->monthorders->type == O_SAIL) ) { //captain may not have orders to sail if he is FOLLOWing. - slr += unit->GetSkill(S_SAILING) * unit->GetMen(); - } - if(ship->speedbonus == 0 && unit->GetSkill(S_SUMMON_WIND) > windlevel && (!Globals->ARCADIA_MAGIC || unit->energy >= unit->GetCastCost(S_SUMMON_WIND, 1, shipclass) ) ) { - windlevel = unit->GetSkill(S_SUMMON_WIND); - windmage = unit; - } - } - - if(windlevel >= shipclass) { - if(Globals->ARCADIA_MAGIC) { - //summon_wind speed bonus for ARCADIA - ship->speedbonus = (windlevel*movepoints)/5; - if (ship->speedbonus == 0) ship->speedbonus = 1; //minimum bonus of 1. If don't want this, must prevent casting, else will cast every ship move - if(windmage) { - windmage->energy -= windmage->GetCastCost(S_SUMMON_WIND, 1, shipclass); - windmage->Event("Casts Summon Wind to aid the ship's " - "progress."); - windmage->Practice(S_SUMMON_WIND); - windmage->Experience(S_SUMMON_WIND,10); - } - #ifdef DEBUG - if (windlevel & !windmage) { - Awrite("Windlevel but no windmage"); - system("pause"); - } - #endif - } else { - //non-Arcadia coding - movepoints += 2; - if(windmage && captain->movepoints == 0) { - windmage->Event("Casts Summon Wind to aid the ship's " - "progress."); - windmage->Practice(S_SUMMON_WIND); - windmage->Experience(S_SUMMON_WIND,10); - } - } - } - - movepoints += ship->speedbonus; //have to do it this way so bonus carries over to subsequent phases (but only if the mage had the energy to cast SWIN originally) - - if (wgt > ObjectDefs[ship->type].capacity) { - captain->Error("SAIL: Ship is overloaded.", quiet); - moved = 0; - } else if (slr < ObjectDefs[ship->type].sailors) { - captain->Error("SAIL: Not enough sailors.", quiet); - moved = 0; - } else { - //guts of the sailing code, and movepoints check. - /* Hexside Patch 030825 BS */ - int cost = 1; - int newhexside = -1; - int waterdepth = 0; - - - if(ship->hexside < 0) { //ie starts from the middle of a hex. - ARegion * newreg = reg->neighbors[dir]; - if (!newreg) { - captain->Error("SAIL: Can't sail that way.", quiet); //ARCADIAN_CHECKER: This will give info away in underground caverns unless blocks are removed - goto done_sailing; - } - if(Globals->WEATHER_EXISTS) { - if (newreg->weather != W_NORMAL && !ship->speedbonus && !newreg->clearskies) cost *= 2; - if (newreg->weather == W_BLIZZARD && !ship->speedbonus && !newreg->clearskies) cost *= 5; - } - - if (!(ObjectDefs[ship->type].flags & ObjectType::SAILOVERLAND) && !newreg->IsCoastal()) { - captain->Error("SAIL: Can't sail inland.", quiet); - goto done_sailing; - } - - if (!(ObjectDefs[ship->type].flags & ObjectType::SAILOVERLAND) && //remember this is for ships starting in the centre of the hex, so if - (TerrainDefs[reg->type].similar_type != R_OCEAN && TerrainDefs[reg->type].similar_type != R_FAKE) && //if the hex is not ocean, we are clearly NOT using hexside terrain rules. - (TerrainDefs[newreg->type].similar_type != R_OCEAN && TerrainDefs[newreg->type].similar_type != R_FAKE)) { - captain->Error("SAIL: Can't sail inland.", quiet); - goto done_sailing; - } - - // Check to see if sailing THROUGH land! - // always allow retracing steps - //This section was not modified by BS in changing the sailing rules March '04 - //This section not made compatible with ARCADIAN_CHECKER patch - if (Globals->PREVENT_SAIL_THROUGH && - (TerrainDefs[reg->type].similar_type != R_OCEAN) && - !(ObjectDefs[ship->type].flags & ObjectType::SAILOVERLAND) && - (ship->prevdir != -1) && - (ship->prevdir != dir) && !Globals->HEXSIDE_TERRAIN) { - int blocked1 = 0; - int blocked2 = 0; - int d1 = ship->prevdir; - int d2 = dir; - if (d1 > d2) { - int tmp = d1; - d1 = d2; - d2 = tmp; - } - for (int k = d1+1; k < d2; k++) { - ARegion *land1 = reg->neighbors[k]; - if ((!land1) || - (TerrainDefs[land1->type].similar_type != - R_OCEAN)) - blocked1 = 1; - } - int sides = NDIRS - 2 - (d2 - d1 - 1); - for (int l = d2+1; l <= d2 + sides; l++) { - int dl = l; - if (dl >= NDIRS) dl -= NDIRS; - ARegion *land2 = reg->neighbors[dl]; - if ((!land2) || - (TerrainDefs[land2->type].similar_type != - R_OCEAN)) - blocked2 = 1; - } - if ((blocked1) && (blocked2)) - { - captain->Error(AString("SAIL: Could not sail ") + - DirectionStrs[dir] + AString(" from ") + - reg->ShortPrint(®ions) + - ". Cannot sail through land.", quiet); - goto done_sailing; - } - } - - - /* Hexside Patch 030825 BS */ - // set hexside value for hexside ships - newhexside = -1; - if((TerrainDefs[newreg->type].similar_type != R_OCEAN && TerrainDefs[newreg->type].similar_type != R_FAKE) && ObjectDefs[ship->type].hexside && Globals->HEXSIDE_TERRAIN) { - //check if the ship can land here. Since it is at sea, it cannot be river-only [Changed: it could be shallow only on a lake]. Check if the terrain forbids ocean-only ships. - waterdepth = HexsideDefs[newreg->hexside[reg->GetRealDirComp(dir)]->type].sailable; - cost = (cost+1) / 2; //ie 1 in winter, 3 in blizzard - - if(waterdepth==1 && ObjectDefs[ship->type].sailable==2) { - captain->Error(AString("SAIL: Water is too shallow for ship to approach ") + newreg->ShortPrint(®ions), quiet); - goto done_sailing; - } - if(waterdepth==2 && ObjectDefs[ship->type].sailable==1) { //currently no hexside terrain with depth 2, but put in just in case of shallow ship sailing from a lake to such terrain - captain->Error(AString("SAIL: Water is too deep for ship to approach. NB This should never occur in Arcadia, contact your GM!") + newreg->ShortPrint(®ions), 0); - goto done_sailing; - } - if(waterdepth==0) { - captain->Error(AString("SAIL: Terrain prevents ship sailing to ") + newreg->ShortPrint(®ions), quiet); - goto done_sailing; - } - newhexside = reg->GetRealDirComp(dir); //this is the hexside we land at. - } - // else hexside value remains -1. Eg if hexside rules are turned off. - // for shallow ships on a lake, we are relying on lakes never being adjacent to oceans. Otherwise we need a depth check here also. - - if (movepoints - captain->movepoints < cost) { - if(captain->monthorders->type == O_SAIL) { - SailOrder *o = (SailOrder *) captain->monthorders; - captain->Error("SAIL: Can't sail that far;" - " remaining moves queued.", quiet); - TurnOrder *tOrder = new TurnOrder; - tOrder->repeating = 0; - AString order = "SAIL "; - order += DirectionAbrs[dir]; - forlist(&o->dirs) { - MoveDir *move = (MoveDir *) elem; - order += " "; - order += DirectionAbrs[move->dir]; - } - tOrder->turnOrders.Add(new AString(order)); - captain->turnorders.Insert(tOrder); - } else { - captain->Error("SAIL: Unit has insufficient movement points to continue following.", quiet); - } - goto done_sailing; - } - - captain->movepoints += cost; //at the moment, captain of ship cannot change mid-sail (well, except for unlikely event of him being killed, in which case if replacement had sail orders they'll be phase 0 so never called). If ever a unit is allowed to sail then move, then need to update all shipboard unit's movepoints at this step. - ship->MoveObject(newreg); - ship->SetPrevDir(reg->GetRealDirComp(dir)); - ship->hexside = newhexside; - forlist(&facs) { //it might be more convenient to give messages for each unit who helps with sailing. However, this is more concise on the report. - Faction * f = ((FactionPtr *) elem)->ptr; - if(newhexside>-1) f->Event(*ship->name + AString(" sails from ") + - reg->ShortPrint(®ions) + AString(" to ") + - newreg->ShortPrint(®ions) + " (" + DirectionStrs[newhexside] + AString(").")); - else f->Event(*ship->name + AString(" sails from ") + - reg->ShortPrint(®ions) + AString(" to ") + - newreg->ShortPrint(®ions) + AString(".")); - } - if(Globals->TRANSIT_REPORT != GameDefs::REPORT_NOTHING) { - forlist(&ship->units) { - // Everyone onboard gets to see the sights - Unit *unit = (Unit *)elem; - Farsight *f; - // Note the hex being left - forlist(®->passers) { - f = (Farsight *)elem; - if(f->unit == unit) { - // We moved into here this turn - f->exits_used[dir] = 1; - } - } - // And mark the hex being entered - f = new Farsight; - f->faction = unit->faction; - f->level = 0; - f->unit = unit; - f->exits_used[reg->GetRealDirComp(dir)] = 1; - newreg->passers.Add(f); - } - } - reg = newreg; //updates for region returned. - if (newreg->ForbiddenShip(ship) && !Globals->HEXSIDE_TERRAIN) { //with hexside rules, we are on a beach, so guards are NOT going to stop us. - captain->faction->Event(*ship->name + - AString(" is stopped by guards in ") + - newreg->ShortPrint(®ions) + AString(".")); - goto done_sailing; - } - } - - else { //ie (ship->hexside (originally) > -1) - //Thus, we are clearly using hexside sailing rules ;) - newhexside = -1; - ARegion * newreg = reg; - - //if sailing is in same direction as hexside, cross river or enter sea - if(dir==ship->hexside) { - newreg = reg->neighbors[dir]; - if (!newreg) { - captain->Error("SAIL: Can't sail that way - no region present.", quiet); - goto done_sailing; - } - newhexside = (ship->hexside+3)%6; //ie opposite edge. Could also use GetCompDir here I think. - } - - //if sailing to the same hex - else if(dir == (ship->hexside+2)%6 || dir == (ship->hexside+4)%6) { - newreg = reg; - if(dir == (ship->hexside+2)%6) { - newhexside = (ship->hexside+1)%6; //eg if on N hexside sailing SE, move to NE hexside of same region. - } - if(dir == (ship->hexside+4)%6 ) { - newhexside = (ship->hexside+5)%6; //eg if on N hexside sailing SW, move to NW hexside of same region. - } - } - - //if sailing to a new river section & new hex - else if(dir == (ship->hexside+1)%6 || dir == (ship->hexside+5)%6 ) { - newreg = reg->neighbors[dir]; - if (!newreg) { - captain->Error("SAIL: Can't sail that way - no region present.", quiet); - goto done_sailing; - } - if(dir == (ship->hexside+1)%6 ) { - newhexside = (ship->hexside+5)%6; //eg if on N hexside sailing NE, move to NW hexside of NE region. - } - if(dir == (ship->hexside+5)%6 ) { - newhexside = (ship->hexside+1)%6; //eg if on N hexside sailing NW, move to NE hexside of NW region - } - } - - //if sailing towards hex centre - else if(dir == (ship->hexside+3)%6 ) { - captain->Error("SAIL: Can't sail across land", quiet); - goto done_sailing; - } - else { - captain->Error("SAIL: This sailing error should never be called. Contact your GM.", 0); - goto done_sailing; - } - - if(newhexside<0 || newhexside>5) { - captain->Error("SAIL: This hexside error should never be called. Contact your GM", 0); - goto done_sailing; - } - //we now have the new region and new hexside! - //check that the new region/hexside can be sailed to! - cost = 1; - waterdepth = 0; - if(TerrainDefs[newreg->type].similar_type == R_OCEAN || TerrainDefs[newreg->type].similar_type == R_FAKE) { - newhexside=-1; - if(newreg->type == R_LAKE) waterdepth=3; //anything can sail onto a lake. - else waterdepth=2; - } - else if(!Globals->HEXSIDE_TERRAIN) { // This could get called if a game goes through rule changes. Otherwise it should never be. - newhexside = -1; - } - else { - waterdepth = HexsideDefs[newreg->hexside[newhexside]->type].sailable; - - //if have found no sailable object, check if it is a beach with no beach object from bad world generation -/* if(!waterdepth) { - if(TerrainDefs[newreg->neighbors[newhexside]->type].similar_type == R_OCEAN) waterdepth = 2; //This looks strange, but is checking the hexside the boat is on to see if it is adjacent to ocean/lake, and saying that in the absence of a beach we will treat it like ocean. - } */ //removed as this was allowing sailing onto rocks - } - if(!waterdepth) { - captain->Error("SAIL: That location cannot be sailed to.", quiet); - goto done_sailing; - } - if(ObjectDefs[ship->type].sailable != waterdepth && ObjectDefs[ship->type].sailable != 3 && waterdepth != 3) { - captain->Error("SAIL: That ship type cannot sail there.", quiet); - goto done_sailing; - } - - if(Globals->WEATHER_EXISTS) { - if (newreg->weather == W_BLIZZARD && !ship->speedbonus && !newreg->clearskies) cost = cost * 5; - else if (newreg->weather != W_NORMAL && !ship->speedbonus && !newreg->clearskies) cost = cost * 2; - } - if(newhexside != -1) cost = (cost+1)/2; //ie half cost for moving to hexsides (rounded up). - - // if cannot move - if (movepoints - captain->movepoints < cost) { - if(captain->monthorders->type == O_SAIL) { - SailOrder *o = (SailOrder *) captain->monthorders; - captain->Error("SAIL: Can't sail that far;" - " remaining moves queued.", quiet); - TurnOrder *tOrder = new TurnOrder; - tOrder->repeating = 0; - AString order = "SAIL "; - order += DirectionAbrs[dir]; - forlist(&o->dirs) { - MoveDir *move = (MoveDir *) elem; - order += " "; - order += DirectionAbrs[move->dir]; - } - tOrder->turnOrders.Add(new AString(order)); - captain->turnorders.Insert(tOrder); - } else { - captain->Error("SAIL: Unit has insufficient movement points to continue following.", quiet); - } - goto done_sailing; - } - //move the ship - captain->movepoints += cost; - ship->MoveObject(newreg); - ship->SetPrevDir(dir); //This is obsolete with hexside stuff. Could just as well discard it. - forlist(&facs) { - Faction * f = ((FactionPtr *) elem)->ptr; - if(newhexside>-1) f->Event(*ship->name + AString(" sails from ") + - reg->ShortPrint(®ions) + " (" + DirectionStrs[ship->hexside] + AString(") to ") + - newreg->ShortPrint(®ions) + " (" + DirectionStrs[newhexside] + AString(").")); - else f->Event(*ship->name + AString(" sails from ") + - reg->ShortPrint(®ions) + " (" + DirectionStrs[ship->hexside] + AString(") to ") + - newreg->ShortPrint(®ions) + AString(".")); - } - ship->hexside = newhexside; - - //do post-move stuff - if(Globals->TRANSIT_REPORT != GameDefs::REPORT_NOTHING && newreg != reg) { - forlist(&ship->units) { - // Everyone onboard gets to see the sights - Unit *unit = (Unit *)elem; - Farsight *f; - // Note the hex being left - forlist(®->passers) { - f = (Farsight *)elem; - if(f->unit == unit) { - // We moved into here this turn - f->exits_used[dir] = 1; - } - } - // And mark the hex being entered - f = new Farsight; - f->faction = unit->faction; - f->level = 0; - f->unit = unit; - f->exits_used[newreg->GetRealDirComp(dir)] = 1; - newreg->passers.Add(f); - } - } - reg = newreg; //updates for region returned. - if (newreg->ForbiddenShip(ship)) { //ship can be stopped once on each edge, as long as that edge is not a coastal edge (ie adjacent to sea) since in that case guards could hardly stop the ship. - if(!newreg->neighbors[newhexside] || TerrainDefs[newreg->neighbors[newhexside]->type].similar_type != R_OCEAN) { - captain->faction->Event(*ship->name + - AString(" is stopped by guards in ") + - newreg->ShortPrint(®ions) + AString(".")); - goto done_sailing; - } - } - //end of the hexside ships stuff - } - } - } - - - /* Clear out move orders */ - forlist(&ship->units) { - Unit * unit = (Unit *) elem; - if (moved) { - unit->alias = 0; - if (firstmove && (unit == captain || (unit->monthorders && unit->monthorders->type == O_SAIL))) { //captain might have FOLLOW orders - unit->Practice(S_SAILING); - unit->Experience(S_SAILING,10); - } - if (unit->monthorders && unit->monthorders->type == O_MOVE) { - delete unit->monthorders; - unit->monthorders = 0; - } - } - } - return reg; - -done_sailing: - { - if(captain->movepoints > 0) moved = 1; //we might not have moved this phase, but we moved in an earlier phase. - /* Clear out everyone's orders */ - forlist(&ship->units) { - Unit * unit = (Unit *) elem; - if (moved) { - unit->alias = 0; - } - - if (unit->monthorders) { -/* if ((unit == captain || unit->monthorders->type == O_SAIL) && moved) { //captain might have FOLLOW orders - unit->Practice(S_SAILING); - unit->Experience(S_SAILING,10); - }*/ - if ((moved && unit->monthorders->type == O_MOVE) || //I don't think a unit here could still have move orders, but just in case. Well, why not? MOVE N 123 N - unit->monthorders->type == O_SAIL) { - delete unit->monthorders; - unit->monthorders = 0; - } - } - } - - return reg; //why do we need to return a location if we haven't moved? - } -} - -void Game::RunTeachOrders() -{ - forlist((®ions)) { - ARegion * r = (ARegion *) elem; - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->monthorders) { - if (u->monthorders->type == O_TEACH) { - Do1TeachOrder(r,u); - delete u->monthorders; - u->monthorders = 0; - } - } - } - } - } -} - -void Game::Do1TeachOrder(ARegion * reg,Unit * unit) -{ - TeachOrder * order = (TeachOrder *) unit->monthorders; - int quiet = order->quiet; - - /* First pass, find how many to teach */ - if(unit->IsNormal()) { - /* small change to handle Ceran's mercs */ - if(!unit->GetMen(I_MERC)) { - // Mercs can teach even though they are not leaders. - // They cannot however improve their own skills - unit->Error("TEACH: Normal units cannot teach.", quiet); - return; - } - } - - int students = 0; - forlist(&order->targets) { - UnitId * id = (UnitId *) elem; - Unit * target = reg->GetUnitId(id,unit->faction->num); - if (!target) { - order->targets.Remove(id); - unit->Error("TEACH: No such unit.", quiet); - delete id; - } else { - if (target->faction->GetAttitude(unit->faction->num) < A_FRIENDLY) { - unit->Error(AString("TEACH: ") + *(target->name) + - " is not a member of a friendly faction.", quiet); - order->targets.Remove(id); - delete id; - } else { - if ((!target->monthorders || - target->monthorders->type != O_STUDY ) && (!Globals->ARCADIA_MAGIC || !target->IsMage() || !target->herostudyorders) ) { - unit->Error(AString("TEACH: ") + *(target->name) + - " is not studying.", quiet); - order->targets.Remove(id); - delete id; - } else { - int sk; - if(Globals->ARCADIA_MAGIC && target->IsMage() && target->herostudyorders) { - sk = ((StudyOrder *) target->herostudyorders)->skill; - } else sk = ((StudyOrder *) target->monthorders)->skill; - if (unit->GetRealSkill(sk) <= target->GetRealSkill(sk) && unit->GetDaysSkill(sk) <= target->GetDaysSkill(sk)) { - /* REAL_EXPERIENCE Patch: Can teach units with lower total skill OR lower days skill */ - unit->Error(AString("TEACH: ") + - *(target->name) + " is not studying " - "a skill you can teach.", quiet); - order->targets.Remove(id); - delete id; - } else { - // Check whether it's a valid skill to teach - if ( (SkillDefs[sk].flags & SkillType::NOTEACH) || - ((SkillDefs[sk].flags & SkillType::MAGIC) && Globals->CANT_TEACH_MAGIC) ) { - unit->Error(AString("TEACH: ") + - AString(SkillDefs[sk].name) + - " cannot be taught.", quiet); - return; - } else { - students += target->GetMen(); - } - } - } - } - } - } - if (!students) return; - - int days = (30 * unit->GetMen() * Globals->STUDENTS_PER_TEACHER); - - /* We now have a list of valid targets */ - { - forlist(&order->targets) { - UnitId * id = (UnitId *) elem; - Unit * u = reg->GetUnitId(id,unit->faction->num); - - //int sk = ((StudyOrder *) u->monthorders)->skill; - int sk; - if(Globals->ARCADIA_MAGIC && u->IsMage() && u->herostudyorders) { - sk = ((StudyOrder *) u->herostudyorders)->skill; - } else sk = ((StudyOrder *) u->monthorders)->skill; - - int umen = u->GetMen(); - int tempdays = (umen * days) / students; - if (tempdays > 30 * umen) tempdays = 30 * umen; - - /* REAL_EXPERIENCE Patch*/ -/* -//removed this limitation (cannot be taught beyond teacher level) for Nylandor. Besides, it wasn't working properly. Check it out sometime, I think the problem is in the third line. - - int teacherexp = unit->GetExperSkill(sk) - u->GetExperSkill(sk); //if have higher experience, can teach student beyond own study level. - if (teacherexp < 0 ) teacherexp = 0; //this is 0,1,2,3 - ie the level difference - int daysaboveteacher = u->skills.GetDays(sk) + tempdays - umen * GetDaysByLevel(unit->GetDaysSkill(sk) + teacherexp); - if(daysaboveteacher > 0) tempdays -= daysaboveteacher; -*/ - if(tempdays < 0) tempdays = 0; // shouldn't be necessary, but just in case. - - days -= tempdays; //reducing the teacher attributes of how many people he can teach! - students -= umen; - - StudyOrder * o = (StudyOrder *) u->monthorders; - if(Globals->ARCADIA_MAGIC && u->herostudyorders) o = (StudyOrder *) u->herostudyorders; - - o->days += tempdays; - if (o->days > 30 * umen) // this bit returns any spare days to the teacher - { - days += o->days - 30 * umen; - o->days = 30 * umen; - } - unit->Event(AString("Teaches ") + SkillDefs[o->skill].name + - " to " + *u->name + "."); - // The TEACHER may learn something in this process! - unit->Practice(o->skill); - } - //Recycle any spare teaching ability to stop multi-teaching only giving 29 days due to rounding down errors - if(days > 0) { - forlist_reuse(&order->targets) { - if(days < 1) continue; //we've allocated it all, break out. - - UnitId * id = (UnitId *) elem; - Unit * u = reg->GetUnitId(id,unit->faction->num); - - //int sk = ((StudyOrder *) u->monthorders)->skill; - int sk; - if(Globals->ARCADIA_MAGIC && u->IsMage() && u->herostudyorders) { - sk = ((StudyOrder *) u->herostudyorders)->skill; - } else sk = ((StudyOrder *) u->monthorders)->skill; - - int umen = u->GetMen(); - - StudyOrder * o = (StudyOrder *) u->monthorders; - if(Globals->ARCADIA_MAGIC && u->herostudyorders) o = (StudyOrder *) u->herostudyorders; - - if (o->days < 30 * umen) // this unit can still be taught - { - o->days += days; - days = 0; - } - //check if we've given too much: - if (o->days > 30 * umen) // this bit returns any spare days to the teacher - { - days += o->days - 30 * umen; - o->days = 30 * umen; - } - } - } - } - -} - -/* Hexside Patch 030825 BS */ -int Game::HexsideCanGoThere(ARegion * r,Object * obj,Unit * u) -{ - int dir = obj->hexside; - if(dir < 0 || dir > 5) return 0; - -/* Ship may be built on sailable hexside of correct depth */ - int depth = HexsideDefs[r->hexside[dir]->type].sailable; - if(depth < 1) return 0; - int shiptype = ObjectDefs[obj->type].sailable; - if(depth == shiptype || depth == 3 || shiptype == 3) return 1; - - return 0; -} - -void Game::Run1BuildOrder(ARegion * r,Object * obj,Unit * u) -{ - int quiet = u->monthorders->quiet; - - if (!TradeCheck(r, u->faction)) { - u->Error("BUILD: Faction can't produce in that many regions.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - AString skname = ObjectDefs[obj->type].skill; - int sk = LookupSkill(&skname); - if (sk == -1) { - u->Error("BUILD: Can't build that.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int usk = u->GetSkill(sk); - if (usk < ObjectDefs[obj->type].level) { - u->Error("BUILD: Can't build that.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if ((Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) && (obj->type == O_OBANK)) { // trying to build a bank ? - if ((Globals->ALLOW_BANK & GameDefs::BANK_NOTONGUARD) && !(r->CanTax(u))) { - u->Error("BUILD: Cannot build banks if there are guarding units.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if (!r->town && (Globals->ALLOW_BANK & GameDefs::BANK_INSETTLEMENT)) { - u->Error("BUILD: Cannot build banks outside settlements.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if ((Globals->ALLOW_BANK & GameDefs::BANK_SKILLTOBUILD) && (SkillDefs[S_BANKING].flags & SkillType::DISABLED)) { - // GM error - requested banking skill to build but skill is disabled - u->Error("BUILD: Impossible to build banks due to missing skill.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if ((Globals->ALLOW_BANK & GameDefs::BANK_SKILLTOBUILD) && (!u->GetSkill(S_BANKING))) { - u->Error("BUILD: Can't build that.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - } else if (obj->type == O_OBANK) { // This is only if a dumb GM enables banks but not the gamedef - u->Error("BUILD: Bank ? What is that ?", quiet); // maybe give same error "Can't build that." ? - delete u->monthorders; - u->monthorders = 0; - return; - } - - - int needed = obj->incomplete; - int type = obj->type; - // AS - if(((ObjectDefs[type].flags&ObjectType::NEVERDECAY) || !Globals->DECAY) && - needed < 1) { - u->Error("BUILD: Object is finished.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - // AS - if(needed <= -(ObjectDefs[type].maxMaintenance)) { - u->Error("BUILD: Object does not yet require maintenance.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - -/* Hexside Patch 030825 BS */ - if(Globals->HEXSIDE_TERRAIN) { - if(ObjectDefs[type].hexside && obj->hexside==-1) { - u->Error("BUILD: Problem type 1 with hexside terrain, please contact your GM", 0); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(!ObjectDefs[type].hexside && obj->hexside>-1) { - u->Error("BUILD: Problem type 2 with hexside terrain, please contact your GM", 0); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(ObjectDefs[type].hexside) { - if (!HexsideCanGoThere(r,obj,u)) { - u->Error("Build: That structure cannot not be built there.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - } - } - int it = ObjectDefs[type].item; - int itn; - if (it == I_WOOD_OR_STONE) { - itn = u->GetSharedNum(I_WOOD) + u->GetSharedNum(I_STONE); - } else { - itn = u->GetSharedNum(it); - } - - if (itn == 0) { - u->Error("BUILD: Don't have the required item.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int num = u->GetMen() * usk; - - // JLT - if(obj->incomplete == ObjectDefs[type].cost) { - if(ObjectIsShip(type)) { - obj->num = shipseq++; - obj->SetName(new AString("Ship")); - } else { - obj->num = u->object->region->buildingseq++; - obj->SetName(new AString("Building")); - } - } - - // Hack to fix bogus ship numbers - if(ObjectIsShip(type) && obj->num < 100) { - obj->num = shipseq++; - obj->SetName(new AString("Ship")); - } - - // AS - AString job; - if (needed < 1) { - // This looks wrong, but isn't. - // If a building has a maxMaintainence of 75 and the road is at - // -70 (ie, 5 from max) then we want the value of maintMax to be - // 5 here. Then we divide by maintFactor (some things are easier - // to refix than others) to get how many items we need to fix it. - // Then we fix it by that many items * maintFactor - int maintMax = ObjectDefs[type].maxMaintenance + needed; - maintMax /= ObjectDefs[type].maintFactor; - if (num > maintMax) num = maintMax; - if (itn < num) num = itn; - job = " maintenance "; - obj->incomplete -= (num * ObjectDefs[type].maintFactor); - if (obj->incomplete < -(ObjectDefs[type].maxMaintenance)) - obj->incomplete = -(ObjectDefs[type].maxMaintenance); - } else if(needed > 0) { - if (num > needed) num = needed; - if (itn < num) num = itn; - job = " construction "; - obj->incomplete -= num; - if (obj->incomplete == 0) { - obj->incomplete = -(ObjectDefs[type].maxMaintenance); - } - } - - /* Perform the build */ - u->MoveUnit(obj); //BS: I don't think this should be there. obj has been imported as the object the unit is in, so it does not need to be moved there! - - if (it == I_WOOD_OR_STONE) { - if (num > u->items.GetNum(I_STONE)) { - num -= u->items.GetNum(I_STONE); - u->items.SetNum(I_STONE,0); - } else { - u->items.SetNum(I_STONE,u->items.GetNum(I_STONE) - num); - num = 0; - } - if (num > u->items.GetNum(I_WOOD)) { - num -= u->items.GetNum(I_WOOD); - u->items.SetNum(I_WOOD,0); - } else { - u->items.SetNum(I_WOOD,u->items.GetNum(I_WOOD) - num); - num = 0; - } - int sharedstone = u->GetSharedNum(I_STONE); - if (num > sharedstone) { - num -= sharedstone; - u->ConsumeShared(I_STONE, sharedstone); - u->ConsumeShared(I_WOOD, num); - } else { - u->ConsumeShared(I_STONE, num); - } - } else { - u->ConsumeShared(it,num); - } - - // AS - u->Event(AString("Performs") + job + "on " + *(obj->name) + "."); - u->Practice(sk); - u->Experience(sk,10); - - delete u->monthorders; - u->monthorders = 0; -} - -void Game::Run1BuildHexsideOrder(ARegion * r,Object * obj,Unit * u) -{ - int quiet = u->monthorders->quiet; - - if(!Globals->HEXSIDE_TERRAIN) return; - - if (!TradeCheck(r, u->faction)) { - u->Error("BUILD: Faction can't produce in that many regions.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - BuildHexsideOrder *o = (BuildHexsideOrder *)u->monthorders; - AString skname = HexsideDefs[o->terrain].skill; - int sk = LookupSkill(&skname); - if (sk == -1) { - u->Error("BUILD: Can't build that.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int usk = u->GetSkill(sk); - if (usk < HexsideDefs[o->terrain].level) { - u->Error("BUILD: Can't build that.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - Hexside *h = r->hexside[o->direction]; - if(!h) { - //This should never occur. - u->Error("BUILD: Hexside does not exist. Contact your GM.", 0); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int needed = 0; - // If hexside terrain gets expanded to other types, have to redo this! - if(o->terrain == H_ROAD) { - if(h->road < 0) { - u->Error("BUILD: Road is finished.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(!r->neighbors[o->direction] || TerrainDefs[r->neighbors[o->direction]->type].similar_type == R_OCEAN) { - u->Error("BUILD: A road cannot be built there.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(h->road == 0) h->road = HexsideDefs[o->terrain].cost; - needed = h->road; - } - else if(o->terrain == H_BRIDGE) { - //since bridge blockeffect = -1 - if(HexsideDefs[h->type].blockeffect != 1 && h->bridge <= 0) { //allow finishing a bridge if partially completed then dive moved the river. - u->Error("BUILD: Nothing to bridge.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(h->bridge < 0) { - u->Error("BUILD: Bridge is finished.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(h->bridge == 0) h->bridge = HexsideDefs[o->terrain].cost; - needed = h->bridge; - } - else if(o->terrain == H_HARBOUR) { - if(h->type != H_BEACH) { - u->Error("BUILD: Harbours can only be built on beaches.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(h->harbour < 0) { - //this should never occur - u->Error("BUILD: Harbour appears to be finished. Contact your GM.", 0); - delete u->monthorders; - u->monthorders = 0; - return; - } - if(h->harbour == 0) h->harbour = HexsideDefs[o->terrain].cost; - needed = h->harbour; - } - else { - u->Error("BUILD: Cannot BUILD that!", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int it = HexsideDefs[o->terrain].item; - int itn; - if (it == I_WOOD_OR_STONE) { - itn = u->GetSharedNum(I_WOOD) + u->GetSharedNum(I_STONE); - } else { - itn = u->GetSharedNum(it); - } - - if (itn == 0) { - u->Error("BUILD: Don't have the required item.", quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int num = u->GetMen() * usk; - - if (num > needed) num = needed; - if (itn < num) num = itn; - if(o->terrain == H_ROAD) { - h->road -= num; - if(h->road == 0) h->road = -1; - if(h->road >= HexsideDefs[o->terrain].cost) h->road = 0; - } else if(o->terrain == H_BRIDGE) { - h->bridge -= num; - if(h->bridge == 0) h->bridge = -1; - if(h->bridge >= HexsideDefs[o->terrain].cost) h->bridge = 0; - } else if(o->terrain == H_HARBOUR) { - h->harbour -= num; - if(h->harbour >= HexsideDefs[o->terrain].cost) h->harbour = 0; - if(h->harbour <= 0) { - //harbour is finished. - h->harbour = 0; - h->type = H_HARBOUR; - } - } - - /* Deduct the items */ - - u->MoveUnit(r->GetDummy()); - - if (it == I_WOOD_OR_STONE) { - - if (num > u->items.GetNum(I_STONE)) { - num -= u->items.GetNum(I_STONE); - u->items.SetNum(I_STONE,0); - } else { - u->items.SetNum(I_STONE,u->items.GetNum(I_STONE) - num); - num = 0; - } - if (num > u->items.GetNum(I_WOOD)) { - num -= u->items.GetNum(I_WOOD); - u->items.SetNum(I_WOOD,0); - } else { - u->items.SetNum(I_WOOD,u->items.GetNum(I_WOOD) - num); - num = 0; - } - int sharedstone = u->GetSharedNum(I_STONE); - if (num > sharedstone) { - num -= sharedstone; - u->ConsumeShared(I_STONE, sharedstone); - u->ConsumeShared(I_WOOD, num); - } else { - u->ConsumeShared(I_STONE, num); - } - } else { - u->ConsumeShared(it,num); - } - - // AS - u->Event(AString("Performs construction on ") + (HexsideDefs[o->terrain].name) + "."); - u->Practice(sk); - u->Experience(sk,10); - - delete u->monthorders; - u->monthorders = 0; -} - -void Game::RunBuildHelpers(ARegion *r) -{ - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist ((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->monthorders) { - if (u->monthorders->type == O_BUILD) { - BuildOrder *o = (BuildOrder *)u->monthorders; - Object *tarobj = NULL; - if(o->target) { - Unit *target = r->GetUnitId(o->target,u->faction->num); - if(!target) { - u->Error("BUILD: No such unit to help.", o->quiet); - delete u->monthorders; - u->monthorders = 0; - continue; - } - // Make sure that unit is building - if (target->monthorders && - target->monthorders->type != O_BUILD) { - u->Error("BUILD: Unit isn't building.", o->quiet); - delete u->monthorders; - u->monthorders = 0; - continue; - } - // Make sure that unit considers you friendly! - if(target->faction->GetAttitude(u->faction->num) < - A_FRIENDLY) { - u->Error("BUILD: Unit you are helping rejects " - "your help.", o->quiet); - delete u->monthorders; - u->monthorders = 0; - continue; - } - tarobj = target->build; - if (tarobj == NULL) tarobj = target->object; - if((tarobj != NULL) && (u->object != tarobj)) - u->MoveUnit(tarobj); - } else if (u->build != NULL && u->build != u->object) { - u->MoveUnit(u->build); - } - } - } - } - } -} - - -void Game::RunMonthOrders() -{ - forlist(®ions) { - ARegion * r = (ARegion *) elem; - - RunIdleOrders(r); - RunStudyOrders(r); - RunBuildHelpers(r); - RunProduceOrders(r); - } - if(Globals->ARCADIA_MAGIC) RunMasterOrders(); -} - -void Game::RunUnitProduce(ARegion * r,Unit * u) -{ - ProduceOrder * o = (ProduceOrder *) u->monthorders; - - if (o->item == I_SILVER) { - u->Error("Can't do that in this region.", o->quiet); -//u->Error(AString("Can't do that in this region. Error Code: ") + o->skill + " " + o->productivity, o->quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int input = ItemDefs[o->item].pInput[0].item; - if (input == -1) { - u->Error("PRODUCE: Can't produce that.", o->quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - int level = u->GetSkill(o->skill); - if (level < ItemDefs[o->item].pLevel) { - u->Error("PRODUCE: Can't produce that.", o->quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - if (!TradeCheck(r, u->faction)) { - u->Error("PRODUCE: Faction can't produce in that many regions.", o->quiet); - delete u->monthorders; - u->monthorders = 0; - return; - } - - // LLS - int number = u->GetMen() * level + u->GetProductionBonus(o->item); - - // find the max we can possibly produce based on man-months of labor - int maxproduced; - if (ItemDefs[o->item].flags & ItemType::SKILLOUT) - maxproduced = u->GetMen(); - else - maxproduced = number/ItemDefs[o->item].pMonths; - - if (ItemDefs[o->item].flags & ItemType::ORINPUTS) { - // Figure out the max we can produce based on the inputs - int count = 0; - unsigned int c; - for(c = 0; c < sizeof(ItemDefs->pInput)/sizeof(Materials); c++) { - int i = ItemDefs[o->item].pInput[c].item; - if(i != -1) - count += u->GetSharedNum(i) / ItemDefs[o->item].pInput[c].amt; - } - if (maxproduced > count) - maxproduced = count; - count = maxproduced; - - // Deduct the items spent - for(c = 0; c < sizeof(ItemDefs->pInput)/sizeof(Materials); c++) { - int i = ItemDefs[o->item].pInput[c].item; - int a = ItemDefs[o->item].pInput[c].amt; - if(i != -1) { - int amt = u->items.GetNum(i); - if (count > amt / a) { - count -= amt / a; - u->items.SetNum(i, amt-(amt/a)*a); - } else { - u->items.SetNum(i, amt - count * a); - count = 0; - } - } - } - // Recycle with sharing if necessary - for(c = 0; c < sizeof(ItemDefs->pInput)/sizeof(Materials); c++) { - int i = ItemDefs[o->item].pInput[c].item; - int a = ItemDefs[o->item].pInput[c].amt; - if(count && i != -1) { - int amt = u->GetSharedNum(i); - if (count > amt / a) { - count -= amt / a; - u->ConsumeShared(i, (amt/a)*a); - } else { - u->ConsumeShared(i, count * a); - count = 0; - } - } - } - } else { - // Figure out the max we can produce based on the inputs - unsigned int c; - for(c = 0; c < sizeof(ItemDefs->pInput)/sizeof(Materials); c++) { - int i = ItemDefs[o->item].pInput[c].item; - if(i != -1) { - int amt = u->GetSharedNum(i); - if(amt/ItemDefs[o->item].pInput[c].amt < maxproduced) { - maxproduced = amt/ItemDefs[o->item].pInput[c].amt; - } - } - } - - // Deduct the items spent - for(c = 0; c < sizeof(ItemDefs->pInput)/sizeof(Materials); c++) { - int i = ItemDefs[o->item].pInput[c].item; - int a = ItemDefs[o->item].pInput[c].amt; - if(i != -1) { - u->ConsumeShared(i, maxproduced*a); - } - } - } - - // Now give the items produced - int output = maxproduced * ItemDefs[o->item].pOut; - if (ItemDefs[o->item].flags & ItemType::SKILLOUT) - output *= level; - //u->items.SetNum(o->item,u->items.GetNum(o->item) + output); - //mod for Xanaxor games. Produced items go into list credited later to prevent SHARE reusing them for secondary prod: - u->itemsintransit.SetNum(o->item, u->itemsintransit.GetNum(o->item) + output); - - u->Event(AString("Produces ") + ItemString(o->item,output) + " in " + - r->ShortPrint(®ions) + "."); - u->Practice(o->skill); - u->Experience(o->skill,10); - delete u->monthorders; - u->monthorders = 0; -} - -void Game::RunProduceOrders(ARegion * r) -{ - forlist ((&r->products)) - RunAProduction(r,(Production *) elem); - { - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist ((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->monthorders) { - if (u->monthorders->type == O_PRODUCE) RunUnitProduce(r,u); - else if (u->monthorders->type == O_BUILD) Run1BuildOrder(r,obj,u); - else if (u->monthorders->type == O_BUILDHEXSIDE) Run1BuildHexsideOrder(r,obj,u); - } - } - } - } -} - -int Game::ValidProd(Unit * u,ARegion * r, Production * p) -{ - if (u->monthorders->type != O_PRODUCE) return 0; - - ProduceOrder * po = (ProduceOrder *) u->monthorders; - if (p->itemtype == po->item && p->skill == po->skill) { - if (p->skill == -1) { - po->productivity = u->GetMen() * p->productivity; - return po->productivity; - } - int level = u->GetSkill(p->skill); - // if (level < p->level) { - if (level < ItemDefs[p->itemtype].pLevel) { - u->Error("PRODUCE: Unit isn't skilled enough.", po->quiet); - delete u->monthorders; - u->monthorders = 0; - return 0; - } - - // - // Check faction limits on production. If the item is silver, then the - // unit is entertaining or working, and the limit does not apply - // - if (p->itemtype != I_SILVER && !TradeCheck(r, u->faction)) { - u->Error("PRODUCE: Faction can't produce in that many regions.", po->quiet); - delete u->monthorders; - u->monthorders = 0; - return 0; - } - - /* check for bonus production */ - // LLS - int bonus = u->GetProductionBonus(p->itemtype); - po->productivity = u->GetMen() * level * p->productivity + bonus; - return po->productivity; - } - return 0; -} - -int Game::FindAttemptedProd(ARegion * r,Production * p) -{ - int attempted = 0; - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->monthorders) { - attempted += ValidProd(u,r,p); - } - } - } - return attempted; -} - -void Game::RunAProduction(ARegion * r,Production * p) -{ - p->activity = 0; - if (p->amount == 0) return; - - /* First, see how many units are trying to work */ - int attempted = FindAttemptedProd(r,p); //This eliminates 'illegal' production orders - int amt = p->amount; - if (attempted < amt) attempted = amt; - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if(!u->monthorders || u->monthorders->type != O_PRODUCE) - { - continue; - } - - ProduceOrder * po = (ProduceOrder *) u->monthorders; - if (po->skill != p->skill || po->item != p->itemtype) - { - continue; - } - - /* We need to implement a hack to avoid overflowing */ - int uatt, ubucks; - - uatt = po->productivity; - if (uatt && amt && attempted) - { - double dUbucks = ((double) amt) * ((double) uatt) - / ((double) attempted); - ubucks = (int) dUbucks; - } - else - { - ubucks = 0; - } - - amt -= ubucks; - attempted -= uatt; - u->itemsintransit.SetNum(po->item, u->itemsintransit.GetNum(po->item) + ubucks); - p->activity += ubucks; - - /* Show in unit's events section */ - if (po->item == I_SILVER) - { - // - // WORK - // - if (po->skill == -1) - { - u->Event(AString("Earns ") + ubucks + " silver working in " - + r->ShortPrint(®ions) + "."); - } - else - { - // - // ENTERTAIN - // - u->Event(AString("Earns ") + ubucks - + " silver entertaining in " + - r->ShortPrint(®ions) - + "."); - u->Practice(S_ENTERTAINMENT); - if(ubucks) u->Experience(S_ENTERTAINMENT,10); - if(u->GetSkill(S_PHANTASMAL_ENTERTAINMENT)) { - u->Practice(S_PHANTASMAL_ENTERTAINMENT); - if(ubucks) u->Experience(S_PHANTASMAL_ENTERTAINMENT,10); - } - } - } - else - { - /* Everything else */ - u->Event(AString("Produces ") + ItemString(po->item,ubucks) + - " in " + r->ShortPrint(®ions) + "."); - u->Practice(po->skill); - if(ubucks) u->Experience(po->skill,10); - } - delete u->monthorders; - u->monthorders = 0; - } - } -} - -void Game::RunStudyOrders(ARegion * r) -{ - forlist((&r->objects)) { - Object * obj = (Object *) elem; - forlist((&obj->units)) { - Unit * u = (Unit *) elem; - if (u->monthorders) { - if (u->monthorders->type == O_STUDY) { - Do1StudyOrder(u,obj); - delete u->monthorders; - u->monthorders = 0; - } - } - if(Globals->ARCADIA_MAGIC && u->IsMage() && u->herostudyorders) { - Do1StudyOrder(u,obj); - delete u->herostudyorders; - u->herostudyorders = 0; - } - } - } -} - -void Game::RunIdleOrders(ARegion *r) -{ - forlist((&r->objects)) { - Object *obj = (Object *)elem; - forlist((&obj->units)) { - Unit *u = (Unit *)elem; - if (u->monthorders && u->monthorders->type == O_IDLE) { - u->Event("Sits idle."); - delete u->monthorders; - u->monthorders = 0; - } - } - } -} - -void Game::Do1StudyOrder(Unit *u,Object *obj) -{ - StudyOrder * o; - if(u->monthorders && u->monthorders->type == O_STUDY) o = (StudyOrder *) u->monthorders; - else o = u->herostudyorders; //ARCADIA_MAGIC MOD - - int sk = o->skill; - int cost = SkillCost(sk) * u->GetMen(); - if (!u->GetSharedMoney(cost)) { - u->Error("STUDY: Not enough funds.", o->quiet); - return; - } - - // Check that the skill can be studied - if (SkillDefs[sk].flags & SkillType::NOSTUDY) { - u->Error( AString("STUDY: ") + AString(SkillDefs[sk].name) + " cannot be studied.", o->quiet); - return; - } - - // Small patch for Ceran Mercs - if(u->GetMen(I_MERC)) { - u->Error("STUDY: Mercenaries are not allowed to study.", o->quiet); - return; - } - - if((SkillDefs[sk].flags & SkillType::MAGIC) && u->type != U_MAGE) { - u->Error("STUDY: That skill can only be studied by heroes.", o->quiet); - } - - if(sk == S_HEROSHIP && Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - if (CountMages(u->faction) >= AllowedMages(u->faction)) { - u->Error("STUDY: Faction has too many heroes.", o->quiet); - return; - } - } - - if((SkillDefs[sk].flags&SkillType::APPRENTICE) && u->type != U_APPRENTICE) { - u->Error("STUDY: That skill can only be studied by apprentices.", o->quiet); - } - -//TO CHECK: - if ((Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) && - (sk == S_QUARTERMASTER) && (u->GetRealSkill(S_QUARTERMASTER) == 0) && - (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES)) { - if (CountQuarterMasters(u->faction) >= - AllowedQuarterMasters(u->faction)) { - u->Error("STUDY: Can't have another quartermaster.", o->quiet); - return; - } - if(u->GetMen() != 1) { - u->Error("STUDY: Only 1-man units can be quartermasters.", o->quiet); - return; - } - } - - // If TACTICS_NEEDS_WAR is enabled, and the unit is trying to study to tact-5, - // check that there's still space... - if (Globals->TACTICS_NEEDS_WAR && sk == S_TACTICS && - u->GetRealSkill(sk) == 4 && u->skills.GetDays(sk)/u->GetMen() >= 390) { - - if (CountTacticians(u->faction) >= - AllowedTacticians(u->faction)) { - u->Error("STUDY: Can't have another level 5 tactics leader.", o->quiet); - return; - } - - if (u->GetMen() != 1) { - u->Error("STUDY: Only 1-man units can study to level 5 in tactics.", o->quiet); - return; - } - - } // end tactics check - - int days = 30 * u->GetMen(); - int taughtdays = o->days; - - if((SkillDefs[sk].flags & SkillType::MAGIC) && u->GetRealSkill(sk) >= 2 && !Globals->ARCADIA_MAGIC) { - if(Globals->LIMITED_MAGES_PER_BUILDING) { - if (obj->incomplete > 0 || obj->type == O_DUMMY) { - u->Error("Warning: Magic study rate outside of a building " - "cut in half above level 2.", o->quiet); - days /= 2; - taughtdays /= 2; - } else if(obj->mages == 0) { - u->Error("Warning: Magic rate cut in half above level 2 due " - "to number of mages studying in structure.", o->quiet); - days /= 2; - taughtdays /= 2; - } else { - obj->mages--; - } - } else if(!(ObjectDefs[obj->type].protect) || (obj->incomplete > 0)) { - u->Error("Warning: Magic study rate outside of a building cut in " - "half above level 2.", o->quiet); - days /= 2; - taughtdays /= 2; - } - } - - if(SkillDefs[sk].flags & SkillType::SLOWSTUDY) { - days /= 2; - taughtdays /= 2; - } - - - if (u->Study(sk,days,o->quiet)) { - if(taughtdays) u->Study(sk,taughtdays,0,0); //the second 0 means any taught knowledge does not overflow to experience - u->ConsumeSharedMoney(cost); //We checked earlier that we can get this - AString str("Studies "); - str += SkillDefs[sk].name; - int teachdays = o->days/u->GetMen(); - if (teachdays) { - str += " and was taught for "; - str += teachdays; - str += " days"; - } - str += "."; - u->Event(str); - } else return; //return if could not study. - - if(o->level && u->GetRealSkill(sk) < o->level) { //STUDY order mod - TurnOrder *tOrder = new TurnOrder; - AString order; - tOrder->repeating = 0; - order = AString("STUDY ") + SkillDefs[sk].abbr + " " + o->level; - tOrder->turnOrders.Add(new AString(order)); - u->turnorders.Insert(tOrder); - } -} - -void Game::ClearCombatMovementMaluses() -{ - forlist((®ions)) { - ARegion * region = (ARegion *) elem; - forlist((®ion->objects)) { - Object * obj = (Object *) elem; - forlist(&obj->units) { - Unit * unit = (Unit *) elem; - unit->movementmalus = 0; - } - } - } -} - -void Game::RunMoveOrders() -{ -// This follow code is very messy. I don't recommend using it unless, like me, -// you are pushed for time. A better method would be to link all followers to -// the unit they are following, and get them to move immediately after -// the target moves (or is a unit on a ship that sails). - - - for (int phase = 0; phase < Globals->MAX_SPEED; phase++) { - - ClearCombatMovementMaluses(); - - forlist((®ions)) { - ARegion * region = (ARegion *) elem; - forlist((®ion->objects)) { - Object * obj = (Object *) elem; - forlist(&obj->units) { - Unit * unit = (Unit *) elem; - unit->marker = 0; //used in setupfollowers. - Object *tempobj = obj; - if(phase == unit->movepoints) DoMoveEnter(unit,region,&tempobj); //the phase check is added on for sail during move, to avoid gaining movepoints by boarding a ship - } - } - } - SetupFollowers(phase); //this assigns a unit for 'followers' to follow, and ensures that no loops of followers creep in. - AList * locations = new AList; - AList * shipping = new AList; - forlist_reuse((®ions)) { - ARegion * region = (ARegion *) elem; - forlist((®ion->objects)) { - Object * obj = (Object *) elem; - forlist(&obj->units) { - Unit * unit = (Unit *) elem; - if (phase == unit->movepoints && unit->monthorders && - (unit->monthorders->type == O_MOVE || - unit->monthorders->type == O_ADVANCE) && - !unit->nomove) { - locations->Add(DoAMoveOrder(unit,region,obj)); - } - } - } - SailShips(region, phase, shipping); - //now, have to move all followers! - int numfollowers; - do { - numfollowers = 0; - forlist((®ion->objects)) { - Object * obj = (Object *) elem; - forlist(&obj->units) { - Unit * unit = (Unit *) elem; - if(phase >= unit->movepoints && unit->monthorders && - unit->monthorders->type == O_FOLLOW && - ((FollowOrder *)unit->monthorders)->target && - !unit->nomove ) { - //this unit has follow orders. - FollowOrder *o = (FollowOrder *) unit->monthorders; - if(o->target->monthorders && o->target->monthorders->type == O_FOLLOW && - ((FollowOrder *)o->target->monthorders)->target) numfollowers++; //this unit's target has yet to try and follow it's own target, so don't process this unit's follow order yet. - else if(o->target->object->region == unit->object->region) { - //The target unit has not moved, so clear our follow order. - o->target = 0; - } else { - //This unit's target has moved, so we want to follow it with a MOVE or SAIL order. - int initialpoints = unit->movepoints; - unit->movepoints = phase; //cannot proceed 'before' the unit it is following. This may lead to - //situations where a following unit cannot join battles even though it does not move. - if(obj->IsBoat() && obj->GetOwner() == unit) { - //sail order - if(obj->incomplete < 1) { - ARegionPtr * p = new ARegionPtr; - p->ptr = DoASailOrder(region,obj,unit); - shipping->Add(p); - o->target = 0; //since we have moved. - } else { - unit->Error("SAIL: Ship is not finished.", o->quiet); - delete o; - unit->monthorders = 0; - o = 0; - } - } else { - //move order - locations->Add(DoAMoveOrder(unit,region,obj)); - o->target = 0; - } - if(unit->movepoints == phase) unit->movepoints = initialpoints; - } - } else if(unit->monthorders && unit->monthorders->type == O_FOLLOW) { - if(unit->nomove) { - FollowOrder *o = (FollowOrder *) unit->monthorders; - delete o; - unit->monthorders = 0; - } else { - FollowOrder *o = (FollowOrder *) unit->monthorders; - o->target = 0; - } - } - } - } - } while (numfollowers); - } - - DoAdvanceAttacks(locations); - locations->DeleteAll(); - - forlist_reuse(shipping) { - ARegion * r2 = ((ARegionPtr *) elem)->ptr; - DoAutoAttacksRegion(r2); - } - shipping->DeleteAll(); - } - - forlist((®ions)) { - ARegion * region = (ARegion *) elem; - forlist((®ion->objects)) { - Object * obj = (Object *) elem; - forlist(&obj->units) { - Unit * unit = (Unit *) elem; - if(unit->monthorders && unit->monthorders->type == O_FOLLOW) { - FollowOrder *o = (FollowOrder *) unit->monthorders; - delete o; - unit->monthorders = 0; - } - } - } - } -} - -void Game::SetupFollowers(int phase) -{ - forlist(®ions) { - ARegion *region = (ARegion *) elem; - forlist(®ion->objects) { - Object * obj = (Object *) elem; - forlist(&obj->units) { - Unit *unit = (Unit *) elem; - if(unit->monthorders && unit->monthorders->type == O_FOLLOW) { - if(phase >= unit->movepoints && !unit->nomove) { - - FollowOrder *o = (FollowOrder *) unit->monthorders; - o->advancing = 0; - Unit *tar = 0; - if(o->ship) { - Object *pship = region->GetObject(o->ship); - if(pship) { - forlist(&pship->units) { - Unit *u = (Unit *) elem; - //skip all units which don't have men, or have orders to move - if(!u->GetMen()) continue; - if(u->monthorders && (u->monthorders->type == O_MOVE || u->monthorders->type == O_ADVANCE)) continue; - //this unit is our only possible captain to sail without battles - since he's not moving out. - if(u->monthorders && (u->monthorders->type == O_SAIL || u->monthorders->type == O_FOLLOW)) { - tar = u; - } - break; - } - } - } else { - tar = region->GetUnitId(o->targetid, unit->faction->num); - if(tar && !o->targetid->unitnum) o->targetid->unitnum = tar->num; //updates "NEW" targets so we can follow them beyond one hex. - if(!tar && o->targetid && o->targetid->unitnum) { - int done; - do { - done = 0; - forlist(®ion->hell) { - Unit *deadu = (Unit *) elem; - if(!done && deadu->num == o->targetid->unitnum) { - if(deadu->gavemento.First()) { - o->targetid->unitnum = ((UnitId *) deadu->gavemento.First())->unitnum; - done = 1; - } - } - } - if(done) tar = region->GetUnitId(o->targetid, unit->faction->num); - } while(done && !tar); - } - } -/* if(tar && ObjectIsShip(tar->object->type) && tar->object != unit->object && (!tar->monthorders || (tar->monthorders->type != O_MOVE && tar->monthorders->type != O_ADVANCE && tar->monthorders->type != O_SAIL && tar->monthorders->type != O_FOLLOW))) { - //this target unit is not moving, but the ship he is on may be. - forlist(&tar->object->units) { - Unit *u = (Unit *) elem; - //skip all units which don't have men, or have orders to move - if(!u->GetMen()) continue; - if(u->monthorders && (u->monthorders->type == O_MOVE || u->monthorders->type == O_ADVANCE)) continue; - //this unit is our only possible captain to sail without battles - since he's not moving out. - if(u->monthorders && u->monthorders->type == O_SAIL) { - tar = u; - } - break; - } - }*/ - - if(tar && tar->monthorders && !tar->nomove) { - o->target = tar; //set the unit to follow the unit specified. - Unit * finaltar = tar; - while(finaltar && finaltar->monthorders && finaltar->monthorders->type == O_FOLLOW && !finaltar->nomove) { - if( ((FollowOrder *)finaltar->monthorders)->ship ) { - Object *pship = region->GetObject(((FollowOrder *)finaltar->monthorders)->ship); - finaltar = 0; - if(pship) { - forlist(&pship->units) { - Unit *u = (Unit *) elem; - if(!u->GetMen()) continue; - if(u->monthorders && (u->monthorders->type == O_MOVE || u->monthorders->type == O_ADVANCE)) continue; - if(u->monthorders && (u->monthorders->type == O_SAIL || u->monthorders->type == O_FOLLOW)) finaltar = u; - break; - } - } - } else finaltar = region->GetUnitId(((FollowOrder *)finaltar->monthorders)->targetid, finaltar->faction->num); - if(finaltar == unit) finaltar = 0; //if get a loop of follow orders, then no-one moves. - if(finaltar) { - if(finaltar->marker == unit->num) finaltar = 0; - else finaltar->marker = unit->num; //mark each unit, if we get back to it we have looped. - } - } - //if we are not a ship captain, try to enter the object the ultimate target is in, but only if all intermediary targets can do so also. - //I am assuming here that there is no drowning issue with moving out of a ship over water. If there is, someone else can code it! - //Ship captains try to follow their target by sailing not moving. - int iscaptain = 0; - if(unit->object->IsBoat() && unit->object->GetOwner() == unit) iscaptain = 1; - int shouldadvance = 1; - if(!iscaptain && finaltar) { - int shouldfollow = 1; - Object *to = finaltar->object; - Unit *oldtar; - tar = unit; - while(tar != finaltar && (shouldfollow || shouldadvance)) { - if(tar->object != finaltar->object && - (!to->CanEnter(region,tar) || to->ForbiddenBy(region, tar)) ) - shouldfollow = 0; //we don't start battles to enter objects when following. - oldtar = tar; - if( ((FollowOrder *)finaltar->monthorders)->ship ) { - tar = finaltar; //if there's a ship involved, no follow, no advance. - shouldfollow = 0; - shouldadvance = 0; - } else tar = region->GetUnitId(((FollowOrder *)tar->monthorders)->targetid, tar->faction->num); - if (oldtar->faction->GetAttitude(tar->faction->num) < A_ALLY) shouldadvance = 0; - } - if(finaltar->object != unit->object && shouldfollow) { - unit->MoveUnit(to); - unit->Event(AString("Enters ") + *(to->name) + "."); - } - if(finaltar->object != unit->object && ObjectIsShip(unit->object->type)) { - //follower might get sailed away! - unit->MoveUnit(region->GetDummy()); - } - if(finaltar->monthorders && finaltar->monthorders->type == O_ADVANCE && shouldadvance) o->advancing = 1; //ie if all units in between are advancing and allied - } - tar = finaltar; //tar is now the 'ultimate' target. - - //we now have the 'ultimate' target which this unit, and maybe some others, are following. - if(tar && phase == tar->movepoints && !tar->nomove && tar->monthorders && (tar->monthorders->type == O_MOVE || tar->monthorders->type == O_ADVANCE || - tar->monthorders->type == O_SAIL)) { - //set the follow direction to the next direction this unit is moving. - MoveDir * x = 0; - if(tar->monthorders->type == O_SAIL && ((SailOrder *)tar->monthorders)->dirs.Num() ) { - x = (MoveDir *) ((SailOrder *)tar->monthorders)->dirs.First(); - o->advancing = 0; - } else if ( ((MoveOrder *)tar->monthorders)->dirs.Num()) { - x = (MoveDir *) ((MoveOrder *)tar->monthorders)->dirs.First(); - if(shouldadvance) o->advancing = ((MoveOrder *)tar->monthorders)->advancing; - else o->advancing = 0; //only advance after an ally. - } - if(x) { - if(x->dir == MOVE_IN && unit->object != tar->object) { - //they are moving IN, and are in a different object to us. Thus, we cannot follow them :(. - o->target = 0; - o->dir = -1; - } else o->dir = x->dir; //somehow have to deal with moveenters (& thus move IN) At the moment will not enter into objects after the target unit. - } else { - o->target = 0; //ultimate target is not moving. - o->dir = -1; - } - } else { - o->target = 0; //the target unit is not moving, so nor are we, so don't bother looking for it later. - o->dir = -1; - } - } else { - o->target = 0; //there is no target unit. - o->dir = -1; - } - } else { - FollowOrder *o = (FollowOrder *) unit->monthorders; - if(unit->nomove) { - delete o; - unit->monthorders = 0; - } else { - o->target = 0; - o->dir = -1; - } - } - } - } - } - } -} - -void Game::DoMoveEnter(Unit * unit,ARegion * region,Object **obj) -{ - MoveOrder * o; - if (!unit->monthorders || - ((unit->monthorders->type != O_MOVE) && - (unit->monthorders->type != O_ADVANCE))) - return; - o = (MoveOrder *) unit->monthorders; - - while (o->dirs.Num()) { - MoveDir * x = (MoveDir *) o->dirs.First(); - int i = x->dir; - if (i != MOVE_OUT && i < MOVE_ENTER) return; - o->dirs.Remove(x); - delete x; - - if (i >= MOVE_ENTER) { - Object * to = region->GetObject(i - MOVE_ENTER); - if (!to) { - unit->Error("MOVE: Can't find object.", o->quiet); - continue; - } - - if (!to->CanEnter(region,unit)) { - unit->Error("ENTER: Can't enter that.", o->quiet); - continue; - } - - Unit *forbid = to->ForbiddenBy(region, unit); - if (forbid && !o->advancing) { - unit->Error("ENTER: Is refused entry.", o->quiet); - continue; - } - - if(forbid && region->IsSafeRegion()) - { - unit->Error("ENTER: No battles allowed in safe regions.", o->quiet); - continue; - } - - if (forbid && !(unit->canattack && unit->IsReallyAlive())) { - unit->Error(AString("ENTER: Unable to attack ") + - *(forbid->name), o->quiet); - continue; - } - - int done = 0; - while (forbid) - { - int result = RunBattle(region, unit, forbid, 0, 0); -#ifdef DEBUG -cout << "Returned to DoMoveEnter" << endl; -#endif - if(result == BATTLE_IMPOSSIBLE) { - unit->Error(AString("ENTER: Unable to attack ")+ - *(forbid->name), o->quiet); - done = 1; - break; - } - if (!unit->canattack || !unit->IsReallyAlive()) { - done = 1; - break; - } - forbid = to->ForbiddenBy(region, unit); - } -#ifdef DEBUG -cout << "Resolved forbidding" << endl; -#endif - if (done) continue; - - unit->MoveUnit(to); - unit->Event(AString("Enters ") + *(to->name) + "."); - *obj = to; - } else { - if (i == MOVE_OUT) { - if(TerrainDefs[region->type].similar_type == R_OCEAN && - (!unit->CanSwim() || - unit->GetFlag(FLAG_NOCROSS_WATER))) - { - unit->Error("MOVE: Can't leave ship.", o->quiet); - continue; - } - - Object * to = region->GetDummy(); - unit->MoveUnit(to); - *obj = to; - } - } - } -} - -Location * Game::DoAMoveOrder(Unit * unit, ARegion * region, Object * obj) -{ - Location * loc = new Location; -// int movetype = unit->MoveType(); //dummy movetype until we know where we are going. - AString road; - - if (unit->guard == GUARD_GUARD) unit->guard = GUARD_NONE; - - int i; - int quiet; - if(unit->monthorders->type == O_MOVE || unit->monthorders->type == O_ADVANCE) { - MoveOrder * o = (MoveOrder *) unit->monthorders; - quiet = o->quiet; - if (o->advancing) unit->guard = GUARD_ADVANCE; - if (o->dirs.Num()) { - MoveDir * x = (MoveDir *) o->dirs.First(); - o->dirs.Remove(x); - i = x->dir; - delete x; - } else goto done_moving; - } else if(unit->monthorders->type == O_FOLLOW) { - FollowOrder * o = (FollowOrder *) unit->monthorders; - quiet = o->quiet; - if(o->advancing) unit->guard = GUARD_ADVANCE; - i = o->dir; - } else goto done_moving; //this should never occur. - - /* Ok, now we can move a region */ - if(region->dynamicexits) ResolveExits(region,unit); - - { - int startmove = 0; - /* Setup region to move to */ - ARegion * newreg; - int portalwgt = 0; - if (i == MOVE_IN) { - if (obj->inner == -1) { - unit->Error("MOVE: Can't move IN there.", quiet); - goto done_moving; - } else if(obj->type == O_ESEAPORTAL) { - portalwgt += unit->Weight(); // ARCADIA_MAGIC Patch (portals) - } - newreg = regions.GetRegion(obj->inner); - } else { - newreg = region->neighbors[i]; - } - - if (!newreg) { - unit->Error(AString("MOVE: Can't move that direction."), quiet); - goto done_moving; - } - - if(region->type == R_NEXUS && newreg->IsStartingCity()) - startmove = 1; - - if((TerrainDefs[region->type].similar_type == R_OCEAN) && - (!unit->CanSwim() || unit->GetFlag(FLAG_NOCROSS_WATER))) { - unit->Error(AString("MOVE: Can't move while in the ocean."), quiet); - goto done_moving; - } - - //BS edit to prevent merfolk beaching themselves (and any other swimming monster with no walk capacity) - if(unit->type == U_WMON && (TerrainDefs[region->type].similar_type == R_OCEAN) && - (TerrainDefs[newreg->type].similar_type != R_OCEAN) && !unit->CanWalk(unit->items.Weight())) { - unit->Error(AString("MOVE: Can't move out of ocean."), quiet); - goto done_moving; - } - - if(Globals->ARCADIA_MAGIC) { - if(unit->type == U_WMON && newreg->willsink > 0 && newreg->willsink < region->willsink && !unit->CanSwim() ) { - unit->Error("MOVE: Monsters don't move into sinking regions.", quiet); - goto done_moving; - } - } - - -// Arcadia portal stuff, deducting travel energy cost. If cost is more than mage can bear, collapse the portal. -// Otherwise, do nothing, and we'll subtrace the cost later. The cost here must be the same as the cost in -// unit::EnergyRecharge() or strange things will happen. - - Location *locmage = 0; - if(portalwgt) { - locmage = regions.FindUnit(obj->mageowner); //this creates a 'new' location, so should be deleted later. - - if(!locmage || (locmage->unit->GetEnergy(portalwgt) < 0) ) { - //cannot pass through - unit->Error(AString("MOVE: The portal collapses as unit enters."), quiet); - if(locmage) { - locmage->unit->Error(AString("Not enough energy to hold a portal open, which promptly collapses"), quiet); - } - if(locmage) delete locmage; - locmage = 0; - Object *dest = region->GetDummy(); - forlist(&obj->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(dest); - } - //inner object, so destroy link at other end. - ARegion *newreg = regions.GetRegion(obj->inner); - forlist_reuse(&newreg->objects) { - Object *ob = (Object *) elem; - if(ob->type == O_ESEAPORTAL && ob->mageowner == obj->mageowner && ob->inner == region->num) { - Object *dest2 = newreg->GetDummy(); - forlist(&obj->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(dest2); - } - newreg->objects.Remove(ob); - delete ob; - } - } - region->objects.Remove(obj); - delete obj; - obj = dest; //for when we access it later, this is where our unit now is. - goto done_moving; - } - //otherwise, this portal can be used. - } - - int movetype = unit->MoveType(newreg); - - road = ""; - int cost = newreg->MoveCost(movetype, region, i, &road); - if (region->type != R_NEXUS && - unit->CalcMovePoints(newreg) - unit->movepoints < cost) { - //we don't have enough movement points to move! - if(unit->MoveType(newreg) == M_NONE) { - unit->Error("MOVE: Unit is overloaded and cannot move.", quiet); - } else if(unit->monthorders->type == O_FOLLOW) { - unit->Error("MOVE: Unit has insufficient movement points to continue following.", quiet); - } else { - unit->Error("MOVE: Unit has insufficient movement points;" - " remaining moves queued.", quiet); - MoveOrder * o = (MoveOrder *) unit->monthorders; - TurnOrder *tOrder = new TurnOrder; - AString order; - tOrder->repeating = 0; - if (o->advancing) order = "ADVANCE "; - else order = "MOVE "; - if (i < NDIRS) order += DirectionAbrs[i]; - else if (i == MOVE_IN) order += "IN"; - else if (i == MOVE_OUT) order += "OUT"; - else order += i - MOVE_ENTER; - forlist(&o->dirs) { - MoveDir *move = (MoveDir *) elem; - order += " "; - if (move->dir < NDIRS) order += DirectionAbrs[move->dir]; - else if (move->dir == MOVE_IN) order += "IN"; - else if (move->dir == MOVE_OUT) order += "OUT"; - else order += move->dir - MOVE_ENTER; - } - tOrder->turnOrders.Add(new AString(order)); - unit->turnorders.Insert(tOrder); - } - goto done_moving; - } - if(cost < 0) { - unit->Event(AString("MOVE: Unit is prevented from moving to ") + newreg->ShortPrint(®ions) + " by intervening terrain."); - goto done_moving; - } - - if((TerrainDefs[newreg->type].similar_type == R_OCEAN) && - (!unit->CanSwim() || unit->GetFlag(FLAG_NOCROSS_WATER))) { - unit->Event(AString("Discovers that ") + - newreg->ShortPrint(®ions) + " is " + - TerrainDefs[newreg->type].name + "."); - goto done_moving; - } - - if (unit->type == U_WMON && newreg->town && newreg->IsGuarded()) { - //monsters don't move into towns ... unless it is Arcadia and they are dragons! - if(!Globals->ARCADIA_MAGIC || unit->items.GetNum(I_DRAGON) == 0) { - unit->Event("Monsters don't move into guarded towns."); - goto done_moving; - } - } - if (unit->guard == GUARD_ADVANCE) { - Unit *ally = newreg->ForbiddenByAlly(unit); - if (ally && !startmove) { - unit->Event(AString("Can't ADVANCE: ") + *(newreg->name) + - " is guarded by " + *(ally->name) + ", an ally."); - goto done_moving; - } - } - - Unit * forbid = newreg->Forbidden(unit); - if (forbid && !startmove && unit->guard != GUARD_ADVANCE) { - int obs = unit->GetAttribute("observation"); - unit->Event(AString("Is forbidden entry to ") + - newreg->ShortPrint(®ions) + " by " + - forbid->GetName(obs) + "."); - obs = forbid->GetAttribute("observation"); - forbid->Event(AString("Forbids entry to ") + - unit->GetName(obs) + "."); - goto done_moving; - } - - /* Clear the unit's alias out, so as not to interfere with TEACH */ - unit->alias = 0; - - unit->movepoints += cost; - unit->MoveUnit(newreg->GetDummy()); - if(movetype != M_FLY) unit->CrossHexside(region, newreg); - - AString temp; - switch (movetype) { - case M_WALK: - temp = AString("Walks ") + road; - if(TerrainDefs[newreg->type].similar_type == R_OCEAN) - temp = "Swims "; - break; - case M_RIDE: - temp = AString("Rides ") + road; - unit->Experience(S_RIDING,cost); - if(unit->GetSkill(S_SWIFTNESS)) unit->Experience(S_SWIFTNESS,cost); - break; - case M_FLY: - temp = "Flies "; - unit->Experience(S_RIDING,cost); - if(unit->GetSkill(S_SWIFTNESS)) unit->Experience(S_SWIFTNESS,cost); - break; - } - unit->Event(temp + AString("from ") + region->ShortPrint(®ions) - + AString(" to ") + newreg->ShortPrint(®ions) + - AString(".")); - if (forbid) { - unit->advancefrom = region; - } - - //Arcadia portal stuff - #ifdef DEBUG - if(portalwgt && !locmage || portalwgt < 0) { - Awrite("portal error; locmage is zero after movement or portalwgt is negative"); - system("pause"); - } - #endif - - if(locmage) { - locmage->unit->transferred += portalwgt; - delete locmage; - } - - if(Globals->TRANSIT_REPORT != GameDefs::REPORT_NOTHING) { - // Update our visit record in the region we are leaving. - Farsight *f; - forlist(®ion->passers) { - f = (Farsight *)elem; - if(f->unit == unit) { - // We moved into here this turn - if(i < MOVE_IN) { - f->exits_used[i] = 1; - } - } - } - // And mark the hex being entered - f = new Farsight; - f->faction = unit->faction; - f->level = 0; - f->unit = unit; - if(i < MOVE_IN) { - f->exits_used[region->GetRealDirComp(i)] = 1; - } - newreg->passers.Add(f); - } - region = newreg; //region updated here - } - loc->unit = unit; - loc->region = region; - loc->obj = region->GetDummy(); //This is an Arcadia change, to allow checking of the object during attacks. Before the object was the starting object, not the finishing one. - return loc; - -done_moving: - if(unit->monthorders->type == O_MOVE || unit->monthorders->type == O_ADVANCE) { - MoveOrder *o = (MoveOrder *) unit->monthorders; - delete o; - unit->monthorders = 0; - } - loc->unit = unit; - loc->region = region; - loc->obj = obj; - return loc; -} - -void Game::RunMasterOrders() -{ - //Need to recode with new system. See Nylandor code for details -} diff --git a/arcadia/npc.cpp b/arcadia/npc.cpp deleted file mode 100644 index a4bbbafab..000000000 --- a/arcadia/npc.cpp +++ /dev/null @@ -1,479 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "game.h" -#include "gamedata.h" - -void Game::CreateCityMons() -{ - if(!Globals->CITY_MONSTERS_EXIST) return; - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if (r->type == R_NEXUS || r->IsStartingCity() || r->town) { - CreateCityMon(r, 100, 7); - } - } -} - -void Game::CreateWMons() -{ - if(!Globals->WANDERING_MONSTERS_EXIST) return; - - GrowWMons(50); -} - -void Game::CreateLMons() -{ - if(!Globals->LAIR_MONSTERS_EXIST) return; - - GrowLMons(50); -} - -void Game::GrowWMons(int rate) -{ - // - // Now, go through each 8x8 block of the map, and make monsters if - // needed. - // - int level; - for(level = 0; level < regions.numLevels; level++) { - ARegionArray *pArr = regions.pRegionArrays[level]; - int xsec; - for (xsec=0; xsec< pArr->x / 8; xsec++) { - for (int ysec=0; ysec< pArr->y / 16; ysec++) { - /* OK, we have a sector. Count mons, and wanted */ - int mons=0; - int wanted=0; - for (int x=0; x<8; x++) { - for (int y=0; y<16; y+=2) { - ARegion *reg = pArr->GetRegion(x+xsec*8, y+ysec*16+x%2); - if (reg && !reg->IsGuarded()) { - mons += reg->CountWMons(); - /* - * Make sure there is at least one monster type - * enabled for this region - */ - int avail = 0; - int mon = TerrainDefs[reg->type].smallmon; - if(!((mon == -1) || - (ItemDefs[mon].flags & ItemType::DISABLED))) - avail = 1; - mon = TerrainDefs[reg->type].bigmon; - if(!((mon == -1) || - (ItemDefs[mon].flags & ItemType::DISABLED))) - avail = 1; - mon = TerrainDefs[reg->type].humanoid; - if(!((mon == -1) || - (ItemDefs[mon].flags & ItemType::DISABLED))) - avail = 1; - - if(avail) - wanted += TerrainDefs[reg->type].wmonfreq; - } - } - } - - wanted /= 10; - wanted -= mons; - wanted = (wanted*rate + getrandom(100))/100; - if (wanted > 0) { - for (int i=0; i< wanted;) { - int m=getrandom(8); - int n=getrandom(8)*2+m%2; - ARegion *reg = pArr->GetRegion(m+xsec*8, n+ysec*16); - if (reg && !reg->IsGuarded() && MakeWMon(reg)) { - i++; - } - } - } - } - } - } -} - -void Game::GrowLMons(int rate) -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - // - // Don't make lmons in guarded regions - // - if (r->IsGuarded()) continue; - - forlist(&r->objects) { - Object *obj = (Object *) elem; - if (obj->units.Num()) continue; - int montype = ObjectDefs[obj->type].monster; - int grow=!(ObjectDefs[obj->type].flags&ObjectType::NOMONSTERGROWTH); - if ((montype != -1) && grow) { - if (getrandom(100) < rate) { - MakeLMon(obj); - } - } - } - } -} - -int Game::MakeWMon(ARegion *pReg) -{ - if(!Globals->WANDERING_MONSTERS_EXIST) return 0; - - if (TerrainDefs[pReg->type].wmonfreq == 0) return 0; - - if (getrandom(3) && TerrainDefs[pReg->type].similar_type != R_OCEAN) return 0; //land regions have only 1/3 the monsters of ocean. Arcadia only mod. - - int montype = TerrainDefs[pReg->type].smallmon; //44% chance smallmon, 44% chance humanoid, 12% chance bigmon - if (getrandom(2) && (TerrainDefs[pReg->type].humanoid != -1)) - montype = TerrainDefs[pReg->type].humanoid; - int yeareffect = year - 1; //BS mod - big monsters come more later on. - if(yeareffect > 6) yeareffect = 6; - if (yeareffect && TerrainDefs[pReg->type].bigmon != -1 && !getrandom(8-yeareffect)) { //no biggies at all in year 1. - montype = TerrainDefs[pReg->type].bigmon; - } - if((montype == -1) || (ItemDefs[montype].flags & ItemType::DISABLED)) - return 0; - - MonType *mp = FindMonster(ItemDefs[montype].abr, - (ItemDefs[montype].type & IT_ILLUSION)); - Faction *monfac = GetFaction(&factions, monfaction); - Unit *u = GetNewUnit(monfac, 0); - u->MakeWMon(mp->name, montype, (mp->number+getrandom(mp->number)+1)/2); //from 50% to 100% of stored number - u->MoveUnit(pReg->GetDummy()); - return(1); -} - -void Game::MakeLMon(Object *pObj) -{ - if(!Globals->LAIR_MONSTERS_EXIST) return; - if(ObjectDefs[pObj->type].flags & ObjectType::NOMONSTERGROWTH) return; - - int montype = ObjectDefs[pObj->type].monster; - //BS mod - don't always get same monster type. - if (montype == I_TRENT || montype == I_CENTAUR) { - montype = TerrainDefs[pObj->region->type].humanoid; //33% humanoid - if(!getrandom(3) && TerrainDefs[pObj->region->type].smallmon != -1) montype = TerrainDefs[pObj->region->type].smallmon; //17% smallmon - if(!getrandom(2) && TerrainDefs[pObj->region->type].bigmon != -1) montype = TerrainDefs[pObj->region->type].bigmon; //50% bigmon -// if(!getrandom(10)) montype = I_IWOLF; //10% illusions - } - - if((montype == -1) || (ItemDefs[montype].flags & ItemType::DISABLED)) - return; - - MonType *mp = FindMonster(ItemDefs[montype].abr, - (ItemDefs[montype].type & IT_ILLUSION)); - Faction *monfac = GetFaction(&factions, monfaction); - Unit *u = GetNewUnit(monfac, 0); - switch(montype) { - case I_IMP: - u->MakeWMon("Demons", I_IMP, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_DEMON].abr, - (ItemDefs[I_DEMON].type & IT_ILLUSION)); - u->items.SetNum(I_DEMON, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_BALROG].abr, - (ItemDefs[I_BALROG].type & IT_ILLUSION)); - u->items.SetNum(I_BALROG, getrandom(mp->number + 1)); - break; - case I_SKELETON: - u->MakeWMon("Undead", I_SKELETON, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_UNDEAD].abr, - (ItemDefs[I_UNDEAD].type & IT_ILLUSION)); - u->items.SetNum(I_UNDEAD, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_LICH].abr, - (ItemDefs[I_LICH].type & IT_ILLUSION)); - u->items.SetNum(I_LICH, getrandom(mp->number + 1)); - break; - case I_IWOLF: //BS mod - u->MakeWMon("Hunters", I_IWOLF, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_IEAGLE].abr, - (ItemDefs[I_IEAGLE].type & IT_ILLUSION)); - u->items.SetNum(I_IEAGLE, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_IGRYFFIN].abr, - (ItemDefs[I_IGRYFFIN].type & IT_ILLUSION)); - u->items.SetNum(I_IGRYFFIN, getrandom(mp->number + 1)); - break; - case I_MAGICIANS: - u->MakeWMon("Evil Mages", I_MAGICIANS, - (mp->number + getrandom(mp->number) + 1) / 2); - - mp = FindMonster(ItemDefs[I_SORCERERS].abr, - (ItemDefs[I_SORCERERS].type & IT_ILLUSION)); - u->items.SetNum(I_SORCERERS, - getrandom(mp->number + 1)); - u->SetFlag(FLAG_BEHIND, 1); - u->MoveUnit(pObj); - - u = GetNewUnit(monfac, 0); - - mp = FindMonster(ItemDefs[I_WARRIORS].abr, - (ItemDefs[I_WARRIORS].type & IT_ILLUSION)); - u->MakeWMon(mp->name, I_WARRIORS, - (mp->number + getrandom(mp->number) + 1) / 2); - - break; - case I_DARKMAGE: - u->MakeWMon("Dark Mages", I_DARKMAGE, (getrandom(mp->number) + 1)); - - mp = FindMonster(ItemDefs[I_MAGICIANS].abr, - (ItemDefs[I_MAGICIANS].type & IT_ILLUSION)); - u->items.SetNum(I_MAGICIANS, - (mp->number + getrandom(mp->number) + 1) / 2); - - mp = FindMonster(ItemDefs[I_SORCERERS].abr, - (ItemDefs[I_SORCERERS].type & IT_ILLUSION)); - u->items.SetNum(I_SORCERERS, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_DARKMAGE].abr, - (ItemDefs[I_DARKMAGE].type & IT_ILLUSION)); - u->items.SetNum(I_DARKMAGE, getrandom(mp->number + 1)); - u->SetFlag(FLAG_BEHIND, 1); - u->MoveUnit(pObj); - - u = GetNewUnit(monfac, 0); - - mp = FindMonster(ItemDefs[I_DROW].abr, - (ItemDefs[I_DROW].type & IT_ILLUSION)); - u->MakeWMon(mp->name, I_DROW, - (mp->number + getrandom(mp->number) + 1) / 2); - - break; - case I_ILLYRTHID: - u->MakeWMon(mp->name, I_ILLYRTHID, - (mp->number + getrandom(mp->number) + 1) / 2); - u->SetFlag(FLAG_BEHIND, 1); - u->MoveUnit(pObj); - - u = GetNewUnit(monfac, 0); - - mp = FindMonster(ItemDefs[I_SKELETON].abr, - (ItemDefs[I_SKELETON].type & IT_ILLUSION)); - u->MakeWMon("Undead", I_SKELETON, getrandom(mp->number + 1)); - - mp = FindMonster(ItemDefs[I_UNDEAD].abr, - (ItemDefs[I_UNDEAD].type & IT_ILLUSION)); - u->items.SetNum(I_UNDEAD, getrandom(mp->number + 1)); - break; - case I_STORMGIANT: - if (getrandom(3) < 1) { - montype = I_CLOUDGIANT; - mp = FindMonster(ItemDefs[montype].abr, - (ItemDefs[montype].type & IT_ILLUSION)); - } - u->MakeWMon(mp->name, montype, - (mp->number + getrandom(mp->number) + 1) / 2); - break; - default: - u->MakeWMon(mp->name, montype, - (mp->number + getrandom(mp->number) + 1) / 2); - break; - } - u->MoveUnit(pObj); -} - -Unit *Game::MakeManUnit(Faction *fac, ARegion *pReg, int num, int level, int weaponlevel, int armor, int behind) -{ - Unit *u = GetNewUnit(fac); - ManType *men = FindRace(ItemDefs[pReg->race].abr); - if(!men) men = FindRace("HELF"); - -/* BS: - This method was going into infernal loops with races that allowed weaponlevel to start as 3. Rather than try to fix - it, I've just deleted the original and written my own. -*/ - if(!behind) { - u->SetMen(pReg->race, num); - u->items.SetNum(I_SWORD, num); - if( (u->GetSkillKnowledgeMax(S_RIDING) > u->GetSkillKnowledgeMax(S_COMBAT)) && (TerrainDefs[pReg->type].flags & TerrainType::RIDINGMOUNTS) && !(TerrainDefs[pReg->type].flags & TerrainType::RIDINGLIMITED) ) { - u->SetSkill(S_RIDING, level); - u->items.SetNum(I_HORSE, num); - } else u->SetSkill(S_COMBAT, level); - // u->SetFlag(FLAG_BEHIND,1); - if(armor) { - u->items.SetNum(I_LEATHERARMOR, num); //only the frontrow gets armour - } - } else { - u->SetMen(pReg->race, num); - if(u->GetSkillKnowledgeMax(S_CROSSBOW) > u->GetSkillKnowledgeMax(S_LONGBOW)) { - u->items.SetNum(I_CROSSBOW, num); - u->SetSkill(S_CROSSBOW, level); - } else { - u->items.SetNum(I_LONGBOW, num); - u->SetSkill(S_LONGBOW, level); - } - u->SetFlag(FLAG_BEHIND,1); - } - u->AdjustSkills(1); - return u; -/* - // Check skills: - int scomb = men->defaultlevel; - int sxbow = men->defaultlevel; - int slbow = men->defaultlevel; - for (unsigned int i=0; - i<(sizeof(men->skills)/sizeof(men->skills[0])); - i++) { - if(men->skills[i] == NULL) continue; - if(FindSkill(men->skills[i]) == FindSkill("COMB")) - scomb = men->speciallevel; - if(FindSkill(men->skills[i]) == FindSkill("XBOW")) - sxbow = men->speciallevel; - if(FindSkill(men->skills[i]) == FindSkill("LBOW")) - slbow = men->speciallevel; - } - int combat = scomb; - AString *s = new AString("COMB"); - int sk = LookupSkill(s); - if(behind) { - if(slbow >= sxbow) { - *s = AString("LBOW"); - sk = LookupSkill(s); - combat = slbow; - } else { - *s = AString("XBOW"); - sk = LookupSkill(s); - combat = sxbow; - } - } - if(combat < level) weaponlevel += level - combat; - int weapon = -1; - int witem = -1; - while (weapon == -1) { - int fitting[NUMWEAPONS]; - int n = 0; - for(int i=0; iabbr) continue; - - AString *s1 = new AString(WeaponDefs[i].baseSkill); - AString *s2 = new AString(WeaponDefs[i].orSkill); - if((WeaponDefs[i].flags & WeaponType::RANGED) - && (!behind)) continue; - int attack = WeaponDefs[i].attackBonus; - if(attack < (producelevel-1)) attack = producelevel-1; - if((LookupSkill(s1) == sk) - || (LookupSkill(s2) == sk)) { - if((behind) && (attack + combat <= weaponlevel)) { - fitting[i] = 1; - if(WeaponDefs[i].attackBonus == weaponlevel) fitting[i] = 5; - n += fitting[i]; - } else if ((!behind) && (attack == weaponlevel)) { - fitting[i] = 1; - //if(WeaponDefs[i].attackBonus == weaponlevel) fitting[i] = 5; - n += fitting[i]; - } else continue; - } else { - // make Javelins possible - AString *cs = new AString("COMB"); - if((behind) && (scomb > combat)) { - if((WeaponDefs[i].flags & WeaponType::RANGED) - && ((LookupSkill(s1) == LookupSkill(cs)) - || (LookupSkill(s2) == LookupSkill(cs)))) { - fitting[i] = 1; - n++; - } - } - } - } - -// AString *tmp = new AString(" (behind)"); -// if(!behind) tmp = new AString(""); -// Awrite(AString("Found ") + n + " fitting weapons " + *tmp + "."); - - if(n < 1) { - weaponlevel++; - continue; - } else { - int secondtry = -1; - while(secondtry <= 0) { - weapon = -1; - int w = getrandom(n); - -// Awrite(AString("Roll: ") + w); - - n = -1; - for(int i=0; i= w) && (weapon == -1)) - weapon = i; - } - } - if(weapon >= 0) { - AString *ws = new AString(WeaponDefs[weapon].abbr); - witem = LookupItem(ws); - secondtry++; - if(men->CanUse(witem)) break; - } - } - } - } - // Check again which skills the weapon uses - AString *ws1 = new AString(WeaponDefs[weapon].baseSkill); - AString *ws2 = new AString(WeaponDefs[weapon].orSkill); - if((LookupSkill(ws1) != sk) && (LookupSkill(ws2) != sk)) - sk = LookupSkill(ws1); - int maxskill = men->defaultlevel; - int special = 0; - for(unsigned int i=0; - i<(sizeof(men->skills)/sizeof(men->skills[0])); - i++) { - if(FindSkill(men->skills[i]) == FindSkill(SkillDefs[sk].abbr)) { - special = 1; - } - } - if(special) maxskill = men->speciallevel; - if(level > maxskill) level = maxskill; - u->SetMen(mantype, num); - -// Awrite(AString("-> chose ") + ItemDefs[witem].name); - - u->items.SetNum(witem, num); - u->SetSkill(sk, level); - if(behind) u->SetFlag(FLAG_BEHIND,1); - if(armor) { - int ar = I_PLATEARMOR; - if(!men->CanUse(ar)) ar = I_CHAINARMOR; - if(!men->CanUse(ar)) ar = I_LEATHERARMOR; - u->items.SetNum(ar, num); - } - return u; -*/ -} diff --git a/arcadia/object.cpp b/arcadia/object.cpp deleted file mode 100644 index 314881dca..000000000 --- a/arcadia/object.cpp +++ /dev/null @@ -1,568 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "object.h" -#include "items.h" -#include "skills.h" -#include "gamedata.h" -#include "unit.h" - -int LookupObject(AString *token) -{ - for (int i = 0; i < NOBJECTS; i++) { - if (*token == ObjectDefs[i].name) return i; - } - return -1; -} - -int ParseObject(AString *token) -{ - int r = -1; - for (int i=O_DUMMY+1; iPutInt(num); - if (type != -1) f->PutStr(ObjectDefs[type].name); - else f->PutStr("NO_OBJECT"); - f->PutInt(incomplete); - f->PutStr(*name); - if (describe) { - f->PutStr(*describe); - } else { - f->PutStr("none"); - } - f->PutInt(inner); - if(type == O_ESEAPORTAL) f->PutInt(mageowner); - f->PutInt(hexside); /* Hexside Patch 030825 BS */ - if (Globals->PREVENT_SAIL_THROUGH && !Globals->ALLOW_TRIVIAL_PORTAGE) - f->PutInt(prevdir); - else - f->PutInt(-1); - f->PutInt(runes); - f->PutInt(units.Num()); - forlist ((&units)) - ((Unit *) elem)->Writeout(f); -} - -void Object::Readin(Ainfile *f, AList *facs, ATL_VER v) -{ - AString *temp; - - num = f->GetInt(); - - temp = f->GetStr(); - type = LookupObject(temp); - delete temp; - - incomplete = f->GetInt(); - - if (name) delete name; - name = f->GetStr(); - describe = f->GetStr(); - if (*describe == "none") { - delete describe; - describe = 0; - } - inner = f->GetInt(); - if(type == O_ESEAPORTAL) mageowner = f->GetInt(); - hexside = f->GetInt(); /* Hexside Patch 030825 BS */ - prevdir = f->GetInt(); - runes = f->GetInt(); - - // Now, fix up a save file if ALLOW_TRIVIAL_PORTAGE is allowed, just - // in case it wasn't when the save file was made. - if (Globals->ALLOW_TRIVIAL_PORTAGE) prevdir = -1; - int i = f->GetInt(); - for (int j=0; jReadin(f, facs, v); - temp->MoveUnit(this); - } - mages = ObjectDefs[type].maxMages; -} - -void Object::SetName(AString *s) -{ - if (s && (CanModify())) { - AString *newname = s->getlegal(); - if(!newname) { - delete s; - return; - } - delete s; - delete name; - *newname += AString(" [") + num + "]"; - name = newname; - } -} - -void Object::SetDescribe(AString *s) -{ - if (CanModify()) { - if (describe) delete describe; - if (s) { - AString *newname = s->getlegal(); - delete s; - describe = newname; - } else describe = 0; - } -} - -int Object::IsBoat() -{ - if (ObjectDefs[type].capacity) - return 1; - return 0; -} - -int Object::IsBuilding() -{ - if (ObjectDefs[type].protect) - return 1; - return 0; -} - -int Object::CanModify() -{ - return (ObjectDefs[type].flags & ObjectType::CANMODIFY); -} - -Unit *Object::GetUnit(int num) -{ - forlist((&units)) - if (((Unit *) elem)->num == num) - return ((Unit *) elem); - return 0; -} - -Unit *Object::GetUnitAlias(int alias, int faction) -{ - // First search for units with the 'formfaction' - forlist((&units)) { - if(((Unit *)elem)->alias == alias && - ((Unit *)elem)->formfaction->num == faction) - return ((Unit *)elem); - } - // Now search against their current faction - { - forlist((&units)) { - if (((Unit *) elem)->alias == alias && - ((Unit *) elem)->faction->num == faction) - return ((Unit *) elem); - } - } - return 0; -} - -Unit *Object::GetUnitId(UnitId *id, int faction) -{ - if (id == 0) return 0; - if (id->unitnum) { - return GetUnit(id->unitnum); - } else { - if (id->faction) { - return GetUnitAlias(id->alias, id->faction); - } else { - return GetUnitAlias(id->alias, faction); - } - } -} - -int Object::CanEnter(ARegion *reg, Unit *u) -{ - if(!(ObjectDefs[type].flags & ObjectType::CANENTER) && - (u->type == U_MAGE || u->type == U_NORMAL || - u->type == U_APPRENTICE) ) { - } - return 1; -} - -int Object::GetPopulation() -{ - int i=0; - forlist((&units)) i=i+1; - return i; -} - -Unit *Object::ForbiddenBy(ARegion *reg, Unit *u) -{ - Unit *owner = GetOwner(); - if(!owner) { - return(0); - } - - if(owner->GetAttitude(reg, u) < A_FRIENDLY) { - return owner; - } - return 0; -} - -Unit *Object::GetOwner() -{ - Unit *owner = (Unit *) units.First(); - while(owner && !owner->GetMen()) { - owner = (Unit *) units.Next(owner); - } - return(owner); -} - -void Object::Report(Areport *f, Faction *fac, int obs, int truesight, int fog, - int detfac, int passobs, int passtrue, int passdetfac, int present) -{ - ObjectType *ob = &ObjectDefs[type]; - - if((type != O_DUMMY) && !present) { - if(IsBuilding() && - !(Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_BUILDINGS)) { - // This is a building and we don't see buildings in transit - return; - } - if(IsBoat() && - !(Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_SHIPS)) { - // This is a ship and we don't see ships in transit - return; - } - if(IsRoad() && - !(Globals->TRANSIT_REPORT & GameDefs::REPORT_SHOW_ROADS)) { - // This is a road and we don't see roads in transit - return; - } - } - - if (type != O_DUMMY) { - AString temp = AString("+ ") + *name + " : " + ob->name; - /* Hexside Patch 030825 BS */ - if(ob->hexside || IsBoat() ) { - if(hexside == -1) temp += " (hex centre)"; - if(hexside==0) temp += " (Northern hexside)"; - if(hexside==1) temp += " (North Eastern hexside)"; - if(hexside==2) temp += " (South Eastern hexside)"; - if(hexside==3) temp += " (Southern hexside)"; - if(hexside==4) temp += " (South Western hexside)"; - if(hexside==5) temp += " (North Western hexside)"; - } - if (incomplete > 0) { - temp += AString(", needs ") + incomplete; - } else if(Globals->DECAY && - !(ob->flags & ObjectType::NEVERDECAY) && incomplete < 1) { - if(incomplete > (0 - ob->maxMonthlyDecay)) { - temp += ", about to decay"; - } else if(incomplete > (0 - ob->maxMaintenance/2)) { - temp += ", needs maintenance"; - } - } - if (inner != -1) { - temp += ", contains an inner location"; - } - if (runes) { - temp += ", engraved with Runes of Warding"; - if(Globals->ARCADIA_MAGIC) temp += AString(" of level ") + runes; - } - if (describe) { - temp += AString("; ") + *describe; - } - if (!(ob->flags & ObjectType::CANENTER)) { - temp += ", closed to player units"; - } - temp += "."; - f->PutStr(temp); - f->AddTab(); - } - forlist ((&units)) { - Unit *u = (Unit *) elem; - int attitude = fac->GetAttitude(u->faction->num); - if (u->faction == fac) { - u->WriteReport(f, -1, 1, 1, 1, attitude); - } else if(fog) { - //nothing! - } else { - if(present) { - u->WriteReport(f, obs, truesight, detfac, type != O_DUMMY, attitude); - } else { - if(((type == O_DUMMY) && - (Globals->TRANSIT_REPORT & - GameDefs::REPORT_SHOW_OUTDOOR_UNITS)) || - ((type != O_DUMMY) && - (Globals->TRANSIT_REPORT & - GameDefs::REPORT_SHOW_INDOOR_UNITS)) || - ((u->guard == GUARD_GUARD) && - (Globals->TRANSIT_REPORT & - GameDefs::REPORT_SHOW_GUARDS))) { - u->WriteReport(f, passobs, passtrue, passdetfac, - type != O_DUMMY, attitude); - } - } - } - } - f->EndLine(); - if (type != O_DUMMY) { - f->DropTab(); - } -} - -void Object::SetPrevDir(int newdir) -{ - prevdir = newdir; -} - -void Object::MoveObject(ARegion *toreg) -{ - region->objects.Remove(this); - region = toreg; - toreg->objects.Add(this); -} - -int Object::IsRoad() -{ - if (type >= O_ROADN && type <= O_ROADS) return 1; - return 0; -} - -int Object::Weight() -{ - int weight = 0; - forlist(&units) weight += ((Unit *) elem)->Weight(); - return weight; -} - -AString *ObjectDescription(int obj) -{ - if(ObjectDefs[obj].flags & ObjectType::DISABLED) - return NULL; - - ObjectType *o = &ObjectDefs[obj]; - AString *temp = new AString; - *temp += AString(o->name) + ": "; - if(o->capacity) { - *temp += "This is a ship."; - } else { - *temp += "This is a building."; - } - - if(Globals->LAIR_MONSTERS_EXIST && (o->monster != -1)) { - *temp += " Monsters can potentially lair in this structure."; - if(o->flags & ObjectType::NOMONSTERGROWTH) { - *temp += " Monsters in this structures will never regenerate."; - } - } - - if(o->flags & ObjectType::CANENTER) { - *temp += " Units may enter this structure."; - } - - if(o->protect) { - *temp += AString(" This structure provides defense to the first ") + - o->protect + " men inside it."; - // Now do the defences. First, figure out how many to do. - int totaldef = 0; - for (int i=0; idefenceArray[i] != 0); - } - // Now add the description to temp - *temp += AString(" This structure gives a defensive bonus of "); - for (int i=0; idefenceArray[i]) { - totaldef--; - *temp += AString(o->defenceArray[i]) + " against " + - AttType(i) + AString(" attacks"); - - if (totaldef >= 2) { - *temp += AString(", "); - } else { - if (totaldef == 1) { // penultimate bonus - *temp += AString(" and "); - } else { // last bonus - *temp += AString("."); - } - } // end if - } - } // end for - } - - if(o->oceanbonus) { - *temp += AString(" Units in this structure will recieve a bonus of ") + - o->oceanbonus + " to their attack and all defence skills for battles " - "which take place in an ocean or lake region."; - } - - /* - * Handle all the specials - */ - for(int i = 0; i < NUMSPECIALS; i++) { - SpecialType *spd = &SpecialDefs[i]; - AString effect = "are"; - int match = 0; - if(!(spd->targflags & SpecialType::HIT_BUILDINGIF) && - !(spd->targflags & SpecialType::HIT_BUILDINGEXCEPT)) { - continue; - } - for(int j = 0; j < 3; j++) - if(spd->buildings[j] == obj) match = 1; - if(!match) continue; - if(spd->targflags & SpecialType::HIT_BUILDINGEXCEPT) { - effect += " not"; - } - *temp += " Units in this structure "; - *temp += effect + " affected by " + spd->specialname + "."; - } - - if(o->sailors) { - *temp += AString(" This ship requires ") + o->sailors + - " total levels of sailing skill to sail."; - if(o->speed && Globals->HEXSIDE_TERRAIN) { - *temp += AString(" This ship gets ") + o->speed + - " movement points per turn."; - *temp += " This ship may sail into"; - if(o->sailable == 1 || o->sailable == 3) *temp += " rivers, beaches,"; - if(o->sailable == 2 || o->sailable == 3) *temp += " oceans,"; - *temp += " lakes or harbours."; - } - } - if(o->capacity) *temp += AString(" This ship can carry up to ") + o->capacity + - " weight units when moving."; - - if(o->maxMages && Globals->LIMITED_MAGES_PER_BUILDING && !Globals->ARCADIA_MAGIC) { - *temp += AString(" This structure will allow up to ") + o->maxMages + - " mages to study above level 2."; - } - int buildable = 1; - SkillType *pS = NULL; - if(o->item == -1 || o->skill == NULL) buildable = 0; - if (o->skill != NULL) pS = FindSkill(o->skill); - if (pS && (pS->flags & SkillType::DISABLED)) buildable = 0; - if(o->item != I_WOOD_OR_STONE && - (ItemDefs[o->item].flags & ItemType::DISABLED)) - buildable = 0; - if(o->item == I_WOOD_OR_STONE && - (ItemDefs[I_WOOD].flags & ItemType::DISABLED) && - (ItemDefs[I_STONE].flags & ItemType::DISABLED)) - buildable = 0; - if(!buildable) { - *temp += " This structure cannot be built by players."; - } else { - *temp += AString(" This structure is built using ") + - SkillStrs(pS) + " " + o->level + " and requires " + - o->cost + " "; - if(o->item == I_WOOD_OR_STONE) { - *temp += "wood or stone"; - } else { - *temp += ItemDefs[o->item].name; - } - *temp += " to build."; - } - - if(o->productionAided != -1 && - !(ItemDefs[o->productionAided].flags & ItemType::DISABLED)) { - *temp += " This trade structure increases the amount of "; - if(o->productionAided == I_SILVER) { - *temp += "entertainment"; - } else { - *temp += ItemDefs[o->productionAided].names; - } - *temp += " available in the region."; - } - - if(o->flags & ObjectType::OCEANBUILD) - *temp += " This structure may be built in oceans."; - - if(Globals->DECAY) { - if(o->flags & ObjectType::NEVERDECAY) { - *temp += " This structure will never decay."; - } else { - *temp += AString(" This structure can take ") + o->maxMaintenance + - " units of damage before it begins to decay."; - *temp += AString(" Damage can occur at a maximum rate of ") + - o->maxMonthlyDecay + " units per month."; - if(buildable) { - *temp += AString(" Repair of damage is accomplished at ") + - "a rate of " + o->maintFactor + " damage units per " + - "unit of "; - if(o->item == I_WOOD_OR_STONE) { - *temp += "wood or stone."; - } else { - *temp += ItemDefs[o->item].name; - } - } - } - } - - return temp; -} diff --git a/arcadia/object.h b/arcadia/object.h deleted file mode 100644 index 2770ec094..000000000 --- a/arcadia/object.h +++ /dev/null @@ -1,186 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef OBJECT_CLASS -#define OBJECT_CLASS - -class Hexside; -class Object; - -#include "alist.h" -#include "fileio.h" -#include "gamedefs.h" -#include "faction.h" -#include "items.h" - -#define I_WOOD_OR_STONE -2 - -class HexsideType { - public: - char *name; - enum { - DISABLED = 0x001, - CANMODIFY = 0x020 - }; - int flags; - - int item; - int cost; - char *skill; - int level; - - int sailable; - int movementmultiplier; - int blockeffect; - int stealthpen; - int advancepen; - - int exclusive; -}; - -extern HexsideType *HexsideDefs; - -AString *HexsideDescription(int type); - -int ParseHexsideDir(AString *); -int ParseHexside(AString *); - -class Hexside -{ - public: - Hexside(); - ~Hexside(); - - void Readin(Ainfile *f); - void Writeout(Aoutfile *f); - - int type; //exclusive types, cannot be built. Value indicates type which is present. - int bridge; //non-exclusive types. Value of -1 indicates finished, 0 not present, positive value is amount needed to finish. - int road; //non-exclusive types. - int harbour; //exclusive type, so if harbour gets completed, then is reset to zero and type = harbour. can only be built on a beach. -//currently the program is not writing out / reading in harbours. -}; - - -class ObjectType { - public: - char *name; - enum { - DISABLED = 0x001, - NOMONSTERGROWTH = 0x002, - NEVERDECAY = 0x004, - CANENTER = 0x008, - CANMODIFY = 0x020, - TRANSPORT = 0x040, - OCEANBUILD = 0x080, - SAILOVERLAND = 0x100 - }; - int flags; - - int protect; - int capacity; - int sailors; - int maxMages; - int speed; - - int item; - int cost; - char *skill; - int level; - - int maxMaintenance; - int maxMonthlyDecay; - int maintFactor; - - int monster; - - int productionAided; - int defenceArray[NUM_ATTACK_TYPES]; - - int hexside; - int sailable; - int oceanbonus; -}; - -extern ObjectType *ObjectDefs; - -AString *ObjectDescription(int obj); - -int ParseObject(AString *); - -int ObjectIsShip(int); - -class Object : public AListElem -{ - public: - Object(ARegion *region); - ~Object(); - - void Readin(Ainfile *f, AList *, ATL_VER v); - void Writeout(Aoutfile *f); - void Report(Areport *, Faction *, int, int, int, int, int, int, int, int); - - void SetName(AString *); - void SetDescribe(AString *); - - Unit *GetUnit(int); - Unit *GetUnitAlias(int, int); /* alias, faction number */ - Unit *GetUnitId(UnitId *, int); - - // AS - int IsRoad(); - - int IsBoat(); - int IsBuilding(); - int CanModify(); - int CanEnter(ARegion *, Unit *); - int GetPopulation(); - int Weight(); - Unit *ForbiddenBy(ARegion *, Unit *); - Unit *GetOwner(); - - void SetPrevDir(int); - void MoveObject(ARegion *toreg); - - AString *name; - AString *describe; - ARegion *region; - int inner; - int num; - int type; - int incomplete; - int capacity; - int runes; - int hexside; - int prevdir; - int mages; - /* The following are needed only for arcadia portals */ - int mageowner; //needs to be saved - int speedbonus; - - AList units; -}; - -#endif diff --git a/arcadia/orders.cpp b/arcadia/orders.cpp deleted file mode 100644 index e619a8110..000000000 --- a/arcadia/orders.cpp +++ /dev/null @@ -1,489 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "orders.h" - -char *od[] = { - "#atlantis", - "#end", - "unit", - "address", - "advance", - "all", - "armour", - "assassinate", - "attack", - "autotax", - "avoid", - "bank", - "behind", - "build", - "buildhexside", - "buy", - "cast", - "claim", - "combat", - "command", - "consume", - "declare", - "describe", - "destroy", - "disable", - "distribute", - "end", - "endall", - "endtemplate", - "endturn", - "enter", - "entertain", - "evict", - "exchange", - "faction", - "fightas", - "find", - "follow", - "forget", - "form", - "give", - "guard", - "hold", - "idle", - "label", - "leave", - "master", - "move", - "name", - "noaid", - "nocross", - "nospoils", - "option", - "password", - "pillage", - "pool", - "prepare", - "produce", - "promote", - "quit", - "restart", - "reveal", - "sail", - "sell", - "send", - "share", - "show", - "spoils", - "steal", - "study", - "tactics", - "tax", - "teach", - "template", - "transport", - "turn", - "type", - "weapon", - "wishdraw", - "wishskill", - "withdraw", - "work", -}; - -char **OrderStrs = od; - -int Parse1Order(AString *token) -{ - for (int i=0; iPutStr(""); - pCheckFile->PutStr(""); - pCheckFile->PutStr(AString("*** Error: ") + strError + " ***"); - } -} - -int Game::ParseDir(AString *token) -{ - for (int i=0; ivalue(); - if (num) return MOVE_ENTER + num; - return -1; -} - -int ParseTF(AString *token) -{ - if (*token == "true") return 1; - if (*token == "false") return 0; - if (*token == "t") return 1; - if (*token == "f") return 0; - if (*token == "on") return 1; - if (*token == "off") return 0; - if (*token == "1") return 1; - if (*token == "0") return 0; - return -1; -} - -UnitId *Game::ParseUnit(AString *s) -{ - AString *token = s->gettoken(); - if (!token) return 0; - - if (*token == "0") { - delete token; - UnitId *id = new UnitId; - id->unitnum = -1; - id->alias = 0; - id->faction = 0; - return id; - } - - if (*token == "faction") { - delete token; - /* Get faction number */ - token = s->gettoken(); - if (!token) return 0; - - int fn = token->value(); - delete token; - if (!fn) return 0; - - /* Next token should be "new" */ - token = s->gettoken(); - if (!token) return 0; - - if (!(*token == "new")) { - delete token; - return 0; - } - delete token; - - /* Get alias number */ - token = s->gettoken(); - if (!token) return 0; - - int un = token->value(); - delete token; - if (!un) return 0; - - /* Return UnitId */ - UnitId *id = new UnitId; - id->unitnum = 0; - id->alias = un; - id->faction = fn; - return id; - } - - if (*token == "new") { - delete token; - token = s->gettoken(); - if (!token) return 0; - - int un = token->value(); - delete token; - if (!un) return 0; - - UnitId *id = new UnitId; - id->unitnum = 0; - id->alias = un; - id->faction = 0; - return id; - } else { - int un = token->value(); - delete token; - if (!un) return 0; - - UnitId *id = new UnitId; - id->unitnum = un; - id->alias = 0; - id->faction = 0; - return id; - } -} - -int ParseFactionType(AString *o, int *type) -{ - int i; - for (i=0; igettoken(); - if (!token) return -1; - - if (*token == "generic") { - delete token; - for (i=0; igettoken(); - if (!token) return -1; - type[i] = token->value(); - delete token; - foundone = 1; - break; - } - } - if (!foundone) { - delete token; - return -1; - } - token = o->gettoken(); - } - - int tot = 0; - for (i=0; i Globals->FACTION_POINTS) return -1; - - return 0; -} - -void Game::ParseError(OrdersCheck *pCheck, Unit *pUnit, Faction *pFaction, - const AString &strError) -{ - if(pCheck) pCheck->Error(strError); - else if(pUnit) pUnit->Error(strError); - else if(pFaction) pFaction->Error(strError); -} - -Faction * Game::ParseOrders(int faction, Aorders *f, OrdersCheck *pCheck) -{ - Faction *fac = 0; - Unit *unit = 0; - - AString *order = f->GetLine(); -// FormTemplate * formtem = 0; -// int formtemline = 0; - - while (order) { - AString saveorder = *order; - int getatsign = order->getat(); - int getquietsign = order->getexclamation(); - AString *token = order->gettoken(); - - if (token) { - int i = Parse1Order(token); - switch (i) { - case -1: - ParseError(pCheck, unit, fac, *token + " is not a valid order."); - break; - case O_ATLANTIS: - if(fac) - ParseError(pCheck, 0, fac, "No #END statement given."); - delete token; - token = order->gettoken(); - if(!token) { - ParseError(pCheck, 0, 0, - "No faction number given on #atlantis line."); - fac = 0; - break; - } - if(pCheck) { - fac = &(pCheck->dummyFaction); - pCheck->numshows = 0; - } else { - if(!faction) faction = token->value(); //"faction" is only used for label orders. This stuck in to allow parsing orders without knowing which faction it is ... could also otherwise cause trouble if unexpected faction orders are pulled in - fac = GetFaction(&factions, faction); - } - - if (!fac) break; - - delete token; - token = order->gettoken(); - - if(pCheck) { - if(!token) { - ParseError(pCheck, 0, fac, - "Warning: No password on #atlantis line."); - ParseError(pCheck, 0, fac, - "If this is your first turn, ignore this " - "error."); - } - } else { - if(!(*(fac->password) == "none")) { - if(!token || !(*(fac->password) == *token)) { - ParseError(pCheck, 0, fac, - "Incorrect password on #atlantis line."); - fac = 0; - break; - } - } - - if (fac->num == monfaction || fac->num == guardfaction) { - fac = 0; - break; - } - if(!Globals->LASTORDERS_MAINTAINED_BY_SCRIPTS) - fac->lastorders = TurnNumber(); - } - - unit = 0; - break; - - case O_END: - while (unit) { - Unit *former = unit->former; - if (unit->inTurnBlock) - ParseError(pCheck, unit, fac, "TURN: without ENDTURN"); - if (unit->former) - ParseError(pCheck, unit, fac, "FORM: without END."); - if(pCheck) DoLabelOrders(pCheck, unit, fac, faction); //if not pCheck, this is done at the end of orders so that template/all orders included later in the report can be processed - if(unit && pCheck) unit->ClearOrders(); - if (pCheck && former) delete unit; - unit = former; - } - - unit = 0; -// fac = 0; - break; - - case O_UNIT: - if (fac) { - while (unit) { - Unit *former = unit->former; - if (unit->inTurnBlock) - ParseError(pCheck, unit, fac, "TURN: without ENDTURN"); - if (unit->former) - ParseError(pCheck, unit, fac, "FORM: without END."); - if(pCheck) DoLabelOrders(pCheck, unit, fac, faction); - if (unit && pCheck) unit->ClearOrders(); - if (pCheck && former) delete unit; - unit = former; - } - unit = 0; - delete token; - - token = order->gettoken(); - if (!token) { - ParseError(pCheck, 0, fac, "UNIT without unit number."); - unit = 0; - break; - } - - if(pCheck) { - if (!token->value()) { - pCheck->Error("Invalid unit number."); - } else { - unit = &(pCheck->dummyUnit); - unit->monthorders = 0; - } - } else { - unit = GetUnit(token->value()); - if(!unit || unit->faction != fac) { - fac->Error(*token + " is not your unit."); - unit = 0; - } else { - unit->ClearOrders(); - } - } - } - break; - case O_FORM: - if (fac) { - if(unit) { - if (unit->former && !unit->inTurnBlock) { - ParseError(pCheck, unit, fac, "FORM: cannot nest."); - } - else { - unit = ProcessFormOrder(unit, order, pCheck, getquietsign); - if(!pCheck) { - if(unit) unit->ClearOrders(); - } - } - } else { - ParseError(pCheck, 0, fac, - "Order given without a unit selected:"); - ParseError(pCheck, 0, fac, saveorder); - } - } - break; - case O_ENDFORM: - if (fac) { - if (unit && unit->former) { - Unit *former = unit->former; - - if (unit->inTurnBlock) - ParseError(pCheck, unit, fac, "TURN: without ENDTURN"); - if(pCheck) DoLabelOrders(pCheck, unit, fac, faction); - if (pCheck && former) delete unit; - unit = former; - } else { - ParseError(pCheck, unit, fac, "END: without FORM."); - } - } - break; - case O_ALL: - if(fac) { - //want to unselect unit here! -/* while (unit) { - Unit *former = unit->former; - if (unit->inTurnBlock) - ParseError(pCheck, unit, fac, "TURN: without ENDTURN"); - if (unit->former) - ParseError(pCheck, unit, fac, "FORM: without END."); - if(pCheck) DoLabelOrders(pCheck, unit, fac, faction); - if (unit && pCheck) unit->ClearOrders(); - if (pCheck && former) delete unit; - unit = former; - } - unit = 0; - */ - // faction is 0 if checking syntax only, not running turn. -/* if (faction == 0) { - unit = &(pCheck->dummyUnit); - unit->monthorders = 0; - } else { -*/ - if(pCheck) { - pCheck->pCheckFile->PutStr(saveorder); - } - - AString *retval; - retval = ProcessAllOrder(f, pCheck, order, fac); //no need to carry quiet sign - produce errors for incorrect TURN - if (retval) { - delete order; - order = retval; - continue; -// } - } - } - break; - case O_TEMPLATE: - if(fac) { - //want to unselect unit here! -/* while (unit) { - Unit *former = unit->former; - if (unit->inTurnBlock) - ParseError(pCheck, unit, fac, "TURN: without ENDTURN"); - if (unit->former) - ParseError(pCheck, unit, fac, "FORM: without END."); - if(pCheck) DoLabelOrders(pCheck, unit, fac, faction); - if (unit && pCheck) unit->ClearOrders(); - if (pCheck && former) delete unit; - unit = former; - } - unit = 0; - */ - // faction is 0 if checking syntax only, not running turn. -/* if (faction == 0) { - unit = &(pCheck->dummyUnit); - unit->monthorders = 0; - } else { - //want to unselect unit here! - while (unit) { - Unit *former = unit->former; - if (unit->inTurnBlock) - ParseError(pCheck, unit, fac, "TURN: without ENDTURN"); - if (unit->former) - ParseError(pCheck, unit, fac, "FORM: without END."); - if(pCheck) DoLabelOrders(pCheck, unit, fac, faction); - if (unit && pCheck) unit->ClearOrders(); - if (pCheck && former) delete unit; - unit = former; - } - unit = 0; - */ - if(pCheck) { - pCheck->pCheckFile->PutStr(saveorder); - } - - AString *retval; - retval = ProcessTemplateOrder(f, pCheck, order, fac); //no need to carry quiet sign - produce errors for incorrect TURN - if (retval) { - delete order; - order = retval; - continue; -// } - } - } - break; - case O_TURN: - if (unit && unit->inTurnBlock) { - ParseError(pCheck, unit, fac, "TURN: cannot nest"); - } else if (!unit) { - ParseError(pCheck, 0, fac, "Order given without a unit selected:"); - ParseError(pCheck, 0, fac, saveorder); - } else { - // faction is 0 if checking syntax only, not running turn. - if (faction != 0) { - AString *retval; - int dummy = 0; - retval = ProcessTurnOrder(unit, f, pCheck, getatsign, dummy); //no need to carry quiet sign - produce errors for incorrect TURN - if (retval) { - delete order; - order = retval; - continue; - } - } else { - unit->inTurnBlock = 1; - unit->presentMonthOrders = unit->monthorders; - unit->monthorders = 0; - unit->presentTaxing = unit->taxing; - unit->taxing = 0; - } - } - break; - case O_ENDTURN: - if (unit && unit->inTurnBlock) { - if (unit->monthorders) delete unit->monthorders; - unit->monthorders = unit->presentMonthOrders; - unit->presentMonthOrders = 0; - unit->taxing = unit->presentTaxing; - unit->presentTaxing = 0; - unit->inTurnBlock = 0; - } else - ParseError(pCheck, unit, fac, "ENDTURN: without TURN."); - break; - default: - if (fac) { - if (unit) { - if(!pCheck && getatsign) - unit->oldorders.Add(new AString(saveorder)); - - ProcessOrder(i, unit, order, pCheck, getquietsign); - } else { - ParseError(pCheck, 0, fac, "Order given without a unit selected:"); - ParseError(pCheck, 0, fac, saveorder); - } - } - } - SAFE_DELETE(token); - } else { - if(!pCheck) { - if(getatsign && fac && unit) - unit->oldorders.Add(new AString(saveorder)); - } - } - - delete order; - order = 0; - order = f->GetLine(); - - if(pCheck) { - pCheck->pCheckFile->PutStr(saveorder); - } - } - - while (unit) { - Unit *former = unit->former; - if (unit->inTurnBlock) - ParseError(pCheck, 0, fac, "TURN: without ENDTURN"); - if (unit->former) - ParseError(pCheck, 0, fac, "FORM: without END."); - if(unit && pCheck) unit->ClearOrders(); - if (pCheck && former) delete unit; - unit = former; - } - - if(unit && pCheck) { - DoLabelOrders(pCheck, unit, fac, faction); //the ALL and LABEL might not have been put in, but at least this gives us some chance of processing ALL/LABEL orders - unit->ClearOrders(); - unit = 0; - } - - //process type/template and label/all orders - if(!pCheck) { - forlist(®ions) { - ARegion *r = (ARegion *)elem; - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if(u->faction == fac) DoLabelOrders(0, u, fac, faction); - } - } - } - } - - return fac; -} - -void Game::DoLabelOrders(OrdersCheck *pCheck, Unit *unit, Faction *fac, int faction) -{ - if(unit->label) DoLabelOrder(pCheck, unit, fac, faction, 0); - if(unit->typeorders.Num()) { - forlist(&unit->typeorders) { - AString *name = (AString *) elem; - if(name) DoLabelOrder(pCheck, unit, fac, faction, name); - } - unit->typeorders.DeleteAll(); - } -} - - -void Game::DoLabelOrder(OrdersCheck *pCheck, Unit *unit, Faction *fac, int faction, AString *unittype) //label = 0 for label orders -{ - if(!fac) return; - if(!unit) return; - - FormTemplate *formtem = 0; - if(!unittype) { - forlist(&fac->labeltemplates) { - FormTemplate *ftem = (FormTemplate *) elem; - if(*ftem->name == *unit->label) formtem = ftem; - } - if(!formtem) return; - } else { - forlist(&fac->formtemplates) { - FormTemplate *ftem = (FormTemplate *) elem; - if(*ftem->name == *unittype) formtem = ftem; - } - if(!formtem) { - if(!pCheck) ParseError(pCheck, unit, fac, AString("TYPE: Could not find template ") + *unittype); //no error for pCheck as it may refer to a saved template - return; - } - } - - AString *order; - int linenum = 0; - int upto = 1; - - forlist(&formtem->orders) { - order = new AString(*((AString *) elem)); //this gets the temp'th order - linenum++; //1 for first line, etc. Used in turn orders, where passing a 1 will access the second line. - if(linenum < upto) continue; - else upto = linenum; - - AString saveorder = *order; - int getatsign = order->getat(); - int getquietsign = order->getexclamation(); - AString *token = order->gettoken(); - - if (token) { - int i = Parse1Order(token); - switch (i) { - case -1: - ParseError(pCheck, unit, fac, *token + " is not a valid order."); - break; - case O_TURN: - if (unit && unit->inTurnBlock) { - ParseError(pCheck, unit, fac, "TURN: cannot nest"); - } else { - // faction is 0 if checking syntax only, not running turn. - if (faction != 0) { - AString *retval; - retval = ProcessTurnOrder(unit, 0, pCheck, getatsign, upto, formtem); //no need to carry quiet sign - produce errors for incorrect TURN - upto++; //upto gets returned at the ENDTURN line (assuming it exists) - if (retval) { - delete order; - order = retval; - continue; - } - } else { - unit->inTurnBlock = 1; - unit->presentMonthOrders = unit->monthorders; - unit->monthorders = 0; - unit->presentTaxing = unit->taxing; - unit->taxing = 0; - } - } - break; - case O_ENDTURN: - if (unit->inTurnBlock) { - if (unit->monthorders) delete unit->monthorders; - unit->monthorders = unit->presentMonthOrders; - unit->presentMonthOrders = 0; - unit->taxing = unit->presentTaxing; - unit->presentTaxing = 0; - unit->inTurnBlock = 0; - } else - ParseError(pCheck, unit, fac, "ENDTURN: without TURN."); - break; - default: - if(!pCheck && getatsign) unit->oldorders.Add(new AString(saveorder)); - ProcessOrder(i, unit, order, pCheck, getquietsign); - } - SAFE_DELETE(token); - } - } -} - -void Game::ProcessOrder(int orderNum, Unit *unit, AString *o, - OrdersCheck *pCheck, int isquiet) -{ - switch(orderNum) { - case O_ADDRESS: - ProcessAddressOrder(unit, o, pCheck); - break; - case O_ADVANCE: - ProcessAdvanceOrder(unit, o, pCheck, isquiet); - break; - case O_ASSASSINATE: - ProcessAssassinateOrder(unit, o, pCheck, isquiet); - break; - case O_ATTACK: - ProcessAttackOrder(unit, o, pCheck, isquiet); - break; - case O_AUTOTAX: - ProcessAutoTaxOrder(unit, o, pCheck); - break; - case O_AVOID: - ProcessAvoidOrder(unit, o, pCheck); - break; - case O_BANK: - ProcessBankOrder(unit, o, pCheck, isquiet); - break; - case O_IDLE: - ProcessIdleOrder(unit, o, pCheck); - break; - case O_BEHIND: - ProcessBehindOrder(unit, o, pCheck); - break; - case O_BUILD: //this includes BUILDHEXSIDE - case O_BUILDHEXSIDE: - ProcessBuildOrder(unit, o, pCheck, isquiet); - break; - case O_BUY: - ProcessBuyOrder(unit, o, pCheck, isquiet); - break; - case O_CAST: - ProcessCastOrder(unit, o, pCheck, isquiet); - break; - case O_CLAIM: - ProcessClaimOrder(unit, o, pCheck, isquiet); - break; - case O_COMBAT: - ProcessCombatOrder(unit, o, pCheck); - break; - case O_COMMAND: - ProcessCommandOrder(unit, o, pCheck); - break; - case O_CONSUME: - ProcessConsumeOrder(unit, o, pCheck); - break; - case O_DECLARE: - ProcessDeclareOrder(unit->faction, o, pCheck, isquiet); - break; - case O_DESCRIBE: - ProcessDescribeOrder(unit, o, pCheck, isquiet); - break; - case O_LABEL: - ProcessLabelOrder(unit, o, pCheck, isquiet); - break; - case O_DESTROY: - ProcessDestroyOrder(unit, pCheck, isquiet); - break; - case O_DISABLE: - ProcessDisableOrder(unit, o, pCheck, isquiet); - break; - case O_ENTER: - ProcessEnterOrder(unit, o, pCheck, isquiet); - break; - case O_ENTERTAIN: - ProcessEntertainOrder(unit, pCheck, isquiet); - break; - case O_EVICT: - ProcessEvictOrder(unit, o, pCheck, isquiet); - break; - case O_EXCHANGE: - ProcessExchangeOrder(unit, o, pCheck, isquiet); - break; - case O_FACTION: - ProcessFactionOrder(unit, o, pCheck, isquiet); - break; - case O_FIGHTAS: - ProcessFightAsOrder(unit, o, pCheck); - break; - case O_TACTICS: - ProcessTacticsOrder(unit, o, pCheck); - break; - case O_FIND: - ProcessFindOrder(unit, o, pCheck, isquiet); - break; - case O_FOLLOW: - ProcessFollowOrder(unit, o, pCheck, isquiet); - break; - case O_FORGET: - ProcessForgetOrder(unit, o, pCheck, isquiet); - break; - case O_WISHDRAW: - ProcessWishdrawOrder(unit, o, pCheck); - break; - case O_WISHSKILL: - ProcessWishskillOrder(unit, o, pCheck); - break; - case O_WITHDRAW: - ProcessWithdrawOrder(unit, o, pCheck, isquiet); - break; - case O_MASTER: - ProcessMasterOrder(unit, o, pCheck, isquiet); - break; - case O_GIVE: - ProcessGiveOrder(unit, o, pCheck, isquiet); - break; - case O_GUARD: - ProcessGuardOrder(unit, o, pCheck, isquiet); - break; - case O_HOLD: - ProcessHoldOrder(unit, o, pCheck); - break; - case O_LEAVE: - ProcessLeaveOrder(unit, pCheck, isquiet); - break; - case O_MOVE: - ProcessMoveOrder(unit, o, pCheck, isquiet); - break; - case O_NAME: - ProcessNameOrder(unit, o, pCheck, isquiet); - break; - case O_NOAID: - ProcessNoaidOrder(unit, o, pCheck); - break; - case O_NOCROSS: - ProcessNocrossOrder(unit, o, pCheck); - break; - case O_NOSPOILS: - ProcessNospoilsOrder(unit, o, pCheck); - break; - case O_OPTION: - ProcessOptionOrder(unit, o, pCheck); - break; - case O_PASSWORD: - ProcessPasswordOrder(unit, o, pCheck); - break; - case O_PILLAGE: - ProcessPillageOrder(unit, pCheck, isquiet); - break; - case O_PREPARE: - ProcessPrepareOrder(unit, o, pCheck); - break; - case O_WEAPON: - ProcessWeaponOrder(unit, o, pCheck); - break; - case O_ARMOR: - ProcessArmorOrder(unit, o, pCheck); - break; - case O_PRODUCE: - ProcessProduceOrder(unit, o, pCheck, isquiet); - break; - case O_PROMOTE: - ProcessPromoteOrder(unit, o, pCheck, isquiet); - break; - case O_QUIT: - ProcessQuitOrder(unit, o, pCheck); - break; - case O_RESTART: - ProcessRestartOrder(unit, o, pCheck); - break; - case O_REVEAL: - ProcessRevealOrder(unit, o, pCheck); - break; - case O_SAIL: - ProcessSailOrder(unit, o, pCheck, isquiet); - break; - case O_SELL: - ProcessSellOrder(unit, o, pCheck, isquiet); - break; - case O_SEND: - ProcessSendOrder(unit, o, pCheck, isquiet); - break; - case O_SHARE: - ProcessShareOrder(unit, o, pCheck); - break; - case O_SHOW: - ProcessReshowOrder(unit, o, pCheck); - break; - case O_SPOILS: - ProcessSpoilsOrder(unit, o, pCheck); - break; - case O_STEAL: - ProcessStealOrder(unit, o, pCheck, isquiet); - break; - case O_STUDY: - ProcessStudyOrder(unit, o, pCheck, isquiet); - break; - case O_TAX: - ProcessTaxOrder(unit, pCheck, isquiet); - break; - case O_TEACH: - ProcessTeachOrder(unit, o, pCheck, isquiet); - break; - case O_TYPE: - ProcessTypeOrder(unit, o, pCheck); - break; - case O_WORK: - ProcessWorkOrder(unit, pCheck, isquiet); - break; - case O_TRANSPORT: - ProcessTransportOrder(unit, o, pCheck, isquiet); - break; - case O_DISTRIBUTE: - ProcessDistributeOrder(unit, o, pCheck, isquiet); - break; - } -} - -void Game::ProcessPasswordOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(pCheck) return; - - AString *token = o->gettoken(); - if (u->faction->password) delete u->faction->password; - if (token) { - u->faction->password = token; - u->faction->Event(AString("Password is now: ") + *token); - } else { - u->faction->password = new AString("none"); - u->faction->Event("Password cleared."); - } -} - -void Game::ProcessOptionOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "OPTION: What option?"); - return; - } - - if (*token == "times") { - delete token; - if(!pCheck) { - u->faction->Event("Times will be sent to your faction."); - u->faction->times = 1; - } - return; - } - - if (*token == "notimes") { - delete token; - if(!pCheck) { - u->faction->Event("Times will not be sent to your faction."); - u->faction->times = 0; - } - return; - } - - if (*token == "showattitudes") { - delete token; - u->faction->Event("Units will now have a leading sign to show your " - "attitude to them."); - u->faction->showunitattitudes = 1; - return; - } - - if (*token == "dontshowattitudes") { - delete token; - u->faction->Event("Units will now have a leading minus sign regardless" - " of your attitude to them."); - u->faction->showunitattitudes = 0; - return; - } - - if (*token == "template") { - delete token; - - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "OPTION: No template type specified."); - return; - } - - int newformat = -1; - if (*token == "off") { - newformat = TEMPLATE_OFF; - } - if (*token == "short") { - newformat = TEMPLATE_SHORT; - } - if (*token == "long") { - newformat = TEMPLATE_LONG; - } - // DK - if (*token == "map") { - newformat = TEMPLATE_MAP; - } - delete token; - - if (newformat == -1) { - ParseError(pCheck, u, 0, "OPTION: Invalid template type."); - return; - } - - if(!pCheck) { - u->faction->temformat = newformat; - } - - return; - } - - delete token; - - ParseError(pCheck, u, 0, "OPTION: Invalid option."); -} - -void Game::ProcessReshowOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - AString *token = o->gettoken(); - if (!token) { - // LLS - ParseError(pCheck, u, 0, "SHOW: Show what?"); - return; - } - - if(pCheck) { - if(pCheck->numshows++ > 100) { - if(pCheck->numshows == 102) { - pCheck->Error("Too many SHOW orders."); - } - return; - } - } else { - if (u->faction->numshows++ > 100) { - if (u->faction->numshows == 102) { - u->Error("Too many SHOW orders."); - } - return; - } - } - - if (*token == "skill") { - delete token; - - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "SHOW: Show what skill?"); - return; - } - int sk = ParseSkill(token); - delete token; - - if(sk == -1 || - (SkillDefs[sk].flags & SkillType::DISABLED) || - ((SkillDefs[sk].flags & SkillType::APPRENTICE) && - !Globals->APPRENTICES_EXIST)) { - ParseError(pCheck, u, 0, "SHOW: No such skill."); - return; - } - - token = o->gettoken(); - int lvl; - if (!token) { - ParseError(pCheck, u, 0, "SHOW: No skill level given. Showing level 1"); - lvl = 1; - } - else { - lvl = token->value(); - delete token; - } - - if(!pCheck) { -/* //Disabled for Arcadia - you can see any skill you want to! - if (lvl > u->faction->skills.GetDays(sk)) { - u->Error("SHOW: Faction doesn't have that skill."); - return; - }*/ - - u->faction->shows.Add(new ShowSkill(sk, lvl)); - } - return; - } - - if (*token == "item") { - delete token; - token = o->gettoken(); - - if (!token) { - ParseError(pCheck, u, 0, "SHOW: Show which item?"); - return; - } - - int item = ParseEnabledItem(token); - delete token; - - if(item == -1 || (ItemDefs[item].flags & ItemType::DISABLED)) { - ParseError(pCheck, u, 0, "SHOW: No such item."); - return; - } - - if(!pCheck) { - u->faction->DiscoverItem(item, 1, 0); - } - return; - } - - if (*token == "object") { - delete token; - token = o->gettoken(); - - if(!token) { - ParseError(pCheck, u, 0, "SHOW: Show which object?"); - return; - } - - int obj = ParseObject(token); - delete token; - - if(obj == -1 || (ObjectDefs[obj].flags & ObjectType::DISABLED)) { - ParseError(pCheck, u, 0, "SHOW: No such object."); - return; - } - - if(!pCheck) { - u->faction->objectshows.Add(ObjectDescription(obj)); - } - return; - } - - ParseError(pCheck, u, 0, "SHOW: Show what?"); -} - -void Game::ProcessForgetOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "FORGET: No skill given."); - return; - } - - int sk = ParseSkill(token); - delete token; - - if (sk==-1) { - ParseError(pCheck, u, 0, "FORGET: Invalid skill."); - return; - } - - if(!pCheck) { - ForgetOrder *ord = new ForgetOrder; - ord->quiet = isquiet; - ord->skill = sk; - u->forgetorders.Add(ord); - } -} - -void Game::ProcessEntertainOrder(Unit *unit, OrdersCheck *pCheck, int isquiet) -{ - if (unit->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((unit->taxing == TAX_TAX) || - (unit->taxing == TAX_PILLAGE)))) { - AString err = "ENTERTAIN: Overwriting previous "; - if (unit->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, unit, 0, err); - if (unit->monthorders) delete unit->monthorders; - } - ProduceOrder *ord = new ProduceOrder; - ord->item = I_SILVER; - ord->skill = S_ENTERTAINMENT; - ord->quiet = isquiet; - unit->monthorders = ord; -} - -void Game::ProcessCombatOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - AString *token = o->gettoken(); - if (!token) { - if(!pCheck) { - u->combat = -1; - u->Event("Combat spell set to none."); - } - return; - } - int sk = ParseSkill(token); - delete token; - - if (sk==-1) { - ParseError(pCheck, u, 0, "COMBAT: Invalid skill."); - return; - } - if(!(SkillDefs[sk].flags & SkillType::MAGIC)) { - ParseError(pCheck, u, 0, "COMBAT: That is not a magic skill."); - return; - } - if(!(SkillDefs[sk].flags & SkillType::COMBAT)) { - ParseError(pCheck, u, 0, - "COMBAT: That skill cannot be used in combat."); - return; - } - - if(!pCheck) { - if (u->type != U_MAGE) { - u->Error("COMBAT: That unit is not a hero."); - return; - } - if (!u->GetSkill(sk)) { - u->Error("COMBAT: Unit does not possess that skill."); - return; - } - - u->combat = sk; - AString temp = AString("Combat spell set to ") + SkillDefs[sk].name; - if(Globals->USE_PREPARE_COMMAND) { - u->readyItem = -1; - temp += " and prepared item set to none"; - } - temp += "."; - - u->Event(temp); - } -} - -void Game::ProcessCommandOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!pCheck) { - if (u->type != U_MAGE) { - u->Error("COMMAND: That unit is not a hero."); - return; - } - u->SetFlag(FLAG_COMMANDER, 1); - //remove the old commander - forlist(®ions) { - ARegion *reg = (ARegion *)elem; - forlist(®->objects) { - Object *obj = (Object *)elem; - forlist(&obj->units) { - Unit *u2 = (Unit *)elem; - if((u2->flags & FLAG_COMMANDER) && u2->faction == u->faction && u2 != u) { - u2->SetFlag(FLAG_COMMANDER, 0); - u2->Event("Is removed from command"); - } - } - } - } - u->Event(AString(*u->name) + " takes command of your faction."); - - if(u->GetEthnicity() != u->faction->ethnicity) { - u->faction->ethnicity = u->GetEthnicity(); - WorldEvent *event = new WorldEvent; - event->type = WorldEvent::CONVERSION; - event->fact1 = u->faction->num; - event->fact2 = u->faction->ethnicity; - event->reportdelay = 0; - worldevents.Add(event); - } - } -} - -// Lacandon's prepare command -void Game::ProcessPrepareOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!(Globals->USE_PREPARE_COMMAND)) { - ParseError(pCheck, u, 0, "PREPARE is not a valid order."); - return; - } - - AString *token = o->gettoken(); - if(!token) { - if(!pCheck) { - u->readyItem = -1; - u->Event("Prepared battle item set to none."); - } - return; - } - int it = ParseEnabledItem(token); - if (it == -1) { - ParseError(pCheck, u, 0, "PREPARE: Invalid item."); - return; - } - BattleItemType *bt = FindBattleItem(token->Str()); - delete token; - - if(bt == NULL) { - ParseError(pCheck, u, 0, "PREPARE: Invalid item."); - return; - } - - if (!bt->flags & BattleItemType::SPECIAL) { - ParseError(pCheck, u, 0, "PREPARE: That item cannot be prepared."); - return; - } - - if(!pCheck) { - if ((bt->flags & BattleItemType::MAGEONLY) && - !((u->type == U_MAGE) || (u->type == U_APPRENTICE) || - (u->type == U_GUARDMAGE))) { - u->Error("PREPARE: Only a mage or apprentice may use this item."); - return; - } - if(!u->items.GetNum(it)) { - u->Error("PREPARE: Unit does not possess that item."); - return; - } - u->readyItem = it; - AString temp; - temp = AString("Prepared item set to ") + ItemDefs[it].name; - if(u->combat != -1) { - u->combat = -1; - temp += " and combat spell set to none"; - } - temp += "."; - u->Event(temp); - } -} - -void Game::ProcessWeaponOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!(Globals->USE_WEAPON_ARMOR_COMMAND)) { - ParseError(pCheck, u, 0, "WEAPON is not a valid order."); - return; - } - - AString *token = o->gettoken(); - int i; - if (!token) { - if (!pCheck) { - for (i = 0; i < MAX_READY; ++i) u->readyWeapon[i] = -1; - u->Event("Preferred weapons set to none."); - } - return; - } - int it; - int items[MAX_READY]; - i = 0; - while (token && (i < MAX_READY)) { - it = ParseEnabledItem(token); - delete token; - if (it == -1) { - ParseError(pCheck, u, 0, "WEAPON: Invalid item."); - } else if (!(ItemDefs[it].type & IT_WEAPON)) { - ParseError(pCheck, u, 0, "WEAPON: Item is not a weapon."); - } else { - if(!pCheck) items[i++] = it; - } - token = o->gettoken(); - } - if (token) delete token; - if(pCheck) return; - - while (i < MAX_READY) { - items[i++] = -1; - } - if (items[0] == -1) return; - AString temp = "Preferred weapons set to: "; - for (i=0; ireadyWeapon[i] = items[i]; - if (items[i] != -1) { - if (i > 0) temp += ", "; - temp += ItemDefs[items[i]].name; - } - } - temp += "."; - u->Event(temp); -} - -void Game::ProcessArmorOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!(Globals->USE_WEAPON_ARMOR_COMMAND)) { - ParseError(pCheck, u, 0, "ARMOR is not a valid order."); - return; - } - - AString *token = o->gettoken(); - int i; - if (!token) { - if (!pCheck) { - for (i = 0; i < MAX_READY; ++i) u->readyArmor[i] = -1; - u->Event("Preferred armor set to none."); - } - return; - } - int it; - int items[MAX_READY]; - i = 0; - while (token && (i < MAX_READY)) { - it = ParseEnabledItem(token); - delete token; - if (it == -1) { - ParseError(pCheck, u, 0, "ARMOR: Invalid item."); - } else if (!(ItemDefs[it].type & IT_ARMOR)) { - ParseError(pCheck, u, 0, "ARMOR: Item is not armor."); - } else { - if(!pCheck) items[i++] = it; - } - token = o->gettoken(); - } - if (token) delete token; - if(pCheck) return; - - while (i < MAX_READY) { - items[i++] = -1; - } - if (items[0] == -1) return; - AString temp = "Preferred armour set to: "; - for (i=0; ireadyArmor[i] = items[i]; - if (items[i] != -1) { - if (i > 0) temp += ", "; - temp += ItemDefs[items[i]].name; - } - } - temp += "."; - u->Event(temp); -} - -void Game::ProcessClaimOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "CLAIM: No amount given."); - return; - } - - int value = token->value(); - delete token; - if (!value) { - ParseError(pCheck, u, 0, "CLAIM: No amount given."); - return; - } - - if(!pCheck) { - if (value > u->faction->unclaimed) { - if(!isquiet) u->Error("CLAIM: Don't have that much unclaimed silver."); - value = u->faction->unclaimed; - } - u->faction->unclaimed -= value; - u->SetMoney(u->GetMoney() + value); - u->Event(AString("Claims $") + value + "."); - } -} - -void Game::ProcessFactionOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_FACTION_TYPES) { - ParseError(pCheck, u, 0, - "FACTION: Invalid order, no faction types in this game."); - return; - } - - int oldfactype[NFACTYPES]; - int factype[NFACTYPES]; - - int i; - if(!pCheck) { - for(i = 0; i < NFACTYPES; i++) { - oldfactype[i] = u->faction->type[i]; - } - } - - int retval = ParseFactionType(o, factype); - if (retval == -1) { - ParseError(pCheck, u, 0, "FACTION: Bad faction type."); - return; - } - - if(!pCheck) { - int m = CountMages(u->faction); - int a = CountApprentices(u->faction); - - for(i = 0; i < NFACTYPES; i++) u->faction->type[i] = factype[i]; - - if(m > AllowedMages(u->faction)) { - if(!isquiet) u->Error(AString("FACTION: Too many mages to change to that " - "faction type.")); - - for(i = 0; i < NFACTYPES; i++) - u->faction->type[i] = oldfactype[i]; - - return; - } - - if (a > AllowedApprentices(u->faction)) { - if(!isquiet) u->Error(AString("FACTION: Too many apprentices to change to that " - "faction type.")); - - for(i = 0; i < NFACTYPES; i++) - u->faction->type[i] = oldfactype[i]; - - return; - } - - if (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - int q = CountQuarterMasters(u->faction); - if((Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) && - (q > AllowedQuarterMasters(u->faction))) { - if(!isquiet) u->Error(AString("FACTION: Too many quartermasters to " - "change to that faction type.")); - - for(i = 0; i < NFACTYPES; i++) - u->faction->type[i] = oldfactype[i]; - - return; - } - } - - u->faction->lastchange = TurnNumber(); - u->faction->DefaultOrders(); - } -} - -void Game::ProcessAssassinateOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *id = ParseUnit(o); - if (!id || id->unitnum == -1) { - ParseError(pCheck, u, 0, "ASSASSINATE: No target given."); - return; - } - if(!pCheck) { - if (u->stealorders) delete u->stealorders; - AssassinateOrder *ord = new AssassinateOrder; - ord->target = id; - ord->quiet = isquiet; - u->stealorders = ord; - } -} - -void Game::ProcessStealOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *id = ParseUnit(o); - if (!id || id->unitnum == -1) { - ParseError(pCheck, u, 0, "STEAL: No target given."); - return; - } - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "STEAL: No item given."); - delete id; - return; - } - int i = ParseEnabledItem(token); - delete token; - if (i == -1) { - ParseError(pCheck, u, 0, "STEAL: Bad item given."); - delete id; - return; - } - - if (IsSoldier(i)) { - ParseError(pCheck, u, 0, "STEAL: Can't steal that."); - delete id; - return; - } - if(!pCheck) { - StealOrder *ord = new StealOrder; - ord->target = id; - ord->item = i; - ord->quiet = isquiet; - if (u->stealorders) delete u->stealorders; - u->stealorders = ord; - } -} - -void Game::ProcessQuitOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!pCheck) { - if (u->faction->password && !(*(u->faction->password) == "none")) { - AString *token = o->gettoken(); - if (!token) { - u->faction->Error("QUIT: Must give the correct password."); - return; - } - - if (!(*token == *(u->faction->password))) { - delete token; - u->faction->Error("QUIT: Must give the correct password."); - return; - } - - delete token; - } - - if (u->faction->quit != QUIT_AND_RESTART) { - u->faction->quit = QUIT_BY_ORDER; - } - } -} - -void Game::ProcessRestartOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!pCheck) { - if (u->faction->password && !(*(u->faction->password) == "none")) { - AString *token = o->gettoken(); - if (!token) { - u->faction->Error("RESTART: Must give the correct password."); - return; - } - - if (!(*token == *(u->faction->password))) { - delete token; - u->faction->Error("RESTART: Must give the correct password."); - return; - } - - delete token; - } - - if (u->faction->quit != QUIT_AND_RESTART) { - u->faction->quit = QUIT_AND_RESTART; - Faction *pFac = AddFaction(0, NULL); - pFac->SetAddress(*(u->faction->address)); - AString *pass = new AString(*(u->faction->password)); - pFac->password = pass; - AString *facstr = new AString(AString("Restarting ") - + *(pFac->address) + "."); - newfactions.Add(facstr); - } - } -} - -void Game::ProcessDestroyOrder(Unit *u, OrdersCheck *pCheck, int isquiet) -{ - if(!pCheck) { - u->destroy = 1; //No easy way of keeping this quiet - } -} - -void Game::ProcessFindOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "FIND: No faction number given."); - return; - } - int n = token->value(); - int is_all = (*token == "all"); - delete token; - if (n==0 && !is_all) { - ParseError(pCheck, u, 0, "FIND: No faction number given."); - return; - } - if(!pCheck) { - FindOrder *ord = new FindOrder; - ord->find = n; - ord->quiet = isquiet; - u->findorders.Add(ord); - } -} - -void Game::ProcessConsumeOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - AString *token = o->gettoken(); - if (token) { - if (*token == "unit") { - if(!pCheck) { - u->SetFlag(FLAG_CONSUMING_UNIT, 1); - u->SetFlag(FLAG_CONSUMING_FACTION, 0); - } - delete token; - return; - } - - if (*token == "faction") { - if(!pCheck) { - u->SetFlag(FLAG_CONSUMING_UNIT, 0); - u->SetFlag(FLAG_CONSUMING_FACTION, 1); - } - delete token; - return; - } - - if (*token == "none") { - if(!pCheck) { - u->SetFlag(FLAG_CONSUMING_UNIT, 0); - u->SetFlag(FLAG_CONSUMING_FACTION, 0); - } - delete token; - return; - } - - delete token; - ParseError(pCheck, u, 0, "CONSUME: Invalid value."); - } else { - if(!pCheck) { - u->SetFlag(FLAG_CONSUMING_UNIT, 0); - u->SetFlag(FLAG_CONSUMING_FACTION, 0); - } - } -} - -void Game::ProcessBankOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - int amt; - int what; -// int inbank; -// int lvl; -// int max = Globals->BANK_MAXSKILLPERLEVEL *5; // value if banks & skills disabled - - if (!(Globals->ALLOW_BANK & GameDefs::BANK_ENABLED)) { - ParseError(pCheck, u, 0, "There are no banks in this game."); - return; - } - AString *token = o->gettoken(); - if (token) { - if (*token == "deposit") - what = 2; - if (*token == "withdraw") - what = 1; - delete token; - if (what == 2) { - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "BANK: No amount to deposit given."); - return; - } - amt = token->value(); - delete token; - } else if (what == 1) { // withdrawal - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "BANK: No amount to withdraw given."); - return; - } - amt = token->value(); - delete token; - } else { - ParseError(pCheck, u, 0, "BANK: No WITHDRAW or DEPOSIT given."); - return; - } - } else { - ParseError(pCheck, u, 0, "BANK: No action given."); - return; - } - if(!pCheck) { - BankOrder *ord = new BankOrder; - ord->what = what; - ord->amount = amt; - ord->quiet = isquiet; - u->bankorders.Add(ord); - } - return; -} - -void Game::ProcessRevealOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if(!pCheck) { - AString *token = o->gettoken(); - if (token) { - if (*token == "unit") { - u->reveal = REVEAL_UNIT; - delete token; - return; - } - if (*token == "faction") { - delete token; - u->reveal = REVEAL_FACTION; - return; - } - if (*token == "none") { - delete token; - u->reveal = REVEAL_NONE; - return; - } - } else { - u->reveal = REVEAL_NONE; - } - } -} - -void Game::ProcessTaxOrder(Unit *u, OrdersCheck *pCheck, int isquiet) -{ - if (u->taxing == TAX_PILLAGE) { - ParseError(pCheck, u, 0, "TAX: The unit is already pillaging."); - return; - } - if(Globals->TAX_PILLAGE_MONTH_LONG && u->monthorders) { - delete u->monthorders; - u->monthorders = NULL; - AString err = "TAX: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - - u->taxing = TAX_TAX; //no easy way to keep quiet -} - -void Game::ProcessPillageOrder(Unit *u, OrdersCheck *pCheck, int isquiet) -{ - if (u->taxing == TAX_TAX) { - ParseError(pCheck, u, 0, "PILLAGE: The unit is already taxing."); - return; - } - if(Globals->TAX_PILLAGE_MONTH_LONG && u->monthorders) { - delete u->monthorders; - u->monthorders = NULL; - AString err = "PILLAGE: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - - u->taxing = TAX_PILLAGE; -} - -void Game::ProcessPromoteOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *id = ParseUnit(o); - if (!id || id->unitnum == -1) { - ParseError(pCheck, u, 0, "PROMOTE: No target given."); - return; - } - if(!pCheck) { - if (u->promote) { - delete u->promote; - } - u->promote = id; - u->promotequiet = isquiet; - } -} - -void Game::ProcessLeaveOrder(Unit *u, OrdersCheck *pCheck, int isquiet) -{ - if(!pCheck) { -// if (u->monthorders && u->monthorders->type == O_BUILD) return; - if (u->enter == 0) u->enter = -1; - } -} - -void Game::ProcessEnterOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "ENTER: No object specified."); - return; - } - int i = token->value(); - delete token; - if (i) { - if(!pCheck) { - u->enter = i; - } - } else { - ParseError(pCheck, u, 0, "ENTER: No object specified."); - } -} - -void Game::ProcessBuildOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (token) { - if(*token == "help") { - UnitId *targ = 0; - delete token; - if(!pCheck) { - targ = ParseUnit(o); - if(!targ) { - unit->Error("BUILD: Non-existent unit to help."); - return; - } - if(targ->unitnum == -1) { - unit->Error("BUILD: Non-existent unit to help."); - return; - } - } - BuildOrder *ord = new BuildOrder; - ord->target = targ; - ord->quiet = isquiet; - if (unit->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((unit->taxing == TAX_TAX) || - (unit->taxing == TAX_PILLAGE)))) { - if (unit->monthorders) delete unit->monthorders; - AString err = "BUILD: Overwriting previous "; - if (unit->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, unit, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) unit->taxing = TAX_NONE; - unit->monthorders = ord; -// if (unit->enter == -1) unit->enter = 0; - return; - } - - int ot = ParseObject(token); - if (ot==-1 || ObjectDefs[ot].flags & ObjectType::DISABLED) { - int ht = ParseHexside(token); - delete token; - if (ht==-1 || HexsideDefs[ht].flags & HexsideType::DISABLED || !Globals->HEXSIDE_TERRAIN) { - ParseError(pCheck, unit, 0, "BUILD: Not a valid object name."); - return; - } else { - token = o->gettoken(); - int dir = ParseHexsideDir(token); - if(dir<0 || dir>5) { - ParseError(pCheck, unit, 0, "BUILD: Not a valid direction."); - return; - } - BuildHexsideOrder *ord = new BuildHexsideOrder; - ord->terrain = ht; - ord->direction = dir; - ord->quiet = isquiet; - if (unit->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((unit->taxing == TAX_TAX) || (unit->taxing == TAX_PILLAGE)))) { - if (unit->monthorders) delete unit->monthorders; - AString err = "BUILD: Overwriting previous "; - if (unit->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, unit, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) unit->taxing = TAX_NONE; - unit->monthorders = ord; -// if (unit->enter == -1) unit->enter = 0; - return; - } - } - delete token; - if (!pCheck) { - ARegion *reg = unit->object->region; - if (TerrainDefs[reg->type].similar_type == R_OCEAN && !(ObjectDefs[ot].flags & ObjectType::OCEANBUILD)) { - if(!isquiet) unit->Error("BUILD: Can't build that in an ocean."); - return; - } - - if (ObjectIsShip(ot) && !(ObjectDefs[ot].flags & ObjectType::SAILOVERLAND) && !Globals->HEXSIDE_TERRAIN) { - if (!reg->IsCoastalOrLakeside()) { - if(!isquiet) unit->Error("BUILD: Can't build ship in " - "non-(coastal or lakeside) region."); - return; - } - } - if (reg->buildingseq > 99) { - if(!isquiet) unit->Error("BUILD: The region is full."); - return; - } -/* Hexside Patch 030825 BS*/ - int dir=-1; - if (ObjectDefs[ot].hexside && Globals->HEXSIDE_TERRAIN) { - AString * t = o->gettoken(); - if (!t) { - if(!isquiet) unit->Error("BUILD: No direction specified."); - return; - } - dir = ParseHexsideDir(t); - if(dir < 0) { - if(!isquiet) unit->Error("BUILD: Incorrect direction specified."); - return; - } - if (reg->neighbors[dir]->buildingseq > 99) { - if(!isquiet) unit->Error("BUILD: The neighbouring region is full."); - return; - } - } - - - Object *obj = new Object(reg); - obj->type = ot; - obj->incomplete = ObjectDefs[obj->type].cost; - obj->hexside = dir; - obj->inner = -1; - unit->build = obj; - unit->object->region->objects.Add(obj); - } - } - - BuildOrder *ord = new BuildOrder; - ord->target = NULL; - ord->quiet = isquiet; - if (unit->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((unit->taxing == TAX_TAX) || (unit->taxing == TAX_PILLAGE)))) { - if (unit->monthorders) delete unit->monthorders; - AString err = "BUILD: Overwriting previous "; - if (unit->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, unit, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) unit->taxing = TAX_NONE; - unit->monthorders = ord; -// if (unit->enter == -1) unit->enter = 0; -} - -void Game::ProcessAttackOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *id = ParseUnit(o); - while (id && id->unitnum != -1) { - if(!pCheck) { - if (!u->attackorders) u->attackorders = new AttackOrder; - u->attackorders->targets.Add(id); - if(!isquiet) u->attackorders->quiet = 0; - } - id = ParseUnit(o); - } -} - -void Game::ProcessSellOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "SELL: Number to sell not given."); - return; - } - int num = 0; - if(*token == "ALL") { - num = -1; - } else { - num = token->value(); - } - delete token; - if (!num) { - ParseError(pCheck, u, 0, "SELL: Number to sell not given."); - return; - } - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "SELL: Item not given."); - return; - } - int it = ParseGiveableItem(token); - delete token; - if (it == -1) { - ParseError(pCheck, u, 0, "SELL: Can't sell that."); - return; - } - if(ItemDefs[it].flags & ItemType::DISABLED) { - ParseError(pCheck, u, 0, "SELL: Can't sell that."); - return; - } - if(!pCheck) { - SellOrder *ord = new SellOrder; - ord->item = it; - ord->num = num; - ord->quiet = isquiet; - u->sellorders.Add(ord); - } -} - -void Game::ProcessBuyOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "BUY: Number to buy not given."); - return; - } - int num = 0; - if(*token == "ALL") { - num = -1; - } else { - num = token->value(); - } - delete token; - if (!num) { - ParseError(pCheck, u, 0, "BUY: Number to buy not given."); - return; - } - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "BUY: Item not given."); - return; - } - int it = ParseGiveableItem(token); - if(it == -1) { - if(*token == "peasant" || *token == "peasants" || *token == "peas") { - if(pCheck) { - it = -1; - for(int i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(ItemDefs[i].type & IT_LEADER) continue; - if(ItemDefs[i].type & IT_MAN) { - it = i; - break; - } - } - } else { - it = u->object->region->race; - } - } - } - delete token; - if (it == -1) { - ParseError(pCheck, u, 0, "BUY: Can't buy that."); - return; - } - if(ItemDefs[it].flags & ItemType::DISABLED) { - ParseError(pCheck, u, 0, "BUY: Can't buy that."); - return; - } - - if(!pCheck) { - BuyOrder *ord = new BuyOrder; - ord->item = it; - ord->num = num; - ord->quiet = isquiet; - u->buyorders.Add(ord); - } -} - -void Game::ProcessProduceOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "PRODUCE: No item given."); - return; - } - int it = ParseEnabledItem(token); - delete token; - - if (it == -1) { - ParseError(pCheck, u, 0, "PRODUCE: Can't produce that."); - return; - } - if(ItemDefs[it].flags & ItemType::DISABLED) { - ParseError(pCheck, u, 0, "PRODUCE: Can't produce that."); - return; - } - - ProduceOrder *ord = new ProduceOrder; - ord->item = it; - ord->quiet = isquiet; - AString skname = ItemDefs[it].pSkill; - ord->skill = LookupSkill(&skname); - if (u->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - if (u->monthorders) delete u->monthorders; - AString err = "PRODUCE: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - u->monthorders = ord; -} - -void Game::ProcessWorkOrder(Unit *u, OrdersCheck *pCheck, int isquiet) -{ - ProduceOrder *ord = new ProduceOrder; - ord->skill = -1; - ord->item = I_SILVER; - ord->quiet = isquiet; - if (u->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - if (u->monthorders) delete u->monthorders; - AString err = "WORK: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - u->monthorders = ord; -} - -void Game::ProcessTeachOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - TeachOrder *ord = 0; - - if (u->monthorders && u->monthorders->type == O_TEACH) { - ord = (TeachOrder *) u->monthorders; - } else { - ord = new TeachOrder; - ord->quiet = 1; - } - - if(!isquiet) ord->quiet = 0; - - int students = 0; - UnitId *id = ParseUnit(o); - while (id && id->unitnum != -1) { - students++; - if(ord) { - ord->targets.Add(id); - } - id = ParseUnit(o); - } - - if (!students) { - ParseError(pCheck, u, 0, "TEACH: No students given."); - return; - } - - if ((u->monthorders && u->monthorders->type != O_TEACH) || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - if (u->monthorders) delete u->monthorders; - AString err = "TEACH: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - u->monthorders = ord; -} - -void Game::ProcessStudyOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "STUDY: No skill given."); - return; - } - int sk = ParseSkill(token); - delete token; - if (sk==-1) { - ParseError(pCheck, u, 0, "STUDY: Invalid skill."); - return; - } - - if(SkillDefs[sk].flags & SkillType::DISABLED) { - ParseError(pCheck, u, 0, "STUDY: Invalid skill."); - return; - } - - if((SkillDefs[sk].flags & SkillType::APPRENTICE) && - !Globals->APPRENTICES_EXIST) { - ParseError(pCheck, u, 0, "STUDY: Invalid skill."); - return; - } - - StudyOrder *ord = new StudyOrder; - ord->skill = sk; - ord->days = 0; - ord->quiet = isquiet; - - token = o->gettoken(); //STUDY order mod start - if(token) { - ord->level = token->value(); - delete token; - } else ord->level = 0; //STUDY order mod end - - if(pCheck || u->IsMage() && Globals->ARCADIA_MAGIC) { - if(u->herostudyorders) { - delete u->herostudyorders; - AString err = "STUDY: Overwriting previous "; - err += "study order."; - if(!u->inTurnBlock) ParseError(pCheck, u, 0, err); //if in turn block, don't worry about the error for now. Saves making new variables for unit. - } - u->herostudyorders = ord; - return; - } - - //not a pCheck or a mage - if (u->monthorders || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - if (u->monthorders) delete u->monthorders; - AString err = "STUDY: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - u->monthorders = ord; -} - -void Game::ProcessDeclareOrder(Faction *f, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, 0, f, "DECLARE: No faction given."); - return; - } - int fac; - if (*token == "default") { - fac = -1; - } else { - fac = token->value(); - } - delete token; - - if(!pCheck) { - Faction *target; - if (fac != -1) { - target = GetFaction(&factions, fac); - if (!target) { - if(!isquiet) f->Error(AString("DECLARE: Non-existent faction ")+fac+"."); - return; - } - if (target == f) { - if(!isquiet) f->Error(AString("DECLARE: Can't declare towards your own " - "faction.")); - return; - } - } - } - - token = o->gettoken(); - if (!token) { - if (fac != -1) { - if(!pCheck) { - f->SetAttitude(fac, -1); - } - } - return; - } - - int att = ParseAttitude(token); - delete token; - if (att == -1) { - ParseError(pCheck, 0, f, "DECLARE: Invalid attitude."); - return; - } - - if(!pCheck) { - if (fac == -1) { - f->defaultattitude = att; - } else { - f->SetAttitude(fac, att); - } - } -} - -void Game::ProcessWithdrawOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - if(!(Globals->ALLOW_WITHDRAW)) { - ParseError(pCheck, unit, 0, "WITHDRAW is not a valid order."); - return; - } - - AString *token = o->gettoken(); - if(!token) { - ParseError (pCheck, unit, 0, "WITHDRAW: No amount given."); - return; - } - int amt = token->value(); - if(amt < 1) { - amt = 1; - } else { - delete token; - token = o->gettoken(); - if(!token) { - ParseError(pCheck, unit, 0, "WITHDRAW: No item given."); - return; - } - } - int item = ParseGiveableItem(token); - delete token; - - if (item == -1) { - ParseError(pCheck, unit, 0, "WITHDRAW: Invalid item."); - return; - } - if (ItemDefs[item].flags & ItemType::DISABLED) { - ParseError(pCheck, unit, 0, "WITHDRAW: Invalid item."); - return; - } - if (!(ItemDefs[item].type & IT_NORMAL)) { - ParseError(pCheck, unit, 0, "WITHDRAW: Invalid item."); - return; - } - if(item == I_SILVER) { - ParseError(pCheck, unit, 0, "WITHDRAW: Invalid item."); - return; - } - - if(!pCheck) { - WithdrawOrder *ord = new WithdrawOrder; - ord->item = item; - ord->amount = amt; - ord->quiet = isquiet; - unit->withdraworders.Add(ord); - } - return; -} - -void Game::ProcessMasterOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - //MASTER not enabled for Xanaxor - ParseError(pCheck, unit, 0, "MASTER is not a valid order."); - -/* - if(!(Globals->ARCADIA_MAGIC)) { - ParseError(pCheck, unit, 0, "MASTER is not a valid order."); - return; - } - - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "MASTER: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, unit, 0, "MASTER: Invalid value."); - return; - } - - if(!pCheck) { - if( val == 0 ) unit->mastery = 0; - else { - if ((unit->monthorders && unit->monthorders->type != O_MASTER) || //check other monthlong orders delete MASTER orders - (Globals->TAX_PILLAGE_MONTH_LONG && - ((unit->taxing == TAX_TAX) || (unit->taxing == TAX_PILLAGE)))) { - AString err = "MASTER: Overwriting previous "; - if (unit->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, unit, 0, err); - if (unit->monthorders) delete unit->monthorders; - unit->monthorders = 0; - } - if(Globals->TAX_PILLAGE_MONTH_LONG) unit->taxing = TAX_NONE; - unit->monthorders = new MasterOrder; - unit->monthorders->quiet = isquiet; - } - } -*/ - return; -} - -void Game::ProcessWishdrawOrder(Unit *unit, AString *o, OrdersCheck *pCheck) -{ - if(!(Globals->TESTGAME_ENABLED) && (pCheck || !unit->faction->IsNPC() ) ) { - ParseError(pCheck, unit, 0, "WISHDRAW is not a valid order."); - return; - } - - AString *token = o->gettoken(); - if(!token) { - ParseError (pCheck, unit, 0, "WISHDRAW: No amount given."); - return; - } - int amt = token->value(); - if(amt < 1) { - amt = 1; - } else { - delete token; - token = o->gettoken(); - if(!token) { - ParseError(pCheck, unit, 0, "WISHDRAW: No item given."); - return; - } - } - int item = ParseGiveableItem(token); - delete token; - - if (item == -1) { - ParseError(pCheck, unit, 0, "WISHDRAW: Invalid item."); - return; - } - if (ItemDefs[item].flags & ItemType::DISABLED) { - ParseError(pCheck, unit, 0, "WISHDRAW: Invalid item."); - return; - } - - if(!pCheck) { - WishdrawOrder *order = new WishdrawOrder; - order->item = item; - order->amount = amt; - unit->wishdraworders.Add(order); - } - return; -} - -void Game::ProcessWishskillOrder(Unit *unit, AString *o, OrdersCheck *pCheck) -{ - if(!(Globals->TESTGAME_ENABLED) && (pCheck || !unit->faction->IsNPC() ) ) { - ParseError(pCheck, unit, 0, "WISHSKILL is not a valid order."); - return; - } - - AString *token = o->gettoken(); - if(!token) { - ParseError (pCheck, unit, 0, "WISHSKILL: No skill given."); - return; - } - - int sk = ParseSkill(token); - delete token; - if (sk==-1) { - ParseError(pCheck, unit, 0, "WISHSKILL: Invalid skill."); - return; - } - - if(SkillDefs[sk].flags & SkillType::DISABLED) { - ParseError(pCheck, unit, 0, "WISHSKILL: Invalid skill."); - return; - } - - if((SkillDefs[sk].flags & SkillType::APPRENTICE) && - !Globals->APPRENTICES_EXIST) { - ParseError(pCheck, unit, 0, "WISHSKILL: Invalid skill."); - return; - } - - token = o->gettoken(); - if(!token) { - ParseError(pCheck, unit, 0, "WISHSKILL: No knowledge level given."); - return; - } - int days = token->value(); - delete token; - - if(days < 0) days = 0; - - token = o->gettoken(); - if(!token) { - ParseError(pCheck, unit, 0, "WISHSKILL: No experience level given."); - return; - } - int exper = token->value(); - delete token; - - if(exper < 0) exper = 0; - - if(!pCheck) { - WishskillOrder *order = new WishskillOrder; - order->skill = sk; - order->knowledge = days; - order->experience = exper; - unit->wishskillorders.Add(order); - } - return; -} - -AString *Game::ProcessTurnOrder(Unit *unit, Aorders *f, OrdersCheck *pCheck, - int repeat, int &formline, FormTemplate *formtem) -{ - int turnDepth = 1; - int turnLast = 1; - int formDepth = 0; - TurnOrder *tOrder = new TurnOrder; - tOrder->repeating = repeat; - - AString *order, *token; - int atsign; - - while (turnDepth) { - // get the next line - if(f) order = f->GetLine(); - else { - order = formtem->GetLine(formline++); //todo!!!! - if(!order) { - ParseError(pCheck, unit, 0, "TURN: without ENDTURN."); - return 0; - } - } - - if (!order) { - // Fake end of commands to invoke appropriate processing - order = new AString("#end"); - } - AString saveorder = *order; - atsign = order->getat(); - token = order->gettoken(); - - if (token) { - int i = Parse1Order(token); - switch (i) { - case O_TURN: - if (turnLast) { - ParseError(pCheck, unit, 0, "TURN: cannot nest."); - break; - } - turnDepth++; - tOrder->turnOrders.Add(new AString(saveorder)); - turnLast = 1; - break; - case O_FORM: - if (!turnLast) { - ParseError(pCheck, unit, 0, "FORM: cannot nest."); - break; - } - turnLast = 0; - formDepth++; - tOrder->turnOrders.Add(new AString(saveorder)); - break; - case O_ENDFORM: - if (turnLast) { - if (!(formDepth + (unit->former != 0))) { - ParseError(pCheck, unit, 0, "END: without FORM."); - break; - } else { - ParseError(pCheck, unit, 0, "TURN: without ENDTURN."); - if (!--turnDepth) { - unit->turnorders.Add(tOrder); - return new AString(saveorder); - } - } - } - formDepth--; - tOrder->turnOrders.Add(new AString(saveorder)); - turnLast = 1; - break; - case O_UNIT: - case O_END: - case O_TEMPLATE: - case O_ALL: - if (!turnLast) - ParseError(pCheck, unit, 0, "FORM: without END."); - while (--turnDepth) { - ParseError(pCheck, unit, 0, "TURN: without ENDTURN."); - ParseError(pCheck, unit, 0, "FORM: without END."); - } - ParseError(pCheck, unit, 0, "TURN: without ENDTURN."); - unit->turnorders.Add(tOrder); - return new AString(saveorder); - break; - case O_ENDTURN: - if (!turnLast) { - ParseError(pCheck, unit, 0, "ENDTURN: without TURN."); - } else { - if (--turnDepth) - tOrder->turnOrders.Add(new AString(saveorder)); - turnLast = 0; - } - break; - default: - tOrder->turnOrders.Add(new AString(saveorder)); - break; - } - delete token; - } - delete order; - } - - unit->turnorders.Add(tOrder); - - return NULL; -} - -AString *Game::ProcessTemplateOrder(Aorders *f, OrdersCheck *pCheck, AString *name, Faction *fac) -{ - FormTemplate *unittype = 0; - AString *temname = name->gettoken(); - if(!temname) { - temname = new AString("default"); - } - - forlist(&fac->formtemplates) { - FormTemplate *formtem = (FormTemplate *) elem; - if(*formtem->name == *temname) { - unittype = formtem; - unittype->orders.DeleteAll(); - } - } - - if(!unittype) { - unittype = new FormTemplate; - unittype->name = temname; - fac->formtemplates.Add(unittype); - } else delete temname; - - AString *order, *token; - - int exitafterone = 0; - - while (1) { - // get the next line - order = f->GetLine(); - if (!order) { - // Fake end of commands to invoke appropriate processing - order = new AString("#end"); - } - - if(exitafterone) return order; - - AString saveorder = *order; - token = order->gettoken(); - - if (token) { - int i = Parse1Order(token); - switch (i) { - case O_UNIT: - case O_END: - case O_TEMPLATE: - case O_ALL: - return new AString(saveorder); - break; - case O_ENDTEMPLATE: - exitafterone = 1; - break; - default: - unittype->orders.Add(new AString(saveorder)); - break; - } - delete token; - } - - if(pCheck) { - pCheck->pCheckFile->PutStr(saveorder); - } - - delete order; - } - - return NULL; -} - -AString *Game::ProcessAllOrder(Aorders *f, OrdersCheck *pCheck, AString *name, Faction *fac) -{ - FormTemplate *labelorders = 0; - AString *temname = name->gettoken(); - if(!temname) { - ParseError(pCheck, 0, 0, "ALL: No label specified."); - return NULL; - } - - forlist(&fac->labeltemplates) { - FormTemplate *formtem = (FormTemplate *) elem; - if(*formtem->name == *temname) { - labelorders = formtem; //add on to earlier all order. - } - } - - if(!labelorders) { - labelorders = new FormTemplate; - labelorders->name = temname; - fac->labeltemplates.Add(labelorders); - } else delete temname; - - AString *order, *token; - - int exitafterone = 0; - - while (1) { - - // get the next line - order = f->GetLine(); - if (!order) { - // Fake end of commands to invoke appropriate processing - order = new AString("#end"); - } - - if(exitafterone) return order; - - AString saveorder = *order; - - token = order->gettoken(); - - if (token) { - int i = Parse1Order(token); - switch (i) { - case O_UNIT: - case O_END: - case O_TEMPLATE: - case O_ALL: - return new AString(saveorder); - break; - case O_ENDALL: - exitafterone = 1; - break; - default: - labelorders->orders.Add(new AString(saveorder)); - break; - } - delete token; - } - - if(pCheck) { - pCheck->pCheckFile->PutStr(saveorder); - } - - delete order; - } - - return NULL; -} - -void Game::ProcessExchangeOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *t = ParseUnit(o); - if (!t) { - ParseError(pCheck, unit, 0, "EXCHANGE: Invalid target."); - return; - } - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "EXCHANGE: No amount given."); - return; - } - int amtGive; - amtGive = token->value(); - delete token; - - if(amtGive < 0) { - ParseError(pCheck, unit, 0, "EXCHANGE: Illegal amount given."); - return; - } - - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "EXCHANGE: No item given."); - return; - } - int itemGive; - itemGive = ParseGiveableItem(token); - delete token; - - if(itemGive == -1) { - ParseError(pCheck, unit, 0, "EXCHANGE: Invalid item."); - return; - } - - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "EXCHANGE: No amount expected."); - return; - } - int amtExpected; - amtExpected = token->value(); - delete token; - - if(amtExpected < 0) { - ParseError(pCheck, unit, 0, "EXCHANGE: Illegal amount given."); - return; - } - - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "EXCHANGE: No item expected."); - return; - } - int itemExpected; - itemExpected = ParseGiveableItem(token); - delete token; - - if(itemExpected == -1) { - ParseError(pCheck, unit, 0, "EXCHANGE: Invalid item."); - return; - } - - if(!pCheck) { - ExchangeOrder *ord = new ExchangeOrder; - ord->giveItem = itemGive; - ord->giveAmount = amtGive; - ord->expectAmount = amtExpected; - ord->expectItem = itemExpected; - ord->target = t; - ord->quiet = isquiet; - unit->exchangeorders.Add(ord); - } -} - -void Game::ProcessGiveOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *t = ParseUnit(o); - if (!t) { - ParseError(pCheck, unit, 0, "GIVE: Invalid target."); - return; - } - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "GIVE: No amount given."); - return; - } - int amt; - if (*token == "unit") { - amt = -1; - } else if(*token == "all") { - amt = -2; - } else { - amt = token->value(); - } - delete token; - int item = -1; - if (amt != -1) { - token = o->gettoken(); - if(token) { - if (t->unitnum == -1) - item = ParseEnabledItem(token); - else - item = ParseGiveableItem(token); - if(amt == -2) { - int found = 0; - if(*token == "normal") { - item = -IT_NORMAL; - found = 1; - } else if(*token == "advanced") { - item = -IT_ADVANCED; - found = 1; - } else if(*token == "trade") { - item = -IT_TRADE; - found = 1; - } else if((*token == "man") || (*token == "men")) { - item = -IT_MAN; - found = 1; - } else if((*token == "monster") || (*token == "monsters")) { - item = -IT_MONSTER; - found = 1; - } else if(*token == "magic") { - item = -IT_MAGIC; - found = 1; - } else if((*token == "weapon") || (*token == "weapons")) { - item = -IT_WEAPON; - found = 1; - } else if(*token == "armour") { - item = -IT_ARMOR; - found = 1; - } else if((*token == "mount") || (*token == "mounts")) { - item = -IT_MOUNT; - found = 1; - } else if(*token == "battle") { - item = -IT_BATTLE; - found = 1; - } else if(*token == "special") { - item = -IT_SPECIAL; - found = 1; - } else if(*token == "food") { - item = -IT_FOOD; - found = 1; - } else if((*token == "tool") || (*token == "tools")) { - item = -IT_TOOL; - found = 1; - } else if((*token == "item") || (*token == "items")) { - item = -NITEMS; - found = 1; - } else if(item != -1) { - found = 1; - } - if(!found) { - ParseError(pCheck, unit, 0, - "GIVE: Invalid item or item class."); - return; - } - } else if(item == -1) { - ParseError(pCheck, unit, 0, "GIVE: Invalid item."); - return; - } - } else { - ParseError(pCheck, unit, 0, "GIVE: No item given."); - return; - } - delete token; - } - - token = o->gettoken(); - int excpt = 0; - if(token && *token == "except") { - if(amt == -2) { - delete token; - if(item < 0) { - ParseError(pCheck, unit, 0, - "GIVE: EXCEPT only valid with specific items."); - return; - } - token = o->gettoken(); - if(!token) { - ParseError(pCheck, unit, 0, "GIVE: EXCEPT requires a value."); - return; - } - excpt = token->value(); - if(excpt <= 0) { - ParseError(pCheck, unit, 0, "GIVE: Invalid EXCEPT value."); - return; - } - } else { - ParseError(pCheck, unit, 0, "GIVE: EXCEPT only valid with ALL"); - return; - } - delete token; - } - - if(!pCheck) { - GiveOrder *ord = new GiveOrder; - ord->item = item; - ord->target = t; - ord->amount = amt; - ord->except = excpt; - ord->quiet = isquiet; - unit->giveorders.Add(ord); - } - return; -} - - -void Game::ProcessSendOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - if(Globals->SEND_COST < 0) { - ParseError(pCheck, unit, 0, "SEND is not a valid order."); - return; - } - - AString *token = o->gettoken(); - int dir = -1; - if(token && (*token == "direction" || *token == "dir")) { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "SEND: No direction specified."); - return; - } - dir = ParseDir(token); - delete token; - if(dir < 0) { - ParseError(pCheck, unit, 0, "SEND: Invalid direction specified."); - return; - } - token = o->gettoken(); - } - - UnitId *tar = NULL; - UnitId *via = NULL; - - if(token && *token == "unit") { - delete token; - tar = ParseUnit(o); - if (!tar) { - ParseError(pCheck, unit, 0, "SEND: Invalid target."); - return; - } - token = o->gettoken(); - } - - if(dir == -1 && tar == NULL) { - if(token) delete token; - ParseError(pCheck, unit, 0, "SEND: Must specify direction and/or unit number."); - return; - } - - if(token && *token == "via") { - delete token; - via = ParseUnit(o); - if (!tar) { - ParseError(pCheck, unit, 0, "SEND: Invalid quartermaster."); - } - token = o->gettoken(); - } - - if (!token) { - ParseError(pCheck, unit, 0, "SEND: No amount given."); - return; - } - - int amt; - if (*token == "all") { - amt = -2; - } else { - amt = token->value(); - } - delete token; - int item = -1; - - token = o->gettoken(); - if(token) { - item = ParseGiveableItem(token); - if(amt == -2) { - int found = 0; - if(*token == "normal") { - item = -IT_NORMAL; - found = 1; - } else if(*token == "advanced") { - item = -IT_ADVANCED; - found = 1; - } else if(*token == "trade") { - item = -IT_TRADE; - found = 1; - //men and monsters cannot be SENT - } else if(*token == "magic") { - item = -IT_MAGIC; - found = 1; - } else if((*token == "weapon") || (*token == "weapons")) { - item = -IT_WEAPON; - found = 1; - } else if(*token == "armour") { - item = -IT_ARMOR; - found = 1; - } else if((*token == "mount") || (*token == "mounts")) { - item = -IT_MOUNT; - found = 1; - } else if(*token == "battle") { - item = -IT_BATTLE; - found = 1; - } else if(*token == "special") { - item = -IT_SPECIAL; - found = 1; - } else if(*token == "food") { - item = -IT_FOOD; - found = 1; - } else if((*token == "tool") || (*token == "tools")) { - item = -IT_TOOL; - found = 1; - } else if((*token == "item") || (*token == "items")) { - item = -NITEMS; - found = 1; - } else if(item != -1) { - found = 1; - } - if(!found) { - ParseError(pCheck, unit, 0, - "SEND: Invalid item or item class."); - return; - } - } else if(item == -1) { - ParseError(pCheck, unit, 0, "SEND: Invalid item."); - return; - } - } else { - ParseError(pCheck, unit, 0, "SEND: No item given."); - return; - } - delete token; - - if(item >= 0 && ((ItemDefs[item].type & IT_MAN) || - (ItemDefs[item].type & IT_MONSTER) || (ItemDefs[item].type & IT_ILLUSION))) { - ParseError(pCheck, unit, 0, "SEND: Invalid item."); - } - - token = o->gettoken(); - int excpt = 0; - if(token && *token == "except") { - delete token; - if(amt == -2) { - if(item < 0) { - ParseError(pCheck, unit, 0, - "SEND: EXCEPT only valid with specific items."); - return; - } - token = o->gettoken(); - if(!token) { - ParseError(pCheck, unit, 0, "SEND: EXCEPT requires a value."); - return; - } - excpt = token->value(); - if(excpt <= 0) { - ParseError(pCheck, unit, 0, "SEND: Invalid EXCEPT value."); - return; - } - } else { - ParseError(pCheck, unit, 0, "SEND: EXCEPT only valid with ALL"); - return; - } - } - - if(!pCheck) { - SendOrder *ord = new SendOrder; - ord->item = item; - ord->target = tar; - ord->via = via; - ord->amount = amt; - ord->except = excpt; - ord->direction = dir; - ord->quiet = isquiet; - unit->sendorders.Add(ord); - } - return; -} - - -void Game::ProcessDescribeOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "DESCRIBE: No argument."); - return; - } - if (*token == "unit") { - delete token; - token = o->gettoken(); - if(!pCheck) { - unit->SetDescribe(token); - } - return; - } - if (*token == "ship" || *token == "building" || *token == "object" || - *token == "structure") { - delete token; - token = o->gettoken(); - if(!pCheck) { - // ALT, 25-Jul-2000 - // Fix to prevent non-owner units from describing objects - if(unit != unit->object->GetOwner()) { - if(!isquiet) unit->Error("DESCRIBE: Unit is not owner."); - return; - } - unit->object->SetDescribe(token); - } - return; - } - ParseError(pCheck, unit, 0, "DESCRIBE: Can't describe that."); -} - -void Game::ProcessLabelOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if(!pCheck) { - unit->SetLabel(token); - } -} - -void Game::ProcessNameOrder(Unit *unit, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "NAME: No argument."); - return; - } - if (*token == "faction") { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "NAME: No name given."); - return; - } - if(!pCheck) { - unit->faction->SetName(token); - } - return; - } - - if (*token == "unit") { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "NAME: No name given."); - return; - } - if(!pCheck) { - unit->SetName(token); - } - return; - } - - if (*token == "building" || *token == "ship" || *token == "object" || - *token == "structure") { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, unit, 0, "NAME: No name given."); - return; - } - if(!pCheck) { - // ALT, 25-Jul-2000 - // Fix to prevent non-owner units from renaming objects - if(unit != unit->object->GetOwner()) { - if(!isquiet) unit->Error("NAME: Unit is not owner."); - return; - } - unit->object->SetName(token); - } - return; - } - - // ALT, 26-Jul-2000 - // Allow some units to rename cities. Unit must be at least the owner - // of tower to rename village, fort to rename town and castle to - // rename city. - if (*token == "village" || *token == "town" || *token == "city") { - delete token; - token = o->gettoken(); - - if (!token) { - ParseError(pCheck, unit, 0, "NAME: No name given."); - return; - } - - if (!pCheck) { - if(!unit->object) { - if(!isquiet) unit->Error("NAME: Unit is not in a structure."); - return; - } - if(!unit->object->region->town) { - if(!isquiet) unit->Error("NAME: Unit is not in a village, town or city."); - return; - } - int cost = 0; - int towntype = unit->object->region->town->TownType(); - AString tstring; - switch(towntype) { - case TOWN_VILLAGE: - tstring = "village"; - break; - case TOWN_TOWN: - tstring = "town"; - break; - case TOWN_CITY: - tstring = "city"; - break; - } - if(Globals->CITY_RENAME_COST) { - cost = (towntype+1)* Globals->CITY_RENAME_COST; - } - int ok = 0; - switch(towntype) { - case TOWN_VILLAGE: - if(unit->object->type == O_TOWER) ok = 1; - case TOWN_TOWN: - if(unit->object->type == O_FORT) ok = 1; - case TOWN_CITY: - if(unit->object->type == O_CASTLE) ok = 1; - if(unit->object->type == O_CITADEL) ok = 1; - if(unit->object->type == O_MFORTRESS) ok = 1; - } - if(!ok) { - if(!isquiet) unit->Error(AString("NAME: Unit is not in a large ")+ - "enough structure to rename a "+tstring+"."); - return; - } - if (unit != unit->object->GetOwner()) { - if(!isquiet) unit->Error(AString("NAME: Cannot name ")+tstring+ - ". Unit is not the owner of object."); - return; - } - if (unit->object->incomplete > 0) { - if(!isquiet) unit->Error(AString("NAME: Cannot name ")+tstring+ - ". Object is not finished."); - return; - } - - AString *newname = token->getlegal(); - if (!newname) { - if(!isquiet) unit->Error("NAME: Illegal name."); - return; - } - if(cost) { - int silver = unit->items.GetNum(I_SILVER); - if(silver < cost) { - if(!isquiet) unit->Error(AString("NAME: Unit doesn't have enough ")+ - "silver to rename a "+tstring+"."); - return; - } - unit->items.SetNum(I_SILVER, silver-cost); - } - - unit->Event(AString("Renames ") + - *(unit->object->region->town->name) + " to " + - *newname + "."); - unit->object->region->NotifyCity(unit, - *(unit->object->region->town->name), *newname); - delete unit->object->region->town->name; - unit->object->region->town->name = newname; - } - return; - } - - delete token; - ParseError(pCheck, unit, 0, "NAME: Can't name that."); -} - -void Game::ProcessGuardOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - /* This is an instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "GUARD: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "GUARD: Invalid value."); - return; - } - if(!pCheck) { - if (val==0) { - if (u->guard != GUARD_AVOID) - u->guard = GUARD_NONE; - } else { - u->guard = GUARD_SET; - } - } -} - -void Game::ProcessBehindOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* This is an instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "BEHIND: Invalid value."); - return; - } - int val = ParseTF(token); - if (val == -1) { - ParseError(pCheck, u, 0, "BEHIND: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_BEHIND, val); - } -} - -void Game::ProcessFightAsOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* Instant order */ - AString *token = o->gettoken(); - int flag = 0; - int val = 1; - if(token) { - if(*token == "foot") flag = FLAG_FIGHTASFOOT; - else if(*token == "ride") flag = FLAG_FIGHTASRIDE; - else if(*token == "fly") val = 0; //No need for this? - else ParseError(pCheck, u, 0, "FIGHT: Bad argument."); - delete token; - } - - if(!pCheck) { - /* Clear all the flags */ - u->SetFlag(FLAG_FIGHTASFOOT, 0); - u->SetFlag(FLAG_FIGHTASRIDE, 0); - - /* Set the flag we're trying to set */ - if(flag) { - u->SetFlag(flag, val); - } - } -} - -void Game::ProcessTacticsOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ -//instant order - if(!pCheck) { - AString *token = o->gettoken(); - if (token) { - if (*token == "aggressive") { - u->tactics = TACTICS_AGGRESSIVE; - delete token; - return; - } - if (*token == "defensive") { - delete token; - u->tactics = TACTICS_DEFENSIVE; - return; - } - if (*token == "none") { - delete token; - u->tactics = TACTICS_NONE; - return; - } - } else { - u->tactics = TACTICS_NONE; - } - } -} - - -void Game::ProcessNoaidOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - // Instant order - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "NOAID: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "NOAID: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_NOAID, val); - } -} - -void Game::ProcessDisableOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "DISABLE: No skill given."); - return; - } - int sk = ParseSkill(token); - delete token; - if (sk==-1) { - ParseError(pCheck, u, 0, "DISABLE: Invalid skill."); - return; - } - - if(SkillDefs[sk].flags & SkillType::DISABLED) { - ParseError(pCheck, u, 0, "DISABLE: Invalid skill."); - return; - } - - // Instant order - token = o->gettoken(); - int val = 1; - - if (token) { - val = ParseTF(token); - delete token; - } - - if (val==-1) { - ParseError(pCheck, u, 0, "DISABLE: Invalid value."); - return; - } - if(!pCheck) { - if(!u->skills.SetDisabled(sk, val) && !isquiet) { //val of 1 means skill is disabled. - u->Error("DISABLE: Does not know that skill"); - } - if(u->combat == sk) { - u->combat = -1; - u->Event("Combat spell set to none."); - } - } -} - -void Game::ProcessSpoilsOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* Instant order */ - AString *token = o->gettoken(); - int flag = 0; - int val = 1; - if(token) { - if(*token == "none") flag = FLAG_NOSPOILS; - else if(*token == "walk") flag = FLAG_WALKSPOILS; - else if(*token == "ride") flag = FLAG_RIDESPOILS; - else if(*token == "fly") flag = FLAG_FLYSPOILS; - else if(*token == "swim") flag = FLAG_SWIMSPOILS; - else if(*token == "sail") flag = FLAG_SAILSPOILS; - else if(*token == "all") val = 0; - else ParseError(pCheck, u, 0, "SPOILS: Bad argument."); - delete token; - } - - if(!pCheck) { - /* Clear all the flags */ - u->SetFlag(FLAG_NOSPOILS, 0); - u->SetFlag(FLAG_WALKSPOILS, 0); - u->SetFlag(FLAG_RIDESPOILS, 0); - u->SetFlag(FLAG_FLYSPOILS, 0); - u->SetFlag(FLAG_SWIMSPOILS, 0); - u->SetFlag(FLAG_SAILSPOILS, 0); - - /* Set the flag we're trying to set */ - if(flag) { - u->SetFlag(flag, val); - } - } -} - -void Game::ProcessTypeOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* Instant order */ - AString *token = o->gettoken(); - if(!token) token = new AString("default"); - - if(!pCheck) { - forlist(&u->typeorders) { - AString *name = (AString *) elem; - if(*name == *token) { - delete token; - return; - } - } - u->typeorders.Add(token); - } -} - -void Game::ProcessNospoilsOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - ParseError(pCheck, u, 0, "NOSPOILS: This command is deprecated. " - "Use the 'SPOILS' command instead"); - - /* Instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "NOSPOILS: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "NOSPOILS: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_FLYSPOILS, 0); - u->SetFlag(FLAG_RIDESPOILS, 0); - u->SetFlag(FLAG_WALKSPOILS, 0); - u->SetFlag(FLAG_SWIMSPOILS, 0); - u->SetFlag(FLAG_SAILSPOILS, 0); - u->SetFlag(FLAG_NOSPOILS, val); - } -} - -void Game::ProcessNocrossOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - int move_over_water = 0; - - if(Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) - move_over_water = 1; - if(!move_over_water) { - int i; - for(i = 0; i < NITEMS; i++) { - if(ItemDefs[i].flags & ItemType::DISABLED) continue; - if(ItemDefs[i].swim > 0) move_over_water = 1; - } - } - if(!move_over_water) { - ParseError(pCheck, u, 0, "NOCROSS is not a valid order."); - return; - } - - /* Instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "NOCROSS: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "NOCROSS: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_NOCROSS_WATER, val); - } -} - - -void Game::ProcessHoldOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* Instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "HOLD: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "HOLD: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_HOLDING, val); - } -} - -void Game::ProcessAutoTaxOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* Instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "AUTOTAX: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "AUTOTAX: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_AUTOTAX, val); - } -} - -void Game::ProcessAvoidOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* This is an instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "AVOID: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "AVOID: Invalid value."); - return; - } - if(!pCheck) { - if (val==1) { - u->guard = GUARD_AVOID; - } else { - if (u->guard == GUARD_AVOID) { - u->guard = GUARD_NONE; - } - } - } -} - -Unit *Game::ProcessFormOrder(Unit *former, AString *o, OrdersCheck *pCheck, int isquiet) -{ -//modified by BS to allow mistaken form orders - - AString *t = o->gettoken(); - int an = 0; -// int error = 0; - if(t) { - an = t->value(); - delete t; - } - -/* if (!an) { - if(pCheck) { - ParseError(pCheck, former, 0, "No alias in FORM order."); - return 0; - } - }*/ - if(pCheck) { - Unit *retval = new Unit; - retval->former = former; - return retval; - } else { - if(an && former->object->region->GetUnitAlias(an, former->faction->num)) { - if(!isquiet) former->Error("Alias multiply defined."); - an = 0; - } - Unit *temp = GetNewUnit(former->faction, an); - temp->CopyFlags(former); - temp->DefaultOrders(former->object); - temp->MoveUnit(former->object); - temp->former = former; - return temp; - } -} - -void Game::ProcessAddressOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* This is an instant order */ - AString *token = o->gettoken(); - if (token) { - if(!pCheck) { - u->faction->address = token; - } - } else { - ParseError(pCheck, u, 0, "ADDRESS: No address given."); - } -} - -void Game::ProcessFollowOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "FOLLOW: Specify to follow a UNIT or SHIP"); - return; - } - FollowOrder *ord = 0; - if(*token == "OBJECT" || *token == "SHIP") { - delete token; - token = o->gettoken(); - int shipnum = token->value(); - delete token; - if(shipnum < 1) { - ParseError(pCheck, u, 0, "FOLLOW: Invalid ship number."); - return; - } - ord = new FollowOrder; - ord->targetid = 0; - ord->ship = shipnum; - ord->quiet = isquiet; - } else if(*token == "UNIT" || *token == "UNITS") { - delete token; - UnitId *t = ParseUnit(o); - if (!t) { - ParseError(pCheck, u, 0, "FOLLOW: Invalid target."); - return; - } - ord = new FollowOrder; - ord->targetid = t; - ord->ship = 0; - ord->quiet = isquiet; - } else { - delete token; - ParseError(pCheck, u, 0, "FOLLOW: Specify to follow a UNIT or SHIP"); - return; - } - - if (u->monthorders || (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - AString err = "FOLLOW: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long orders"; - ParseError(pCheck, u, 0, err); - if (u->monthorders) delete u->monthorders; - u->monthorders = 0; - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - u->monthorders = ord; -} - -void Game::ProcessAdvanceOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - MoveOrder *m = 0; - - if ((u->monthorders && u->monthorders->type != O_ADVANCE) || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - AString err = "ADVANCE: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long orders"; - ParseError(pCheck, u, 0, err); - if (u->monthorders) delete u->monthorders; - u->monthorders = 0; - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - if (!u->monthorders) { - u->monthorders = new MoveOrder; - u->monthorders->type = O_ADVANCE; - u->monthorders->quiet = isquiet; - } - m = (MoveOrder *) u->monthorders; - m->advancing = 1; - - for (;;) { - AString *t = o->gettoken(); - if (!t) return; - int d = ParseDir(t); - delete t; - if (d!=-1) { - if(!pCheck) { - MoveDir *x = new MoveDir; - x->dir = d; - m->dirs.Add(x); - } - } else { - ParseError(pCheck, u, 0, "ADVANCE: Warning, bad direction."); - return; - } - } -} - -void Game::ProcessMoveOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - MoveOrder *m = 0; - - if ((u->monthorders && u->monthorders->type != O_MOVE) || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - AString err = "MOVE: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - if (u->monthorders) delete u->monthorders; - u->monthorders = 0; - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - if (!u->monthorders) { - u->monthorders = new MoveOrder; - u->monthorders->quiet = isquiet; - } - m = (MoveOrder *) u->monthorders; - m->advancing = 0; - - for (;;) { - AString *t = o->gettoken(); - if (!t) return; - int d = ParseDir(t); - delete t; - if (d!=-1) { - if(!pCheck) { - MoveDir *x = new MoveDir; - x->dir = d; - m->dirs.Add(x); - } - } else { - ParseError(pCheck, u, 0, "MOVE: Warning, bad direction."); - return; - } - } -} - -void Game::ProcessSailOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - SailOrder *ord = 0; - - if ((u->monthorders && u->monthorders->type != O_SAIL) || - (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - AString err = "SAIL: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - if (u->monthorders) delete u->monthorders; - u->monthorders = 0; - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - if (!u->monthorders) { - u->monthorders = new SailOrder; - u->monthorders->quiet = isquiet; - } - ord = (SailOrder *) u->monthorders; - - for (;;) { - AString *t = o->gettoken(); - if (!t) return; - int d = ParseDir(t); - delete t; - if (d == -1) { - ParseError(pCheck, u, 0, "SAIL: Warning, bad direction."); - return; - } else { - if (d < NDIRS) { - if(!pCheck) { - MoveDir *x = new MoveDir; - x->dir = d; - ord->dirs.Add(x); - } - } else { - return; - } - } - } -} - -void Game::ProcessEvictOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - UnitId *id = ParseUnit(o); - while (id && id->unitnum != -1) { - if(!pCheck) { - if (!u->evictorders) u->evictorders = new EvictOrder; - u->evictorders->targets.Add(id); - u->evictorders->quiet = isquiet; - } - id = ParseUnit(o); - } -} - -void Game::ProcessIdleOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - if (u->monthorders || (Globals->TAX_PILLAGE_MONTH_LONG && - ((u->taxing == TAX_TAX) || (u->taxing == TAX_PILLAGE)))) { - if (u->monthorders) delete u->monthorders; - AString err = "IDLE: Overwriting previous "; - if (u->inTurnBlock) err += "DELAYED "; - err += "month-long order."; - ParseError(pCheck, u, 0, err); - } - if(Globals->TAX_PILLAGE_MONTH_LONG) u->taxing = TAX_NONE; - IdleOrder *i = new IdleOrder; - u->monthorders = i; -} - -void Game::ProcessTransportOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - if(!Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - ParseError(pCheck, u, 0, "TRANSPORT: Invalid order."); - return; - } - - UnitId *tar = ParseUnit(o); - if (!tar) { - ParseError(pCheck, u, 0, "TRANSPORT: Invalid target."); - return; - } - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "TRANSPORT: No amount given."); - return; - } - - int amt; - if (*token == "all") - amt = -1; - else - amt = token->value(); - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "TRANSPORT: No item given."); - return; - } - int item = ParseTransportableItem(token); - delete token; - if (item == -1) { - ParseError(pCheck, u, 0, "TRANSPORT: Invalid item."); - return; - } - - int except = 0; - token = o->gettoken(); - if (token && *token == "except") { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "TRANSPORT: EXCEPT requires a value."); - return; - } - except = token->value(); - delete token; - if (except <= 0) { - ParseError(pCheck, u, 0, "TRANSPORT: Invalid except value."); - return; - } - } - - if (!pCheck) { - TransportOrder *ord = new TransportOrder; - ord->item = item; - ord->target = tar; - ord->amount = amt; - ord->except = except; - ord->quiet = isquiet; - u->transportorders.Add(ord); - } - return; -} - -void Game::ProcessDistributeOrder(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - if(!Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - ParseError(pCheck, u, 0, "DISTRIBUTE: Invalid order."); - return; - } - - UnitId *tar = ParseUnit(o); - if (!tar) { - ParseError(pCheck, u, 0, "DISTRIBUTE: Invalid target."); - return; - } - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "DISTRIBUTE: No amount given."); - return; - } - - int amt; - if (*token == "all") - amt = -1; - else - amt = token->value(); - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "DISTRIBUTE: No item given."); - return; - } - int item = ParseTransportableItem(token); - delete token; - if (item == -1) { - ParseError(pCheck, u, 0, "DISTRIBUTE: Invalid item."); - return; - } - - int except = 0; - token = o->gettoken(); - if (token && *token == "except") { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "DISTRIBUTE: EXCEPT requires a value."); - return; - } - except = token->value(); - delete token; - if (except <= 0) { - ParseError(pCheck, u, 0, "DISTRIBUTE: Invalid except value."); - return; - } - } - - if (!pCheck) { - TransportOrder *ord = new TransportOrder; - ord->type = O_DISTRIBUTE; - ord->item = item; - ord->target = tar; - ord->amount = amt; - ord->except = except; - ord->quiet = isquiet; - u->transportorders.Add(ord); - } - return; -} - -void Game::ProcessShareOrder(Unit *u, AString *o, OrdersCheck *pCheck) -{ - /* Instant order */ - AString *token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "SHARE: Invalid value."); - return; - } - int val = ParseTF(token); - delete token; - if (val==-1) { - ParseError(pCheck, u, 0, "SHARE: Invalid value."); - return; - } - if(!pCheck) { - u->SetFlag(FLAG_SHARING, val); - } -} diff --git a/arcadia/production.cpp b/arcadia/production.cpp deleted file mode 100644 index 09184c4d6..000000000 --- a/arcadia/production.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "production.h" -#include "gameio.h" -#include "items.h" -#include "skills.h" -#include "gamedata.h" - -Production::Production() -{ - itemtype = -1; - amount = 0; - baseamount = 0; - productivity = 0; - skill = -1; -} - -Production::Production(int it, int maxamt) -{ - itemtype = it; - amount = maxamt; - if(Globals->RANDOM_ECONOMY) - amount += getrandom(maxamt); - baseamount = amount; - productivity = 1; - AString skname = ItemDefs[it].pSkill; - skill = LookupSkill(&skname); -} - -void Production::Writeout(Aoutfile *f) -{ - if (itemtype != -1) f->PutStr(ItemDefs[itemtype].abr); - else f->PutStr("NO_ITEM"); - f->PutInt(amount); - f->PutInt(baseamount); - if (itemtype == I_SILVER) { - if (skill != -1) f->PutStr(SkillDefs[skill].abbr); - else f->PutStr("NO_SKILL"); - } - f->PutInt(productivity); -} - -void Production::Readin(Ainfile *f) -{ - AString *temp; - - temp = f->GetStr(); - itemtype = LookupItem(temp); - delete temp; - - amount = f->GetInt(); - baseamount = f->GetInt(); - - if (itemtype == I_SILVER) temp = f->GetStr(); - else temp = new AString(ItemDefs[itemtype].pSkill); - skill = LookupSkill(temp); - delete temp; - - productivity = f->GetInt(); -} - -AString Production::WriteReport() -{ - AString temp = ItemString(itemtype, amount); - return temp; -} - -void ProductionList::Writeout(Aoutfile *f) -{ - f->PutInt(Num()); - forlist(this) ((Production *) elem)->Writeout(f); -} - -void ProductionList::Readin(Ainfile *f) -{ - int n = f->GetInt(); - for (int i=0; iReadin(f); - Add(p); - } -} - -Production *ProductionList::GetProd(int t, int s) -{ - forlist(this) { - Production *p = (Production *) elem; - if (p->itemtype == t && p->skill == s) return p; - } - return 0; -} - -void ProductionList::AddProd(Production *p) -{ - Production *p2 = GetProd(p->itemtype, p->skill); - if (p2) { - Remove(p2); - delete p2; - } - - Add(p); -} diff --git a/arcadia/production.h b/arcadia/production.h deleted file mode 100644 index 1c9dbbe1c..000000000 --- a/arcadia/production.h +++ /dev/null @@ -1,61 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef PRODUCTION_CLASS -#define PRODUCTION_CLASS - -#include "gamedefs.h" -#include "alist.h" -#include "fileio.h" - -#define P_BIG 40 -#define P_SMALL 20 - -class Production : public AListElem { -public: - Production(int,int); /* item type, amt max */ - Production(); - - void Writeout(Aoutfile *); - void Readin(Ainfile *); - AString WriteReport(); - - int itemtype; - int baseamount; - int amount; - int skill; - int productivity; - int activity; -}; - -class ProductionList : public AList { -public: - Production * GetProd(int,int); /* item type, skill */ - void AddProd(Production *); - - void Writeout(Aoutfile *); - void Readin(Ainfile *); -}; - -#endif diff --git a/arcadia/rules.cpp b/arcadia/rules.cpp deleted file mode 100644 index 26c31b3a3..000000000 --- a/arcadia/rules.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "gamedata.h" -#include "gamedefs.h" - -// -// Define the various globals for this game. -// -// If you change any of these, it is incumbent on you, the GM to change -// the html file containing the rules to correctly reflect the changes! -// - -static int am[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; -int *allowedMages = am; -int allowedMagesSize = sizeof(am) / sizeof(am[0]); - -static int aa[] = { 0, 2, 4, 6, 10, 14 }; -int *allowedApprentices = aa; -int allowedApprenticesSize = sizeof(aa) / sizeof(aa[0]); - -static int aw[] = { 1, 4, 7, 10, 13, 16, 19, 22, 25 }; -int *allowedTaxes = aw; -int allowedTaxesSize = sizeof(aw) / sizeof(aw[0]); - -static int at[] = { 1, 4, 7, 10, 13, 16, 19, 22, 25 }; -int *allowedTrades = at; -int allowedTradesSize = sizeof(at) / sizeof(at[0]); - -static int aq[] = { 0, 2, 4, 8, 12, 20 }; -int *allowedQuartermasters = aq; -int allowedQuartermastersSize = sizeof(aq) / sizeof(aq[0]); - -// at is already taken up for allowedtaxes, so I'll use ag (allowedgenghises) ;) -static int ag[] = { 0, 1, 2, 4, 6, 10 }; -int *allowedTacticians = ag; -int allowedTacticiansSize = sizeof(ag) / sizeof(ag[0]); - -static GameDefs g = { - "Xanaxor", // RULESET_NAME - MAKE_ATL_VER( 4, 0, 0 ), // RULESET_VERSION - - 2, /* FOOT_SPEED */ - 4, /* HORSE_SPEED */ - 8, /* SHIP_SPEED */ //This is no longer used! - 6, /* FLY_SPEED */ - 16, /* MAX_SPEED */ - - // BOOST settings do not exist in GameDefs - // 2, /* FLEET_WIND_BOOST */ - // 0, /* FLEET_CREW_BOOST */ - // 0, /* FLEET_LOAD_BOOST */ - - 10, /* STUDENTS_PER_TEACHER */ - 10, /* MAINTENANCE_COST */ - 20, /* LEADER_COST */ - - 0, /* MAINTAINENCE_MULTIPLIER */ - GameDefs::MULT_NONE, /* MULTIPLIER_USE */ - - 33, /* STARVE_PERCENT */ - GameDefs::STARVE_LEADERS, /* SKILL_STARVATION */ - - 9100, /* START_MONEY */ - 4, /* WORK_FRACTION */ - 20, /* ENTERTAIN_FRACTION */ - 20, /* ENTERTAIN_INCOME */ - - 50, /* TAX_BASE_INCOME */ - 0, /* TAX_BONUS_WEAPON */ - 0, /* TAX_BONUS_ARMOR */ - 0, /* TAX_BONUS_FORT */ - GameDefs::TAX_NORMAL | GameDefs::TAX_HORSE_AND_RIDING_SKILL_AND_MELEE_WEAPON, // WHO_CAN_TAX - 1, // TAX_PILLAGE_MONTH_LONG - - 5, /* HEALS_PER_MAN */ - - 60, /* GUARD_REGEN */ /* percent */ - 20, /* CITY_GUARD */ - 1, /* GUARD_DEPENDS_ON_TAX */ - 50, /* GUARD_MONEY */ - 4000, /* CITY_POP */ - - 35, /* WMON_FREQUENCY */ - 17, /* LAIR_FREQUENCY */ - - 8, /* FACTION_POINTS */ - - 100, /* TIMES_REWARD */ - - 0, // SEPERATE_TEMPLATES - - 1, // TOWNS_EXIST - 0, // LEADERS_EXIST - 1, // SKILL_LIMIT_NONLEADERS - 1, // MAGE_NONLEADERS - 1, // RACES_EXIST - 1, // GATES_EXIST - 1, // FOOD_ITEMS_EXIST - 0, // COASTAL_FISH - 1, // CITY_MONSTERS_EXIST - 1, // WANDERING_MONSTERS_EXIST - 1, // LAIR_MONSTERS_EXIST - 1, // WEATHER_EXISTS - 0, // OPEN_ENDED - 1, // NEXUS_EXISTS - 0, // CONQUEST_GAME - - 1, // RANDOM_ECONOMY - 1, // VARIABLE_ECONOMY - - 50, // CITY_MARKET_NORMAL_AMT - 20, // CITY_MARKET_ADVANCED_AMT - 60, // CITY_MARKET_TRADE_AMT - 20, // CITY_MARKET_MAGIC_AMT - 1, // MORE_PROFITABLE_TRADE_GOODS - - 50, // BASE_MAN_COST - 0, // LASTORDERS_MAINTAINED_BY_SCRIPTS - 6, // MAX_INACTIVE_TURNS - - 0, // EASIER_UNDERWORLD - - 1, // DEFAULT_WORK_ORDER - - GameDefs::FACLIM_FACTION_TYPES, // FACTION_LIMIT_TYPE - - GameDefs::WFLIGHT_NONE, // FLIGHT_OVER_WATER - - 1, // START_CITIES_EXIST - 0, // SAFE_START_CITIES - 50, // AMT_START_CITY_GUARDS - 0, // START_CITY_GUARDS_PLATE - 3, // START_CITY_MAGES - 0, // START_CITY_TACTICS - 0, // APPRENTICES_EXIST // should be set to zero with Arcadia - - "Arcadia IV", // WORLD_NAME - - 1, // NEXUS_GATE_OUT - 0, // NEXUS_IS_CITY - 1, // BATTLE_FACTION_INFO - 1, // ALLOW_WITHDRAW - 1, // SEND_COST - 0, // ALLOW_BANK - 0, // BANK_FEE - 0, // BANK_MAXUNSKILLED - 0, // BANK_MAXSKILLPERLEVEL - 0, // CITY_RENAME_COST - 1, // MULTI_HEX_NEXUS - 0, // UNDERWORLD_LEVELS - 0, // UNDERDEEP_LEVELS - 0, // ABYSS_LEVEL - 0, // FLAT_WORLD - 250, // TOWN_PROBABILITY - 80, // TOWN_SPREAD - 60, // TOWNS_NOT_ADJACENT - 0, // LESS_ARCTIC_TOWNS - 50, // OCEAN - 10, // CONTINENT_SIZE - 2, // TERRAIN_GRANULARITY - 2, // LAKES - 20, // ARCHIPELAGO - 40, // SEVER_LAND_BRIDGES - 6, // SEA_LIMIT - GameDefs::NO_EFFECT, // LAKE_WAGE_EFFECT - 1, // LAKESIDE_IS_COASTAL - 20, // ODD_TERRAIN - 1, // IMPROVED_FARSIGHT - 1, // GM_REPORT - 0, // DECAY - 0, // LIMITED_MAGES_PER_BUILDING // This should be set to 0 with Arcadia - (GameDefs::REPORT_SHOW_REGION | GameDefs::REPORT_SHOW_BUILDINGS), // TRANSIT_REPORT - 0, // MARKETS_SHOW_ADVANCED_ITEMS - GameDefs::PREPARE_NONE, // USE_PREPARE_COMMAND - 5, // MONSTER_ADVANCE_MIN_PERCENT - 75, // MONSTER_ADVANCE_HOSTILE_PERCENT - 0, // HAVE_EMAIL_SPECIAL_COMMANDS - 0, // START_CITIES_START_UNLIMITED - 1, // PROPORTIONAL_AMTS_USAGE - 0, // USE_WEAPON_ARMOR_COMMAND - 0, // MONSTER_NO_SPOILS - 0, // MONSTER_SPOILS_RECOVERY - 3, // MAX_ASSASSIN_FREE_ATTACKS - 0, // RELEASE_MONSTERS - 1, // CHECK_MONSTER_CONTROL_MID_TURN - 1, // DETECT_GATE_NUMBERS - GameDefs::ARMY_ROUT_HITS_FIGURE, // ARMY_ROUT - 1, // ADVANCED_FORTS - 0, // FULL_TRUESEEING_BONUS - zero with Arcadia - 0, // IMPROVED_AMTS - 0, // FULL_INVIS_ON_SELF - zero with Arcadia - 0, // MONSTER_BATTLE_REGEN - 0, // SKILL_PRACTICE_AMOUNT - 0, // UPKEEP_MINIMUM_FOOD - -1, // UPKEEP_MAXIMUM_FOOD - 20, // UPKEEP_FOOD_VALUE - 0, // PREVENT_SAIL_THROUGH - 0, // ALLOW_TRIVIAL_PORTAGE - 9, // GATES_NOT_PERENNIAL - 0, // START_GATES_OPEN - 1, // SHOW_CLOSED_GATES - 0, // TRANSPORT - zero with Arcadia - 2, // LOCAL_TRANSPORT - 3, // NONLOCAL_TRANSPORT - 5, // SHIPPING_COST - 0, // FRACTIONAL_WEIGHT - 0, // GROW_RACES - 0, // PLAYER_ECONOMY - 100, // POP_GROWTH - 3, // DELAY_MORTALITY - 6, // DELAY_GROWTH - 100, // TOWN_DEVELOPMENT - 0, //TACTICS_NEEDS_WAR - 1, // ALLIES_NOAID - 1, // HEXSIDE_TERRAIN - 1, // ARCADIA_MAGIC - 0, // EARTHSEA_VICTORY - 1, // REAL_EXPERIENCE - 0, // TESTGAME_ENABLED - 20, // POP_LEVEL - 1, // FORM_TEMPLATES - GameDefs::SHOW_AS_EVENTS, // SUPPRESS_ERRORS - 1, // LATE_TAX - 80, // MAGE_UNDEAD_INVINCIBLE - 1, // CANT_TEACH_MAGIC - 1, // ARCADIAN_CHECKER -}; - -GameDefs *Globals = &g; diff --git a/arcadia/runorders.cpp b/arcadia/runorders.cpp deleted file mode 100644 index e161e554a..000000000 --- a/arcadia/runorders.cpp +++ /dev/null @@ -1,3816 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "game.h" -#include "gamedata.h" - -#ifndef DEBUG -//#define DEBUG -#endif - -void Game::RunOrders() -{ - // - // Form and instant orders are handled during parsing - // - Awrite("Running FIND Orders..."); - RunFindOrders(); - Awrite("Running ENTER/LEAVE Orders..."); - RunEnterOrders(); - Awrite("Running PROMOTE/EVICT Orders..."); - RunPromoteOrders(); - Awrite("Running Combat..."); - DoAttackOrders(); - DoAutoAttacks(); - Awrite("Running STEAL/ASSASSINATE Orders..."); - RunStealOrders(); - Awrite("Running GIVE/PAY/TRANSFER Orders..."); - DoGiveOrders(); - Awrite("Running EXCHANGE Orders..."); - DoExchangeOrders(); - Awrite("Running DESTROY Orders..."); - RunDestroyOrders(); - if(Globals->ARCADIA_MAGIC) { //moved forward for hypnosis, and since I couldn't think of any reason tax needed to come first. - Awrite("Running Magic Orders..."); - ClearCastEffects(); - RunCastOrders(); - } - if(!Globals->LATE_TAX) { - Awrite("Running PILLAGE Orders..."); - RunPillageOrders(); - Awrite("Running TAX Orders..."); - RunTaxOrders(); - } - Awrite("Running GUARD 1 Orders..."); - DoGuard1Orders(); - if(!Globals->ARCADIA_MAGIC) { - Awrite("Running Magic Orders..."); - ClearCastEffects(); - RunCastOrders(); - } - Awrite("Running SELL Orders..."); - RunSellOrders(); - Awrite("Running BUY Orders..."); - RunBuyOrders(); - Awrite("Running SEND Orders..."); - DoSendOrders(); - Awrite("Running FORGET Orders..."); - RunForgetOrders(); - Awrite("Mid-Turn Processing..."); - MidProcessTurn(); - Awrite("Running QUIT Orders..."); - RunQuitOrders(); - Awrite("Removing Empty Units..."); - DeleteEmptyUnits(); - SinkUncrewedShips(); - DrownUnits(); - if (Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) { - Awrite("Running BANK orders..."); - if (Globals->ALLOW_BANK & GameDefs::BANK_TRADEINTEREST) - BankInterest(); - DoBankDepositOrders(); - DoBankWithdrawOrders(); - } - if(Globals->ALLOW_WITHDRAW) { - Awrite("Running WITHDRAW Orders..."); - DoWithdrawOrders(); - } - if(Globals->LATE_TAX) { - Awrite("Running PILLAGE Orders..."); - RunPillageOrders(); - Awrite("Running TAX Orders..."); - RunTaxOrders(); - } - Awrite("Running Move Orders..."); - RunMoveOrders(); - Awrite("Sinking Ships..."); - SinkUncrewedShips(); - TransferNonShipUnits(); // BS Sailing Mod - DrownUnits(); - Awrite("Clearing Factions..."); - FindDeadFactions(); - Awrite("Running Teach Orders..."); - RunTeachOrders(); - Awrite("Running Month-long Orders..."); - RunMonthOrders(); //Build, produce, work - Awrite("Recieving sent goods"); - RecieveSentGoods(); - Awrite("Running Teleport Orders..."); - RunTeleportOrders(); - if (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - Awrite("Running Transport Orders..."); - CheckTransportOrders(); - RunTransportOrders(); - } - if(Globals->ARCADIA_MAGIC) { - SinkLandRegions(); - DistributeFog(); - RechargeMages(); - } - Awrite("Assessing Maintenance costs..."); - AssessMaintenance(); - Awrite("Post-Turn Processing..."); - PostProcessTurn(); - DeleteEmptyUnits(); - EmptyHell(); - RemoveEmptyObjects(); -} - -void Game::RunCheckAllOrders() -{ - Awrite("Running FIND Orders..."); - RunFindOrders(); - - Awrite("Running ENTER/LEAVE Orders..."); - RunEnterOrders(); - - - Awrite("Running PROMOTE/EVICT Orders..."); - RunPromoteOrders(); - - Awrite("Running DESTROY Orders..."); - RunDestroyOrders(); - - Awrite("Running GIVE/PAY/TRANSFER Orders..."); - DoGiveOrders(); - /* - Awrite("Running EXCHANGE Orders..."); - DoExchangeOrders(); - */ - Awrite("Running DESTROY Orders..."); - RunDestroyOrders(); - - if(Globals->ARCADIA_MAGIC) { //moved forward for hypnosis, and since I couldn't think of any reason tax needed to come first. - Awrite("Running Magic Orders..."); - ClearCastEffects(); - RunCastOrders(); - } - - if(!Globals->LATE_TAX) { - Awrite("Running PILLAGE Orders..."); - RunPillageOrders(); - Awrite("Running TAX Orders..."); - RunTaxOrders(); - } - - - Awrite("Running GUARD 1 Orders..."); - DoGuard1Orders(); - if(!Globals->ARCADIA_MAGIC) { - Awrite("Running Magic Orders..."); - ClearCastEffects(); - RunCastOrders(); - } - - Awrite("Running SELL Orders..."); - RunSellOrders(); - Awrite("Running BUY Orders..."); - RunBuyOrders(); - Awrite("Running SEND Orders..."); - DoSendOrders(); - Awrite("Running FORGET Orders..."); - RunForgetOrders(); - Awrite("Mid-Turn Processing..."); - MidProcessTurn(); - Awrite("Running QUIT Orders..."); - RunQuitOrders(); - Awrite("Removing Empty Units..."); - DeleteEmptyUnits(); - SinkUncrewedShips(); - DrownUnits(); - if (Globals->ALLOW_BANK & GameDefs::BANK_ENABLED) { - Awrite("Running BANK orders..."); - if (Globals->ALLOW_BANK & GameDefs::BANK_TRADEINTEREST) - BankInterest(); - DoBankDepositOrders(); - DoBankWithdrawOrders(); - } - if(Globals->ALLOW_WITHDRAW) { - Awrite("Running WITHDRAW Orders..."); - DoWithdrawOrders(); - } - - if(Globals->LATE_TAX) { - Awrite("Running PILLAGE Orders..."); - RunPillageOrders(); - Awrite("Running TAX Orders..."); - RunTaxOrders(); - } - - Awrite("Running Move Orders..."); - RunMoveOrders(); - Awrite("Sinking Ships..."); - SinkUncrewedShips(); - TransferNonShipUnits(); // BS Sailing Mod - DrownUnits(); - Awrite("Clearing Factions..."); - FindDeadFactions(); - Awrite("Running Teach Orders..."); - RunTeachOrders(); - Awrite("Running Month-long Orders..."); - RunMonthOrders(); //Build, produce, work - Awrite("Recieving sent goods"); - RecieveSentGoods(); - Awrite("Running Teleport Orders..."); - RunTeleportOrders(); - if (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - Awrite("Running Transport Orders..."); - CheckTransportOrders(); - RunTransportOrders(); - } - if(Globals->ARCADIA_MAGIC) { - SinkLandRegions(); - DistributeFog(); - RechargeMages(); - } - Awrite("Assessing Maintenance costs..."); - AssessMaintenance(); - Awrite("Post-Turn Processing..."); - PostProcessTurn(); - DeleteEmptyUnits(); - EmptyHell(); - RemoveEmptyObjects(); -} - -void Game::CountUnits() -{ -//Test item. Not usually called from anywhere - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if(u->faction->num >= 3) Awrite(AString("faction ") + u->faction->num + " " + u->GetMen() + " " + u->dead); - } - } - } -} - -void Game::ClearCastEffects() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - u->SetFlag(FLAG_INVIS, 0); - u->SetFlag(FLAG_VISIB, 0); - } - } - } -} - -void Game::RunCastOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *obj = (Object *) elem; - forlist(&obj->units) { - Unit *u = (Unit *) elem; - forlist(&u->castlistorders) { - CastOrder *ord = (CastOrder *) elem; - RunACastOrder(r, obj, u, ord); - } - u->castlistorders.DeleteAll(); - } - } - } -} - -int Game::CountMages(Faction *pFac) -{ - int i = 0; - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == pFac && u->type == U_MAGE && u->GetMen()) i++; //get men condition added because you can have a mage unit with no leaders after the give phase. - } - } - } - return(i); -} - -int Game::TaxCheck(ARegion *pReg, Faction *pFac) -{ - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - if(AllowedTaxes(pFac) == -1) { - // - // No limit. - // - return(1); - } - - forlist(&(pFac->war_regions)) { - ARegion *x = ((ARegionPtr *) elem)->ptr; - if(x == pReg) { - // - // This faction already performed a tax action in this - // region. - // - return 1; - } - } - if(pFac->war_regions.Num() >= AllowedTaxes(pFac)) { - // - // Can't tax here. - // - return 0; - } else { - // - // Add this region to the faction's tax list. - // - ARegionPtr *y = new ARegionPtr; - y->ptr = pReg; - pFac->war_regions.Add(y); - return 1; - } - } else { - // - // No limit on taxing regions in this game. - // - return(1); - } -} - -int Game::TradeCheck(ARegion *pReg, Faction *pFac) -{ - if(Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - if(AllowedTrades(pFac) == -1) { - // - // No limit on trading on this faction. - // - return(1); - } - - forlist(&(pFac->trade_regions)) { - ARegion *x = ((ARegionPtr *) elem)->ptr; - if (x == pReg) { - // - // This faction has already performed a trade action in this - // region. - // - return 1; - } - } - if (pFac->trade_regions.Num() >= AllowedTrades(pFac)) { - // - // This faction is over its trade limit. - // - return 0; - } else { - // - // Add this region to the faction's trade list, and return 1. - // - ARegionPtr *y = new ARegionPtr; - y->ptr = pReg; - pFac->trade_regions.Add(y); - return 1; - } - } else { - // - // No limit on trade in this game. - // - return(1); - } -} - -void Game::RunStealOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist_safe(&o->units) { - Unit *u = (Unit *) elem; - if (u->stealorders) { - if (u->stealorders->type == O_STEAL) { - Do1Steal(r, o, u); - } else if (u->stealorders->type == O_ASSASSINATE) { - Do1Assassinate(r, o, u); - } - delete u->stealorders; - u->stealorders = 0; - } - } - } - } -} - -AList *Game::CanSeeSteal(ARegion *r, Unit *u) -{ - AList *retval = new AList; - forlist(&factions) { - Faction *f = (Faction *) elem; - if (r->Present(f)) { - if (f->CanSee(r, u, Globals->SKILL_PRACTICE_AMOUNT > 0)) { - FactionPtr *p = new FactionPtr; - p->ptr = f; - retval->Add(p); - } - } - } - return retval; -} - -void Game::Do1Assassinate(ARegion *r, Object *o, Unit *u) -{ - if(u->dead) return; //Arcadia mod because assassin orders cannot be removed. - - AssassinateOrder *so = (AssassinateOrder *) u->stealorders; - Unit *tar = r->GetUnitId(so->target, u->faction->num); - - if (!tar) { - u->Error("ASSASSINATE: Invalid unit given.", so->quiet); - return; - } - if (!tar->IsReallyAlive()) { - u->Error("ASSASSINATE: Invalid unit given.", so->quiet); - return; - } - - // New rule -- You can only assassinate someone you can see - if (!u->CanSee(r, tar)) { - u->Error("ASSASSINATE: Invalid unit given.", so->quiet); - return; - } - - if (tar->type == U_GUARD || tar->type == U_WMON || - tar->type == U_GUARDMAGE) { - u->Error("ASSASSINATE: Can only assassinate other player's " - "units.", so->quiet); - return; - } - - if (u->GetMen() != 1) { - u->Error("ASSASSINATE: Must be executed by a 1-man unit.", so->quiet); - return; - } - - if (u->IsMage() && tar->IsMage()) { - u->Error("ASSASSINATE: Heros cannot assassinate other heros", so->quiet); - return; - } - - int def = tar->GetSkill(S_SECSIGHT); - while(def > 0) { - if(getrandom(2)) { - u->Error("ASSASSINATE: Attempt is foiled by target's second sight", so->quiet); - return; - } - def--; - } - - AList *seers = CanSeeSteal(r, u); - int succ = 1; - forlist(seers) { - Faction *f = ((FactionPtr *) elem)->ptr; - if (f == tar->faction) { - succ = 0; - break; - } - if (f->GetAttitude(tar->faction->num) == A_ALLY) { - succ = 0; - break; - } - if (f->num == guardfaction || f->num == elfguardfaction || - f->num == dwarfguardfaction || f->num == independentguardfaction) { - if(f->ethnicity == tar->faction->ethnicity) { - succ = 0; - break; - } - } - } - if (tar->type == U_MAGE && Globals->ARCADIA_MAGIC) { - int energy = tar->MaxEnergy(); - if(getrandom(40+energy) > 40) succ = 0; // chance for mages to escape assassination. - } - - - if (!succ) { - AString temp = *(u->name) + " is caught attempting to assassinate " + - *(tar->name) + " in " + *(r->name) + "."; - forlist(seers) { - Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(temp); - } - // One learns from one's mistakes. Surviving them is another matter! - u->PracticeAttribute("stealth"); - return; - } - - int ass = 1; - if(u->items.GetNum(I_RINGOFI)) { - ass = 2; // Check if assassin has a ring. - // New rule: if a target has an amulet of true seeing they - // cannot be assassinated by someone with a ring of invisibility - if(tar->AmtsPreventCrime(u)) { - tar->Event("Assassination prevented by amulet of true seeing."); - u->Event(AString("Attempts to assassinate ") + *(tar->name) + - ", but is prevented by amulet of true seeing."); - return; - } - } - u->PracticeAttribute("stealth"); - //assassination taking place ... experience stealth. Target experiences observation. One person dies, other gets experience - u->Experience(S_STEALTH,10); - tar->Experience(S_OBSERVATION,10); - RunBattle(r, u, tar, ass); -#ifdef DEBUG -cout << "Returned to Do1Assassinate" << endl; -#endif -} - -void Game::Do1Steal(ARegion *r, Object *o, Unit *u) -{ - if(u->dead) return; //Arcadia mod because assassin orders cannot be removed. - - StealOrder *so = (StealOrder *) u->stealorders; - Unit *tar = r->GetUnitId(so->target, u->faction->num); - - if (!tar) { - u->Error("STEAL: Invalid unit given.", so->quiet); - return; - } - - // New RULE!! You can only steal from someone you can see. - if(!u->CanSee(r, tar)) { - u->Error("STEAL: Invalid unit given.", so->quiet); - return; - } - - if (tar->type == U_GUARD || tar->type == U_WMON || - tar->type == U_GUARDMAGE) { - u->Error("STEAL: Can only steal from other player's " - "units.", so->quiet); - return; - } - - if (u->GetMen() != 1) { - u->Error("STEAL: Must be executed by a 1-man unit.", so->quiet); - return; - } - - int def = tar->GetSkill(S_SECSIGHT); - while(def > 0) { - if(getrandom(2)) { - u->Error("ASSASSINATE: Attempt is foiled by target's second sight", so->quiet); - return; - } - def--; - } - - AList *seers = CanSeeSteal(r, u); - int succ = 1; - forlist(seers) { - Faction *f = ((FactionPtr *) elem)->ptr; - if (f == tar->faction) { - succ = 0; - break; - } - if (f->GetAttitude(tar->faction->num) == A_ALLY) { - succ = 0; - break; - } - if (f->num == guardfaction || f->num == elfguardfaction || - f->num == dwarfguardfaction || f->num == independentguardfaction) { - if(f->ethnicity == tar->faction->ethnicity) { - succ = 0; - break; - } - } - } - - if (!succ) { - AString temp = *(u->name) + " is caught attempting to steal from " + - *(tar->name) + " in " + *(r->name) + "."; - forlist(seers) { - Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(temp); - } - // One learns from one's mistakes. Surviving them is another matter! - u->PracticeAttribute("stealth"); - return; - } - - // - // New rule; if a target has an amulet of true seeing they can't be - // stolen from by someone with a ring of invisibility - // - if(tar->AmtsPreventCrime(u)) { - tar->Event("Theft prevented by amulet of true seeing."); - u->Event(AString("Attempts to steal from ") + *(tar->name) + ", but " - "is prevented by amulet of true seeing."); - return; - } - - int amt = 1; - if (so->item == I_SILVER) { - amt = tar->GetMoney(); - if (amt < 400) { - amt = amt / 2; - } else { - amt = 200; - } - } - - if (tar->items.GetNum(so->item) < amt) amt = 0; - - u->items.SetNum(so->item, u->items.GetNum(so->item) + amt); - tar->items.SetNum(so->item, tar->items.GetNum(so->item) - amt); - - { - AString temp = *(u->name) + " steals " + - ItemString(so->item, amt) + " from " + *(tar->name) + "."; - forlist(seers) { - Faction *f = ((FactionPtr *) elem)->ptr; - f->Event(temp); - } - } - - tar->Event(AString("Has ") + ItemString(so->item, amt) + " stolen."); - u->PracticeAttribute("stealth"); - return; -} - -void Game::DrownUnits() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if (TerrainDefs[r->type].similar_type == R_OCEAN) { - forlist(&r->objects) { - Object *o = (Object *) elem; - if(o->type != O_DUMMY) continue; - forlist(&o->units) { - Unit *u = (Unit *)elem; - if (!u->TryToSwim()) { - r->Kill(u); - u->Event("Drowns in the ocean."); - } - } - } - } - } -} - -void Game::SinkUncrewedShips() -{ - Unit *u; - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if (TerrainDefs[r->type].similar_type == R_OCEAN) { - forlist(&r->objects) { - Object *o = (Object *) elem; - if(!o->IsBoat()) continue; - - int men = 0; - forlist(&o->units) { - u = (Unit *)elem; - men += u->GetMen(); - } - - if(men <= 0 && getrandom(100) < 10) { //BS Sailing Mod, 10% sink chance - /* No men onboard, move all units out to ocean */ - forlist(&o->units) { - u = (Unit *)elem; - u->MoveUnit(r->GetDummy()); - } - /* And sink the boat */ - r->objects.Remove(o); - delete o; - } - } - } - } -} - -void Game::TransferNonShipUnits() -{ -/* BS Sailing Mod */ - Unit *u; - forlist(®ions) { - ARegion *r = (ARegion *) elem; - if (TerrainDefs[r->type].similar_type == R_OCEAN) { - forlist(&r->objects) { - Object *o = (Object *) elem; - if(o->type == O_DUMMY) continue; - if(o->IsBoat()) continue; - - forlist(&o->units) { - u = (Unit *)elem; - if(u->faction->num != monfaction) { - /* if no boat in the region, move units into the ocean */ - if(!u->HasBoat(r) ) u->MoveUnit(r->GetDummy()); - } - } - } - } - } -} - -int Unit::HasBoat(ARegion *reg) -{ -/* BS Sailing Mod */ - forlist(®->objects) { - Object *o = (Object *) elem; - if(!o->IsBoat()) continue; - Unit *forbid = o->ForbiddenBy(reg, this); - if(!forbid) return 1; //Not forbidden, ie allowed on ship - } - return 0; // no ship would take the unit! -} - -void Game::RunForgetOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - forlist(&u->forgetorders) { - ForgetOrder *fo = (ForgetOrder *) elem; - u->ForgetSkill(fo->skill); - u->Event(AString("Forgets ") + SkillStrs(fo->skill) + "."); - } - u->forgetorders.DeleteAll(); - } - } - } -} - -void Game::RunQuitOrders() -{ - forlist(&factions) { - Faction *f = (Faction *) elem; - if (f->quit) - Do1Quit(f); - } -} - -void Game::Do1Quit(Faction *f) -{ - if(f->start != -1 && regions.GetRegion(f->start) && - regions.GetRegion(f->start)->flagpole == FL_USED_START_LOC) - regions.GetRegion(f->start)->flagpole = FL_UNUSED_START_LOC; - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction == f) { - o->units.Remove(u); //Remove(u), not Kill(u) ?! WHY? - delete u; - } - } - } - } -} - -void Game::RunDestroyOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - Unit *u = o->GetOwner(); - if (u) { - if (u->destroy) { - Do1Destroy(r, o, u); - continue; - } else { - forlist(&o->units) - ((Unit *) elem)->destroy = 0; - } - } - } - } -} - -void Game::Do1Destroy(ARegion *r, Object *o, Unit *u) { - if (TerrainDefs[r->type].similar_type == R_OCEAN) { - u->Error("DESTROY: Can't destroy a ship while at sea."); - forlist(&o->units) { - ((Unit *) elem)->destroy = 0; - } - return; - } - - if (!u->GetMen()) { - u->Error("DESTROY: Empty units cannot destroy structures."); - forlist(&o->units) { - ((Unit *) elem)->destroy = 0; - } - return; - } - - if (o->CanModify()) { - u->Event(AString("Destroys ") + *(o->name) + "."); - Object *dest = r->GetDummy(); - forlist(&o->units) { - Unit *u = (Unit *) elem; - u->destroy = 0; - u->MoveUnit(dest); - } - r->objects.Remove(o); - delete o; - - } else { - u->Error("DESTROY: Can't destroy that."); - forlist(&o->units) { - ((Unit *) elem)->destroy = 0; - } - } -} - -void Game::RunFindOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - RunFindUnit(u); - } - } - } -} - -void Game::RunFindUnit(Unit *u) -{ - int all = 0; - Faction *fac; - forlist(&u->findorders) { - FindOrder *f = (FindOrder *) elem; - if(f->find == 0) all = 1; - if(!all) { - fac = GetFaction(&factions, f->find); - if (fac) { - u->faction->Event(AString("The address of ") + *(fac->name) + - " is " + *(fac->address) + "."); - } else { - u->Error(AString("FIND: ") + f->find + " is not a valid " - "faction number."); - } - } else { - forlist(&factions) { - fac = (Faction *)elem; - if(fac) { - u->faction->Event(AString("The address of ") + - *(fac->name) + " is " + *(fac->address) + "."); - } - } - } - } - u->findorders.DeleteAll(); -} - -void Game::RunTaxOrders() -{ - forlist(®ions) { - RunTaxRegion((ARegion *) elem); - } -} - -int Game::FortTaxBonus(Object *o, Unit *u) -{ - int protect = ObjectDefs[o->type].protect; - int fortbonus = 0; - forlist(&o->units) { - Unit *unit = (Unit *) elem; - int men = unit->GetMen(); - if(unit->num == u->num) { - if(unit->taxing == TAX_TAX) { - int fortbonus = men; - int maxtax = unit->Taxers(1); - if(fortbonus > protect) fortbonus = protect; - if(fortbonus > maxtax) fortbonus = maxtax; - fortbonus *= Globals->TAX_BONUS_FORT; - return(fortbonus); - } - } - protect -= men; - if(protect < 0) protect = 0; - } - return(fortbonus); -} - -int Game::CountTaxes(ARegion *reg) -{ - int t = 0; - forlist(®->objects) { - Object *o = (Object *) elem; - int protect = ObjectDefs[o->type].protect; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->GetFlag(FLAG_AUTOTAX) && !Globals->TAX_PILLAGE_MONTH_LONG) - u->taxing = TAX_TAX; - if(u->taxing == TAX_AUTO) u->taxing = TAX_TAX; - - if (u->taxing == TAX_TAX) { - if (!reg->CanTax(u)) { - u->Error("TAX: A unit is on guard."); - u->taxing = TAX_NONE; - } else { - int men = u->Taxers(0); - int fortbonus = u->GetMen(); - if(fortbonus > protect) fortbonus = protect; - protect -= u->GetMen(); - if(protect < 0) protect = 0; - if (men) { - if(!TaxCheck(reg, u->faction)) { - u->Error("TAX: Faction can't tax that many " - "regions."); - u->taxing = TAX_NONE; - } else { - t += men + fortbonus * Globals->TAX_BONUS_FORT; - } - } else { - u->Error("TAX: Unit cannot tax."); - u->taxing = TAX_NONE; - u->SetFlag(FLAG_AUTOTAX, 0); - } - } - } - } - } - return t; -} - -void Game::RunTaxRegion(ARegion *reg) -{ - int desired = CountTaxes(reg); - reg->untaxed = reg->money - desired; //BS mod. - if (desired < reg->money) desired = reg->money; - - forlist(®->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->taxing == TAX_TAX) { - int t = u->Taxers(0); - t += FortTaxBonus(o, u); - double fAmt = ((double) t) * - ((double) reg->money) / ((double) desired); - int amt = (int) fAmt; - reg->money -= amt; - desired -= t; - u->SetMoney(u->GetMoney() + amt); - u->Event(AString("Collects $") + amt + " in taxes in " + - reg->ShortPrint(®ions) + "."); - u->taxing = TAX_NONE; - } - } - } -} - -void Game::RunPillageOrders() -{ - forlist (®ions) { - RunPillageRegion((ARegion *) elem); - } -} - -int Game::CountPillagers(ARegion *reg) -{ - int p = 0; - forlist(®->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->taxing == TAX_PILLAGE) { - if (!reg->CanPillage(u)) { - u->Error("PILLAGE: A unit is on guard."); - u->taxing = TAX_NONE; - } else { - int men = u->Taxers(1); - if (men) { - if(!TaxCheck(reg, u->faction)) { - u->Error("PILLAGE: Faction can't tax that many " - "regions."); - u->taxing = TAX_NONE; - } else { - p += men; - } - } else { - u->Error("PILLAGE: Not a combat ready unit."); - u->taxing = TAX_NONE; - } - } - } - } - } - return p; -} - -void Game::ClearPillagers(ARegion *reg) -{ - forlist(®->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->taxing == TAX_PILLAGE) { - u->Error("PILLAGE: Not enough men to pillage."); - u->taxing = TAX_NONE; - } - } - } -} - -void Game::RunPillageRegion(ARegion *reg) -{ - if (TerrainDefs[reg->type].similar_type == R_OCEAN) return; - if (reg->money < 1) return; -// if (reg->Wages() < 11) return; - - /* First, count up pillagers */ - int pillagers = CountPillagers(reg); - - if (pillagers * 2 * Globals->TAX_BASE_INCOME < reg->money) { - ClearPillagers(reg); - return; - } - - AList *facs = reg->PresentFactions(); - int amt = reg->money * 2; - forlist(®->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->taxing == TAX_PILLAGE) { - u->taxing = TAX_NONE; - int num = u->Taxers(1); - int temp = (amt * num)/pillagers; - amt -= temp; - pillagers -= num; - u->SetMoney(u->GetMoney() + temp); - u->Event(AString("Pillages $") + temp + " from " + - reg->ShortPrint(®ions) + "."); - forlist(facs) { - Faction *fp = ((FactionPtr *) elem)->ptr; - if (fp != u->faction) { - fp->Event(*(u->name) + " pillages " + - *(reg->name) + "."); - } - } - } - } - } - delete facs; - - /* Destroy economy */ - reg->money = 0; - reg->wages -= 7; //used to be 6, 7 for Xan because of the lower base wage for tax purposes (old breakeven point $25, with 6 would now be $20, with 7 is $26, closer to old behaviour) - if (reg->wages < 0) reg->wages = 0; -} - -void Game::RunPromoteOrders() -{ - ARegion *r; - Object *o; - Unit *u; - - /* First, do any promote orders */ - forlist(®ions) { - r = (ARegion *)elem; - forlist(&r->objects) { - o = (Object *)elem; -// if (o->type != O_DUMMY) { //BS mod - allow promote in open area. - u = o->GetOwner(); - if(u && u->promote) { - Do1PromoteOrder(o, u); - delete u->promote; - u->promote = 0; - } -// } - } - } - /* Now do any evict orders */ - { - forlist(®ions) { - r = (ARegion *)elem; - forlist(&r->objects) { - o = (Object *)elem; - if (o->type != O_DUMMY) { - u = o->GetOwner(); - if (u && u->evictorders) { - Do1EvictOrder(o, u); - delete u->evictorders; - u->evictorders = 0; - } - } - } - } - } - - /* Then, clear out other promote/evict orders */ - { - forlist(®ions) { - r = (ARegion *) elem; - forlist(&r->objects) { - o = (Object *) elem; - forlist(&o->units) { - u = (Unit *) elem; - if (u->promote) { -// if (o->type != O_DUMMY) { - u->Error("PROMOTE: Must be owner", u->promotequiet); - delete u->promote; - u->promote = 0; -// } else { -// u->Error("PROMOTE: Can only promote inside structures.", u->promotequiet); -// delete u->promote; -// u->promote = 0; -// } - } - if (u->evictorders) { - if (o->type != O_DUMMY) { - u->Error("EVICT: Must be owner",u->evictorders->quiet); - delete u->evictorders; - u->evictorders = 0; - } else { - u->Error("EVICT: Can only evict inside structures.",u->evictorders->quiet); - delete u->evictorders; - u->evictorders = 0; - } - } - } - } - } - } -} - -void Game::Do1PromoteOrder(Object *obj, Unit *u) -{ - Unit *tar = obj->GetUnitId(u->promote, u->faction->num); - if (!tar) { - u->Error("PROMOTE: Can't find target.", u->promotequiet); - return; - } - obj->units.Remove(tar); - obj->units.Insert(tar); -} - -void Game::Do1EvictOrder(Object *obj, Unit *u) -{ - EvictOrder *ord = u->evictorders; - - while (ord && ord->targets.Num()) { - UnitId *id = (UnitId *)ord->targets.First(); - ord->targets.Remove(id); - Unit *tar = obj->GetUnitId(id, u->faction->num); - delete id; - if (!tar) continue; - if(obj->IsBoat() && - (TerrainDefs[obj->region->type].similar_type == R_OCEAN) && - (!tar->CanReallySwim() || tar->GetFlag(FLAG_NOCROSS_WATER))) { - u->Error("EVICT: Cannot forcibly evict units over ocean.", ord->quiet); - continue; - } - Object *to = obj->region->GetDummy(); - tar->MoveUnit(to); - tar->Event(AString("Evicted from ") + *obj->name + " by " + *u->name); - u->Event(AString("Evicted ") + *tar->name + " from " + *obj->name); - } -} - -void Game::RunEnterOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->enter) - Do1EnterOrder(r, o, u); - } - } - } -} - -void Game::Do1EnterOrder(ARegion *r, Object *in, Unit *u) -{ - Object *to; - if (u->enter == -1) { - to = r->GetDummy(); - u->enter = 0; - if((TerrainDefs[r->type].similar_type == R_OCEAN) && - ( (!u->CanSwim() && u->items.Weight()) || u->GetFlag(FLAG_NOCROSS_WATER))) { //this allows empty units to leave ships - which can then have men bought into them ... but otherwise, bought merfolk can't leave ships. - u->Error("LEAVE: Can't leave a ship in the ocean."); - return; - } - if (in->IsBoat() && u->CanSwim()) u->leftShip = 1; - } else { - to = r->GetObject(u->enter); - u->enter = 0; - if (!to) { - u->Error("ENTER: Can't enter that."); - return; - } - if (!to->CanEnter(r, u)) { - u->Error("ENTER: Can't enter that."); - return; - } - if (to->ForbiddenBy(r, u)) { - u->Error("ENTER: Is refused entry."); - return; - } - } - u->MoveUnit(to); -} - -void Game::RemoveEmptyObjects() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - if (ObjectDefs[o->type].cost && - o->incomplete >= ObjectDefs[o->type].cost) { - forlist(&o->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(r->GetDummy()); - } - r->objects.Remove(o); - delete o; - } - } - } -} - -void Game::EmptyHell() -{ - forlist(®ions) - ((ARegion *) elem)->ClearHell(); -} - -void Game::MidProcessUnit(ARegion *r, Unit *u) -{ - MidProcessUnitExtra(r, u); -} - -void Game::PostProcessUnit(ARegion *r, Unit *u) -{ - PostProcessUnitExtra(r, u); - /* ARCADIA_MAGIC Patch*/ - if(u->dead && Globals->ARCADIA_MAGIC) { - if(!u->AgeDead()) { - u->MoveUnit(0); - r->hell.Add(u); - } - //check faction - if(u->faction->num != ghostfaction) { - Faction *fac = GetFaction(&factions, ghostfaction); - if(fac) u->faction = fac; - else { - u->MoveUnit(0); //routine for destroying a unit, from ARegion::Kill() - r->hell.Add(u); - } - } - } -} - -void Game::EndGame(Faction *pVictor, AString *victoryline) -{ - forlist(&factions) { - Faction *pFac = (Faction *) elem; - pFac->exists = 0; - if(pFac == pVictor) - pFac->quit = QUIT_WON_GAME; - else - pFac->quit = QUIT_GAME_OVER; - - if(pVictor) - pFac->Event(*victoryline); - else - pFac->Event("The game has ended with no winner."); - } - - gameStatus = GAME_STATUS_FINISHED; -} - -void Game::MidProcessTurn() -{ - forlist(®ions) { - ARegion *r = (ARegion *)elem; - // r->MidTurn(); // Not yet implemented - forlist(&r->objects) { - Object *o = (Object *)elem; - forlist(&o->units) { - Unit *u = (Unit *)elem; - MidProcessUnit(r, u); - } - } - } -} - -void Game::PostProcessTurn() -{ - // process migration before adjusting economy - if(Globals->PLAYER_ECONOMY) ProcessMigration(); - - forlist(®ions) { - ARegion *r = (ARegion *) elem; - r->PostTurn(®ions); - - if(Globals->CITY_MONSTERS_EXIST && (r->town || r->type == R_NEXUS)) - AdjustCityMons(r); - - if(Globals->ARCADIA_MAGIC) { - SpecialErrors(r); - } - - forlist (&r->objects) { - Object *o = (Object *) elem; - forlist (&o->units) { - Unit *u = (Unit *) elem; - PostProcessUnit(r, u); - } - } - } - - if(Globals->ARCADIA_MAGIC) UpdateFactionAffiliations(); - - if(Globals->WANDERING_MONSTERS_EXIST) GrowWMons(Globals->WMON_FREQUENCY); - - if(Globals->LAIR_MONSTERS_EXIST) { - if(year == 1 && month < 2) GrowLMons(100); - else GrowLMons(Globals->LAIR_FREQUENCY); - } - - if(Globals->LAIR_MONSTERS_EXIST) GrowVMons(); - - // - // Check if there are any factions left. - // - int livingFacs = 0; - { - forlist(&factions) { - Faction *pFac = (Faction *) elem; - if(pFac->exists) { - livingFacs = 1; - break; - } - } - } - - if(!livingFacs) { - AString *vicline = new AString(""); - EndGame(0, vicline); - delete vicline; - } else if(!(Globals->OPEN_ENDED)) { - AString *vicline = new AString(""); - Faction *pVictor = CheckVictory(vicline); - - if(pVictor) - EndGame(pVictor, vicline); - delete vicline; - } -} - -void Game::DoAutoAttacks() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - DoAutoAttacksRegion(r); - } -} - -void Game::DoAutoAttacksRegion(ARegion *r) -{ - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->canattack && u->IsReallyAlive()) DoAutoAttack(r, u); - } - } -} - -void Game::DoAdvanceAttacks(AList *locs) -{ -//note that region & unit are up to date, but obj used not to be because it was not updated in ARegion::DoAMoveOrder. This has been -//fixed in the Arcadia code but not yet the standard. - forlist(locs) { - Location *l = (Location *) elem; - Unit *u = l->unit; - ARegion *r = l->region; - if (u->canattack && u->IsReallyAlive()) { - DoAutoAttack(r, u); - if(!u->canattack || !u->IsReallyAlive()) { - u->guard = GUARD_NONE; - } - } - if (u->canattack && u->guard == GUARD_ADVANCE && u->IsReallyAlive()) { - DoAdvanceAttack(r, u); - u->guard = GUARD_NONE; - } - if (u->IsReallyAlive()) { - DoAutoAttackOn(r, u); - if(!u->canattack || !u->IsReallyAlive()) { - u->guard = GUARD_NONE; - } - } - } -} - -void Game::DoAutoAttackOn(ARegion *r, Unit *t) -{ - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->guard != GUARD_AVOID && - (u->GetAttitude(r, t) == A_HOSTILE) && u->IsReallyAlive() && - u->canattack) - AttemptAttack(r, u, t, 1); -#ifdef DEBUG -cout << "Attempted from DoAutoAttackOn" << endl; -#endif - if (!t->IsReallyAlive()) return; - } - } -} - -void Game::DoAdvanceAttack(ARegion *r, Unit *u) { - Unit *t = r->Forbidden(u); - while (t && u->canattack && u->IsReallyAlive()) { - AttemptAttack(r, u, t, 1, 1); -#ifdef DEBUG -cout << "Attempted from DoAdvanceAttack" << endl; -#endif - if(u->IsReallyAlive()) t = r->Forbidden(u); - } -} - -void Game::DoAutoAttack(ARegion *r, Unit *u) { - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *t = (Unit *) elem; - if (u->guard != GUARD_AVOID && (u->GetAttitude(r, t) == A_HOSTILE)) { - AttemptAttack(r, u, t, 1); -#ifdef DEBUG -cout << "Attempted from DoAutoAttack" << endl; -#endif - } - if (u->canattack == 0 || u->IsReallyAlive() == 0) - return; - } - } -} - -int Game::CountWMonTars(ARegion *r, Unit *mon) { - int retval = 0; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction != mon->faction) { //Nylandor mod; monsters can attack guards - if (mon->CanSee(r, u) && mon->CanCatch(r, u)) { - retval += u->GetMen(); - } - } - } - } - return retval; -} - -Unit *Game::GetWMonTar(ARegion *r, int tarnum, Unit *mon) { - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->faction != mon->faction) { //Nylandor mod; monsters can attack guards - if (mon->CanSee(r, u) && mon->CanCatch(r, u)) { - int num = u->GetMen(); - if (num && tarnum < num) return u; - tarnum -= num; - } - } - } - } - return 0; -} - -void Game::CheckWMonAttack(ARegion *r, Unit *u) { - int tars = CountWMonTars(r, u); - if (!tars) return; - - int rand = 300 - tars; - if (rand < 100) rand = 100; - if (getrandom(rand) >= u->Hostile()) return; - - Unit *t = GetWMonTar(r, getrandom(tars), u); - if (t) AttemptAttack(r, u, t, 1); -#ifdef DEBUG -cout << "Attempted from CheckWMonAttack" << endl; -#endif -} - -void Game::DoAttackOrders() -{ - forlist(®ions) { - ARegion *r = (ARegion *) elem; - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (u->type == U_WMON) { - if (u->canattack && u->IsReallyAlive()) { - CheckWMonAttack(r, u); - } - } else { - if (u->attackorders && u->IsReallyAlive()) { - AttackOrder *ord = u->attackorders; - while (ord->targets.Num()) { - UnitId *id = (UnitId *) ord->targets.First(); - ord->targets.Remove(id); - Unit *t = r->GetUnitId(id, u->faction->num); - delete id; - if (u->canattack && u->IsReallyAlive()) { - if (t) { - AttemptAttack(r, u, t, 0); -#ifdef DEBUG -cout << "Attempted from DoAttackOrders" << endl; -#endif - } else { - u->Error("ATTACK: Non-existent unit."); - } - } - } - delete ord; - u->attackorders = 0; - } - } - } - } - } -} - -// Presume that u is alive, can attack, and wants to attack t. -// Check that t is alive, u can see t, and u has enough riding -// skill to catch t. -// -// Return 0 if success. -// 1 if t is already dead. -// 2 if u can't see t -// 3 if u lacks the riding to catch t -void Game::AttemptAttack(ARegion *r, Unit *u, Unit *t, int silent, int adv) -{ - if (!t->IsReallyAlive()) { -#ifdef DEBUG -cout << "Not Alive" << endl; -#endif - return; - } - - if (!u->CanSee(r, t)) { - if (!silent) u->Error("ATTACK: Non-existent unit."); -#ifdef DEBUG -cout << "Can't See " << u->num << " " << t->num << endl; -#endif - return; - } - - if (!u->CanCatch(r, t)) { - if (!silent) u->Error("ATTACK: Can't catch that unit."); -#ifdef DEBUG -cout << "Can't Catch" << endl; -#endif - return; - } - - RunBattle(r, u, t, 0, adv); -#ifdef DEBUG -cout << "Returned to AttemptAttack" << endl; -#endif - return; -} - -void Game::RunSellOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->markets)) { - Market *m = (Market *) elem; - if (m->type == M_SELL && (m->amount > 0)) //second term added to prevent merchantry revealing 0-item markets (and stop them preventing merchantry from working) - DoSell(r, m); - } - { - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if(u->GetSkill(S_MERCHANTRY)) { - forlist((&u->sellorders)) { - SellOrder *o = (SellOrder *) elem; - DoMerchantSell(u,o); //'sell-anywhere' spell - } - } else { - forlist((&u->sellorders)) { - u->Error("SELL: Can't sell that."); - } - } - u->sellorders.DeleteAll(); - } - } - } - } -} - -int Game::GetSellAmount(ARegion *r, Market *m) -{ - int num = 0; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist ((&u->sellorders)) { - SellOrder *o = (SellOrder *) elem; - if (o->item == m->item) { - if(o->num == -1) { - o->num = u->items.CanSell(o->item); - } - if (o->num > u->items.CanSell(o->item)) { - o->num = u->items.CanSell(o->item); - u->Error("SELL: Unit attempted to sell more than " - "it had.", o->quiet); - } - if (o->num < 0) o->num = 0; - u->items.Selling(o->item, o->num); - num += o->num; - } - } - } - } - return num; -} - -void Game::DoSell(ARegion *r, Market *m) -{ - /* First, find the number of items being sold */ - int attempted = GetSellAmount(r, m); - - if (attempted < m->amount) attempted = m->amount; - m->activity = 0; - int oldamount = m->amount; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->sellorders)) { - SellOrder *o = (SellOrder *) elem; - if (o->item == m->item) { - //get any trading bonuses. - int bonus = 0; - Unit *trader = NULL; - forlist((&r->objects)) { - Object *obj2 = (Object *) elem; - forlist((&obj2->units)) { - Unit *u2 = (Unit *) elem; - if(u2->GetAttitude(r,u) == A_ALLY && u2->GetSkill(S_TRADING) > bonus) { - bonus = u2->GetSkill(S_TRADING); - trader = u2; - } - } - } - - int temp = 0; - if (attempted) { - temp = (m->amount *o->num + getrandom(attempted)) - / attempted; - if (temp<0) temp = 0; - } - attempted -= o->num; - m->amount -= temp; - m->activity += temp; - u->items.SetNum(o->item, u->items.GetNum(o->item) - temp); - u->SetMoney(u->GetMoney() + (temp * m->price * (20+bonus)) / 20); - if(trader) trader->numtraded += (temp * m->price * (20+bonus)) / 20; - u->sellorders.Remove(o); - u->Event(AString("Sells ") + ItemString(o->item, temp) - + " at $" + (m->price * (20+bonus)) / 20 + " each."); - delete o; - } - } - } - } - m->amount = oldamount; -} - -void Game::RunBuyOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->markets)) { - Market *m = (Market *) elem; - if (m->type == M_BUY && (m->amount > 0)) - DoBuy(r, m); - } - { - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if(u->GetSkill(S_MERCHANTRY)) { - forlist((&u->buyorders)) { - BuyOrder *o = (BuyOrder *) elem; - DoMerchantBuy(u,o); //'sell-anywhere' spell - } - } else { - forlist((&u->buyorders)) { - u->Error("BUY: Can't buy that."); - } - } - u->buyorders.DeleteAll(); - } - } - } - } -} - -int Game::GetBuyAmount(ARegion *r, Market *m) -{ - //cycle through and make sure each faction's orders are legal first! - forlist(&factions) { - Faction * fac = (Faction *) elem; - int sharedsilver = 0; - int shareditembuys = 0; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if(u->faction != fac) continue; - if(!sharedsilver && u->GetFlag(FLAG_SHARING)) sharedsilver = u->GetSharedMoney(); - forlist ((&u->buyorders)) { - BuyOrder *o = (BuyOrder *) elem; - if (o->item == m->item) { - if (ItemDefs[o->item].type & IT_MAN) { - if (u->type == U_MAGE) { - u->Error("BUY: Heroes can't recruit more men.", o->quiet); - o->num = 0; - } - if(u->type == U_APPRENTICE) { - u->Error("BUY: Apprentices can't recruit more " - "men.", o->quiet); - o->num = 0; - } - // XXX: there has to be a better way - if (u->GetRealSkill(S_QUARTERMASTER)) { - u->Error("BUY: Quartermasters can't recruit more " - "men.", o->quiet); - o->num = 0; - } - if (Globals->TACTICS_NEEDS_WAR && u->GetRealSkill(S_TACTICS) == 5) { - u->Error("BUY: Tacticians can't recruit more " - "men.", o->quiet); //Why not? They wouldn't be a TACT 5 unit anymore if they did! - o->num = 0; - } - if (((ItemDefs[o->item].type & IT_LEADER) && - u->IsNormal()) || - (!(ItemDefs[o->item].type & IT_LEADER) && - u->IsLeader())) { - u->Error("BUY: Can't mix leaders and normal men.", o->quiet); - o->num = 0; - } - } - if (ItemDefs[o->item].type & IT_TRADE) { - if(!TradeCheck(r, u->faction)) { - u->Error("BUY: Can't buy trade items in that " - "many regions.", o->quiet); - o->num = 0; - } - } - - - - if (o->num == -1) { - o->num = u->GetSharedMoney()/m->price; //here "ALL" orders draw on shared money ... should they? - } - if (o->num * m->price > u->GetSharedMoney()) { - o->num = u->GetSharedMoney() / m->price; - u->Error("BUY: Unit attempted to buy more than it " - "could afford.", o->quiet); - } - //we want to add the orders to faction's total shared-money orders - if(u->GetFlag(FLAG_SHARING)) shareditembuys += o->num*m->price; //this is the amount of the order drawing on shared money - else if(o->num * m->price > u->GetMoney()) shareditembuys += o->num*m->price - u->GetMoney(); //this is the amount of the order drawing on shared money - } - if (o->num < 1 && o->num != -1) { - u->buyorders.Remove(o); - delete o; - } - } - } - } - //if we are attempting to buy more items with shared silver than we have shared silver, we need to reduce our orders so we don't try buying more than we can afford - if(sharedsilver < shareditembuys) { - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if(sharedsilver >= shareditembuys) continue; //we have closed the gap, no need to deduct more - forlist ((&u->buyorders)) { - BuyOrder *o = (BuyOrder *) elem; - if (o->item == m->item) { - int ownmoney = 0; - if(!u->GetFlag(FLAG_SHARING)) ownmoney = u->GetMoney(); - int excess = o->num - (ownmoney/m->price); - //work out how much we can buy with our 'fraction' of the shared silver - int newamount = excess * sharedsilver / shareditembuys; - o->num -= (excess-newamount); - //count the money spent here as this unit's own money, removing both items and money from the temporary share 'pool'. However, don't claim it for real because we may not be able to buy the items in the end - shareditembuys -= excess; - sharedsilver -= (o->num*m->price - ownmoney); //subtracting the amount we need to claim - } - if (o->num < 1 && o->num != -1) { - u->buyorders.Remove(o); - delete o; - } - } - } - } - } - } - - //we now know that all factions are attempting to buy within the limits of what they can afford. - //also, no need to check legality of purchase - that's done above - - int num = 0; - forlist_reuse((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist ((&u->buyorders)) { - BuyOrder *o = (BuyOrder *) elem; - if (o->item == m->item) num += o->num; - } - } - } - return num; -} - -void Game::DoBuy(ARegion *r, Market *m) -{ - /* First, find the number of items being purchased */ - int attempted = GetBuyAmount(r, m); - - if (m->amount != -1) - if (attempted < m->amount) attempted = m->amount; - - m->activity = 0; - int oldamount = m->amount; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->buyorders)) { - BuyOrder *o = (BuyOrder *) elem; - if (o->item == m->item) { - //get any trading bonuses. - int bonus = 0; - Unit *trader = NULL; - forlist((&r->objects)) { - Object *obj2 = (Object *) elem; - forlist((&obj2->units)) { - Unit *u2 = (Unit *) elem; - if(u2->GetAttitude(r,u) == A_ALLY && u2->GetSkill(S_TRADING) > bonus) { - bonus = u2->GetSkill(S_TRADING); - trader = u2; - } - } - } - - int temp = 0; - if (m->amount == -1) { - /* unlimited market */ - temp = o->num; - } else { - if (attempted) { - temp = (m->amount * o->num + - getrandom(attempted)) / attempted; - if (temp < 0) temp = 0; - } - attempted -= o->num; - m->amount -= temp; - m->activity += temp; - } - if (ItemDefs[o->item].type & IT_MAN) { - /* recruiting; must dilute skills */ - SkillList *sl = new SkillList; - u->AdjustSkills(); //no overflow when acquiring new men into a unit - delete sl; - /* region economy effects */ - r->Recruit(temp); - } - u->items.SetNum(o->item, u->items.GetNum(o->item) + temp); - u->faction->DiscoverItem(o->item, 0, 1); - u->ConsumeSharedMoney((temp * m->price * (20-bonus) + 19) / 20); - if(trader) trader->numtraded += (temp * m->price * (20-bonus) + 19) / 20; - u->buyorders.Remove(o); - u->Event(AString("Buys ") + ItemString(o->item, temp) - + " at $" + (m->price * (20-bonus) + 19) / 20 + " each."); - delete o; - } - } - } - } - - m->amount = oldamount; -} - -void Game::CheckUnitMaintenanceItem(int item, int value, int consume) -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->needed > 0 && ((!consume) || - (u->GetFlag(FLAG_CONSUMING_UNIT) || - u->GetFlag(FLAG_CONSUMING_FACTION)))) { - int amount = u->items.GetNum(item); - if (amount) { - int eat = (u->needed + value - 1) / value; - if (eat > amount) - eat = amount; - if (ItemDefs[item].type & IT_FOOD) { - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - eat * value > u->stomach_space) { - eat = (u->stomach_space + value - 1) / value; - if (eat < 0) - eat = 0; - } - u->hunger -= eat * value; - u->stomach_space -= eat * value; - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - u->stomach_space < 0) { - u->needed -= u->stomach_space; - u->stomach_space = 0; - } - } - u->needed -= eat * value; - u->items.SetNum(item, amount - eat); - } - } - } - } - } -} - -void Game::CheckFactionMaintenanceItem(int item, int value, int consume) -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->needed > 0 && ((!consume) || - u->GetFlag(FLAG_CONSUMING_FACTION))) { - /* Go through all units again */ - forlist((&r->objects)) { - Object *obj2 = (Object *) elem; - forlist((&obj2->units)) { - Unit *u2 = (Unit *) elem; - - if (u->faction == u2->faction && u != u2) { - int amount = u2->items.GetNum(item); - if (amount) { - int eat = (u->needed + value - 1) / value; - if (eat > amount) - eat = amount; - if (ItemDefs[item].type & IT_FOOD) { - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - eat * value > u->stomach_space) { - eat = (u->stomach_space + value - 1) / value; - if (eat < 0) - eat = 0; - } - u->hunger -= eat * value; - u->stomach_space -= eat * value; - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - u->stomach_space < 0) { - u->needed -= u->stomach_space; - u->stomach_space = 0; - } - } - u->needed -= eat * value; - u2->items.SetNum(item, amount - eat); - } - } - } - - if (u->needed < 1) break; - } - } - } - } - } -} - -void Game::CheckAllyMaintenanceItem(int item, int value) -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->needed > 0) { - /* Go through all units again */ - forlist((&r->objects)) { - Object *obj2 = (Object *) elem; - forlist((&obj2->units)) { - Unit *u2 = (Unit *) elem; - if (u->faction != u2->faction && - u2->GetAttitude(r, u) == A_ALLY) { - int amount = u2->items.GetNum(item); - if (amount) { - int eat = (u->needed + value - 1) / value; - if (eat > amount) - eat = amount; - if (ItemDefs[item].type & IT_FOOD) { - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - eat * value > u->stomach_space) { - eat = (u->stomach_space + value - 1) / value; - if (eat < 0) - eat = 0; - } - u->hunger -= eat * value; - u->stomach_space -= eat * value; - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - u->stomach_space < 0) { - u->needed -= u->stomach_space; - u->stomach_space = 0; - } - } - if (eat) { - u->needed -= eat * value; - u2->items.SetNum(item, amount - eat); - u2->Event(*(u->name) + " borrows " + - ItemString(item, eat) + - " for maintenance."); - u->Event(AString("Borrows ") + - ItemString(item, eat) + - " from " + *(u2->name) + - " for maintenance."); - u2->items.SetNum(item, amount - eat); - } - } - } - } - - if (u->needed < 1) break; - } - } - } - } - } -} - -void Game::CheckUnitHungerItem(int item, int value) -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->hunger > 0) { - int amount = u->items.GetNum(item); - if (amount) { - int eat = (u->hunger + value - 1) / value; - if (eat > amount) - eat = amount; - u->hunger -= eat * value; - u->stomach_space -= eat * value; - u->needed -= eat * value; - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - u->stomach_space < 0) { - u->needed -= u->stomach_space; - u->stomach_space = 0; - } - u->items.SetNum(item, amount - eat); - } - } - } - } - } -} - -void Game::CheckFactionHungerItem(int item, int value) -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->hunger > 0) { - /* Go through all units again */ - forlist((&r->objects)) { - Object *obj2 = (Object *) elem; - forlist((&obj2->units)) { - Unit *u2 = (Unit *) elem; - - if (u->faction == u2->faction && u != u2) { - int amount = u2->items.GetNum(item); - if (amount) { - int eat = (u->hunger + value - 1) / value; - if (eat > amount) - eat = amount; - u->hunger -= eat * value; - u->stomach_space -= eat * value; - u->needed -= eat * value; - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - u->stomach_space < 0) { - u->needed -= u->stomach_space; - u->stomach_space = 0; - } - u2->items.SetNum(item, amount - eat); - } - } - } - - if (u->hunger < 1) break; - } - } - } - } - } -} - -void Game::CheckAllyHungerItem(int item, int value) -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->hunger > 0) { - /* Go through all units again */ - forlist((&r->objects)) { - Object *obj2 = (Object *) elem; - forlist((&obj2->units)) { - Unit *u2 = (Unit *) elem; - if (u->faction != u2->faction && - u2->GetAttitude(r, u) == A_ALLY) { - int amount = u2->items.GetNum(item); - if (amount) { - int eat = (u->hunger + value - 1) / value; - if (eat > amount) - eat = amount; - u->hunger -= eat * value; - u->stomach_space -= eat * value; - u->needed -= eat * value; - if (Globals->UPKEEP_MAXIMUM_FOOD >= 0 && - u->stomach_space < 0) { - u->needed -= u->stomach_space; - u->stomach_space = 0; - } - u2->items.SetNum(item, amount - eat); - u2->Event(*(u->name) + " borrows " + - ItemString(item, eat) + - " to fend off starvation."); - u->Event(AString("Borrows ") + - ItemString(item, eat) + - " from " + *(u2->name) + - " to fend off starvation."); - u2->items.SetNum(item, amount - eat); - } - } - } - - if (u->hunger < 1) break; - } - } - } - } - } -} - -void Game::AssessMaintenance() -{ - /* First pass: set needed */ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - u->needed = u->MaintCost(); - if(u->dead) u->needed = 0; /* ARCADIA_MAGIC Patch */ - u->hunger = u->GetMen() * Globals->UPKEEP_MINIMUM_FOOD; - if(u->dead) u->hunger = 0; /* ARCADIA_MAGIC Patch */ - if (Globals->UPKEEP_MAXIMUM_FOOD < 0) - u->stomach_space = -1; - else - u->stomach_space = u->GetMen() * - Globals->UPKEEP_MAXIMUM_FOOD; - } - } - } - // Assess food requirements first - if (Globals->UPKEEP_MINIMUM_FOOD > 0) { - CheckUnitHunger(); - CheckFactionHunger(); - if (Globals->ALLOW_WITHDRAW) { - // Can claim food for maintenance, so find the cheapest food - int i = -1, cost = -1; - for (int j = 0; j < NITEMS; j++) { - if (ItemDefs[j].flags & ItemType::DISABLED) continue; - if (ItemDefs[j].type & IT_FOOD) { - if (i == -1 || - ItemDefs[i].baseprice > ItemDefs[j].baseprice) - i = j; - } - } - if (i > 0) { - cost = ItemDefs[i].baseprice * 5 / 2; - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->hunger > 0 && u->faction->unclaimed > cost) { - int value = Globals->UPKEEP_FOOD_VALUE; - int eat = (u->hunger + value - 1) / value; - /* Now see if faction has money */ - if (u->faction->unclaimed >= eat * cost) { - u->Event(AString("Withdraws ") + - ItemString(i, eat) + - " for maintenance."); - u->faction->unclaimed -= eat * cost; - u->hunger -= eat * value; - u->stomach_space -= eat * value; - u->needed -= eat * value; - } else { - int amount = u->faction->unclaimed / cost; - u->Event(AString("Withdraws ") + - ItemString(i, amount) + - " for maintenance."); - u->faction->unclaimed -= amount * cost; - u->hunger -= amount * value; - u->stomach_space -= amount * value; - u->needed -= amount * value; - } - } - } - } - } - } - } - CheckAllyHunger(); - } - - // - // Check for CONSUMEing units. - // - if(Globals->FOOD_ITEMS_EXIST) { - CheckUnitMaintenance(1); - CheckFactionMaintenance(1); - } - - // - // Check the unit for money. - // - CheckUnitMaintenanceItem(I_SILVER, 1, 0); - - // - // Check other units in same faction for money - // - CheckFactionMaintenanceItem(I_SILVER, 1, 0); - - if(Globals->FOOD_ITEMS_EXIST) { - // - // Check unit for possible food items. - // - CheckUnitMaintenance(0); - - // - // Fourth pass; check other units in same faction for food items - // - CheckFactionMaintenance(0); - } - - // - // Check unclaimed money. - // - { - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->needed > 0 && u->faction->unclaimed) { - /* Now see if faction has money */ - if (u->faction->unclaimed >= u->needed) { - u->Event(AString("Claims ") + u->needed + - " silver for maintenance."); - u->faction->unclaimed -= u->needed; - u->needed = 0; - } else { - u->Event(AString("Claims ") + - u->faction->unclaimed + - " silver for maintenance."); - u->needed -= u->faction->unclaimed; - u->faction->unclaimed = 0; - } - } - } - } - } - } - - // - // Check other allied factions for $$$. - // - CheckAllyMaintenanceItem(I_SILVER, 1); - if(Globals->FOOD_ITEMS_EXIST) { - // - // Check other factions for food items. - // - CheckAllyMaintenance(); - } - // - // Last, if the unit still needs money, starve some men. - // - { - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->needed > 0 || u->hunger > 0) - u->Short(u->needed, u->hunger); - } - } - } - } -} - -void Game::DoWithdrawOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *)elem; - forlist((&r->objects)) { - Object *obj = (Object *)elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - - forlist((&u->withdraworders)) { - WithdrawOrder *o = (WithdrawOrder *)elem; - if(DoWithdrawOrder(r, u, o)) break; - } - u->withdraworders.DeleteAll(); - - forlist_reuse((&u->wishdraworders)) { - WishdrawOrder *o = (WishdrawOrder *)elem; - if(DoWishdrawOrder(r, u, o)) break; - } - u->wishdraworders.DeleteAll(); - - forlist_reuse((&u->wishskillorders)) { - WishskillOrder *o = (WishskillOrder *)elem; - if(DoWishskillOrder(r, u, o)) break; - } - u->wishskillorders.DeleteAll(); - } - } - } -} - -int Game::DoWithdrawOrder(ARegion *r, Unit *u, WithdrawOrder *o) -{ - int itm = o->item; - int amt = o->amount; - int cost = (ItemDefs[itm].baseprice *5/2)*amt; - - if(r->type == R_NEXUS) { - u->Error("WITHDRAW: Withdraw does not work in the Nexus.", o->quiet); - return 1; - } - - if (cost > u->faction->unclaimed) { - u->Error(AString("WITHDRAW: Too little unclaimed silver to withdraw ")+ - ItemString(itm, amt)+".", o->quiet); - return 0; - } - - if (ItemDefs[itm].max_inventory) { - int cur = u->items.GetNum(itm) + amt; - if (cur > ItemDefs[itm].max_inventory) { - u->Error(AString("WITHDRAW: Unit cannot have more than ")+ - ItemString(itm, ItemDefs[itm].max_inventory), o->quiet); - return 0; - } - } - - u->faction->unclaimed -= cost; - u->Event(AString("Withdraws ") + ItemString(o->item, amt) + "."); - u->items.SetNum(itm, u->items.GetNum(itm) + amt); - u->faction->DiscoverItem(itm, 0, 1); - return 0; -} - -int Game::DoWishdrawOrder(ARegion *r, Unit *u, WishdrawOrder *o) -{ - int itm = o->item; - int amt = o->amount; - -/* //disable this check for a testgame! - if (!u->faction->IsNPC) { - u->Error(AString("WISHDRAW: This faction is not a NPC.")); - return 1; - } -*/ - - if (ItemDefs[itm].max_inventory) { - int cur = u->items.GetNum(itm) + amt; - if (cur > ItemDefs[itm].max_inventory) { - u->Error(AString("WISHDRAW: Unit cannot have more than ")+ - ItemString(itm, ItemDefs[itm].max_inventory), o->quiet); - return 0; - } - } - - u->Event(AString("Wishdraws ") + ItemString(o->item, amt) + "."); - u->items.SetNum(itm, u->items.GetNum(itm) + amt); - u->faction->DiscoverItem(itm, 0, 1); - return 0; -} - -int Game::DoWishskillOrder(ARegion *r, Unit *u, WishskillOrder *o) -{ - int sk = o->skill; - int days = o->knowledge * u->GetMen(); - int exper = o->experience * u->GetMen(); - -/* //disable this check for a testgame! - if (!u->faction->IsNPC) { - u->Error(AString("WISHDRAW: This faction is not a NPC.")); - return 1; - } -*/ - - if((SkillDefs[sk].flags & SkillType::MAGIC) && u->type != U_MAGE) { - if(u->type == U_APPRENTICE) { - u->Error("WISHSKILL: An apprentice cannot be made into an mage.", o->quiet); - return 0; - } - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - if (CountMages(u->faction) >= AllowedMages(u->faction)) { - u->Error("WISHSKILL: Can't have another magician.", o->quiet); - return 0; - } - } - if (u->GetMen() != 1) { - u->Error("WISHSKILL: Only 1-man units can be magicians.", o->quiet); - return 0; - } - if(!(Globals->MAGE_NONLEADERS)) { - if (u->IsLeader() != 1) { - u->Error("WISHSKILL: Only leaders may study magic.", o->quiet); - return 0; - } - } - u->type = U_MAGE; - } - - if((SkillDefs[sk].flags&SkillType::APPRENTICE) && - u->type != U_APPRENTICE) { - if(u->type == U_MAGE) { - u->Error("WISHSKILL: A mage cannot be made into an apprentice.", o->quiet); - return 0; - } - - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - if(CountApprentices(u->faction)>=AllowedApprentices(u->faction)) { - u->Error("WISHSKILL: Can't have another apprentice.", o->quiet); - return 0; - } - } - if(u->GetMen() != 1) { - u->Error("WISHSKILL: Only 1-man units can be apprentices.", o->quiet); - return 0; - } - if(!(Globals->MAGE_NONLEADERS)) { - if(u->IsLeader() != 1) { - u->Error("WISHSKILL: Only leaders may be apprentices.", o->quiet); - return 0; - } - } - u->type = U_APPRENTICE; - } - if ((Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) && - (sk == S_QUARTERMASTER) && (u->GetRealSkill(S_QUARTERMASTER) == 0) && - (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES)) { - if (CountQuarterMasters(u->faction) >= - AllowedQuarterMasters(u->faction)) { - u->Error("WISHSKILL: Can't have another quartermaster.", o->quiet); - return 0; - } - if(u->GetMen() != 1) { - u->Error("WISHSKILL: Only 1-man units can be quartermasters.", o->quiet); - return 0; - } - } - - if(Globals->SKILL_LIMIT_NONLEADERS && u->IsNormal()) { - if (u->skills.Num()) { - Skill * s = (Skill *) u->skills.First(); - if (s->type != sk) { - u->Error("WISHSKILL: Can know only 1 skill.", o->quiet); - return 0; - } - } - } - - u->skills.SetDays(sk, days, exper); - u->AdjustSkills(0); - - /* Check to see if we need to show a skill report */ - int lvl = u->GetRealSkill(sk); - int oldlvl = u->faction->skills.GetDays(sk); - if (lvl > oldlvl) { - for(int i=oldlvl+1; i<=lvl; i++) u->faction->shows.Add(new ShowSkill(sk, i)); - u->faction->skills.SetDays(sk, lvl); - } - u->Event("Wishskills unit"); - return 0; -} - -void Game::DoBankDepositOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *)elem; - forlist((&r->objects)) { - Object *obj = (Object *)elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->bankorders)) { - BankOrder *o = (BankOrder *)elem; - if (o->what == 2) // deposit - DoBankOrder(r, u, o); - } - } - } - } -} - -void Game::DoBankWithdrawOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *)elem; - forlist((&r->objects)) { - Object *obj = (Object *)elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->bankorders)) { - BankOrder *o = (BankOrder *)elem; - DoBankOrder(r, u, o); - } - u->bankorders.DeleteAll(); - } - } - } -} - -void Game::DoBankOrder(ARegion *r, Unit *u, BankOrder *o) -{ - int what = o->what; - int amt = o->amount; - int max;// = o->max; - int lvl;// = o->level; - int inbank;// = o->inbank; - int fee; - - if(r->type == R_NEXUS) { - u->Error("BANK: does not work in the Nexus.", o->quiet); - u->bankorders.Remove(o); - return; - } - if (!(SkillDefs[S_BANKING].flags & SkillType::DISABLED)) { // banking skill ? - lvl = u->GetSkill(S_BANKING); - } else { // skill disabled - pretend level 5 - lvl = 5; - } - if (!(ObjectDefs[O_OBANK].flags & ObjectType::DISABLED)) { // banks enabled ? - if (u->object->type != O_OBANK) // Are they in Bank ? - inbank = 0; // No they are not - else { // Yes they are in bank - if (u->object->incomplete > 0) // Is it completed ? - inbank = 0; // Not completed - else - inbank = 1; // Completed - } - if (inbank) - max = Globals->BANK_MAXSKILLPERLEVEL * lvl * inbank; - else - max = Globals->BANK_MAXUNSKILLED; - } else { // banks disabled - pretend they are in a bank - inbank = 1; - max = Globals->BANK_MAXSKILLPERLEVEL * lvl; - } - - if (!r->CanTax(u) && (Globals->ALLOW_BANK & GameDefs::BANK_NOTONGUARD)) { - if (ObjectDefs[O_OBANK].flags & ObjectType::DISABLED) { - // if banks are disabled, inbank will be 1, so ignore it - //FIXME - u->Error("BANK1: A unit is on guard - banking is not allowed.", o->quiet); - u->bankorders.Remove(o); - return; - } else { // pay attention to inbank - if (!inbank) { // if a unit is in a bank, then allow nevertheless - u->Error("BANK2: A unit is on guard - banking is not allowed.", o->quiet); //FIXME - u->bankorders.Remove(o); - return; - } - } - } - - if(!u->object->region->town && (Globals->ALLOW_BANK & GameDefs::BANK_INSETTLEMENT)) { - if (ObjectDefs[O_OBANK].flags & ObjectType::DISABLED) { // if banks are disabled, inbank will be 1, so ignore it - u->Error("BANK: Unit is not in a village, town or city.", o->quiet); - u->bankorders.Remove(o); - return; - } else { // pay attention to inbank - if (!inbank) { // if a unit is in a bank, then allow nevertheless - u->Error("BANK: Unit is not in a village, town or city.", o->quiet); - u->bankorders.Remove(o); - return; - } - } - } - - if ((amt > u->faction->bankaccount) && (what == 1)) { - u->Error(AString("BANK: Too little silver in the bank to withdraw."), o->quiet); - u->bankorders.Remove(o); - return; - } - if (what == 1) { // withdraw - if (amt > max) { - AString temp = "BANK: Withdrawal limited to "; - temp += max; - temp += " silver."; - u->Error(temp, o->quiet); - amt = max; - } - } else { // deposit - if (u->items.GetNum(I_SILVER) == 0) { - u->Error(AString("BANK: No silver available."), o->quiet); - u->bankorders.Remove(o); - return; - } else { - if (amt > max) { - AString temp = "BANK: Deposit limited to "; - temp += max; - temp += " silver."; - u->Error(temp, o->quiet); - amt = max; - } - if (u->items.GetNum(I_SILVER) < amt) - amt = u->items.GetNum(I_SILVER); - } - } - if (Globals->ALLOW_BANK & GameDefs::BANK_FEES) - fee = (amt * Globals->BANK_FEE)/100; - else - fee = 0; - AString temp; - if (what == 2) - temp += "Deposits "; - else - temp += "Withdraws "; - temp += amt - fee; - if (what == 2) - temp += " in"; - else - temp += " from"; - temp += " the bank"; - if (Globals->ALLOW_BANK & GameDefs::BANK_FEES) { - temp += " (fees "; - temp += fee; - temp += ")"; - } - temp += "."; - u->Event(temp); - if (what == 2) {// deposit - u->faction->bankaccount += amt - fee; - u->items.SetNum(I_SILVER, u->items.GetNum(I_SILVER) - amt); - } else { // withdrawal - u->faction->bankaccount -= amt; - u->items.SetNum(I_SILVER, u->items.GetNum(I_SILVER) + amt - fee); - } - - u->bankorders.Remove(o); - return; -} - -void Game::DoGiveOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->giveorders)) { - GiveOrder *o = (GiveOrder *)elem; - if(o->item < 0) { - if (o->amount == -1) { - /* do 'give X unit' command */ - DoGiveOrder(r, u, o); - } else if (o->amount == -2) { - /* do 'give all type' command */ - forlist((&u->items)) { - Item *item = (Item *)elem; - if((o->item == -NITEMS) || - (ItemDefs[item->type].type & (-o->item))) { - GiveOrder go; - go.amount = item->num; - go.except = 0; - go.item = item->type; - go.target = o->target; - go.type = o->type; - DoGiveOrder(r, u, &go); - go.target = NULL; - } - } - } else { - u->Error("GIVE: Invalid item.", o->quiet); - } - } else if (DoGiveOrder(r, u, o)) { - break; - } - } - u->giveorders.DeleteAll(); - } - } - } -} - -void Game::DoSendOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->sendorders)) { - SendOrder *o = (SendOrder *)elem; - if(o->item < 0) { - if (o->amount == -2) { - /* do 'send all type' command */ - forlist((&u->items)) { - Item *item = (Item *)elem; - if( ((o->item == -NITEMS) || - (ItemDefs[item->type].type & (-o->item))) && - !(ItemDefs[item->type].type & IT_MAN) && - !(ItemDefs[item->type].type & IT_MONSTER) && - !(ItemDefs[item->type].type & IT_ILLUSION)) { - SendOrder so; - so.amount = item->num; - so.except = 0; - so.item = item->type; - so.target = o->target; - so.direction = o->direction; - so.type = o->type; - DoSendOrder(r, u, &so); - so.target = NULL; - } - } - } else { - u->Error("SEND: Invalid item.", o->quiet); - } - } else if (DoSendOrder(r, u, o)) { - break; - } - } - u->sendorders.DeleteAll(); - } - } - } -} - - -void Game::RecieveSentGoods() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if(u->itemsintransit.Num()) { - forlist(&u->itemsintransit) { - Item *i = (Item *) elem; - u->items.SetNum(i->type,u->items.GetNum(i->type) + i->num); - } - u->itemsintransit.DeleteAll(); - } - } - } - } -} - -void Game::DoExchangeOrders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - forlist((&u->exchangeorders)) { - Order *o = (Order *) elem; - DoExchangeOrder(r, u, (ExchangeOrder *) o); - } - } - } - } -} - -void Game::DoExchangeOrder(ARegion *r, Unit *u, ExchangeOrder *o) -{ - // Check if the destination unit exists - Unit *t = r->GetUnitId(o->target, u->faction->num); - if (!t) { - u->Error(AString("EXCHANGE: Nonexistent target (") + - o->target->Print() + ").", o->quiet); - u->exchangeorders.Remove(o); - return; - } - - // Check each Item can be given - if(ItemDefs[o->giveItem].flags & ItemType::CANTGIVE) { - u->Error(AString("EXCHANGE: Can't trade ") + - ItemDefs[o->giveItem].names + ".", o->quiet); - u->exchangeorders.Remove(o); - return; - } - - if(ItemDefs[o->expectItem].flags & ItemType::CANTGIVE) { - u->Error(AString("EXCHANGE: Can't trade ") + - ItemDefs[o->expectItem].names + ".", o->quiet); - u->exchangeorders.Remove(o); - return; - } - - if (ItemDefs[o->giveItem].type & IT_MAN) { - u->Error("EXCHANGE: Exchange aborted. Men may not be traded.", o->quiet); - u->exchangeorders.Remove(o); - return; - } - - if (ItemDefs[o->expectItem].type & IT_MAN) { - u->Error("EXCHANGE: Exchange aborted. Men may not be traded.", o->quiet); - u->exchangeorders.Remove(o); - return; - } - - // New RULE -- Must be able to see unit to give something to them! - if(!u->CanSee(r, t)) { - u->Error(AString("EXCHANGE: Nonexistent target (") + - o->target->Print() + ").", o->quiet); - return; - } - // Check other unit has enough to give - //This is not compatible to item-sharing because the shared items may be traded with others before the exchange is executed. - //In fact, this applies to normal Atlantis too, as the items could be exchanged before the opposing exchange order is met - so there is a bug in the original code here -/* int amtRecieve = o->expectAmount; - if (amtRecieve > t->items.GetNum(o->expectItem)) { - t->Error(AString("EXCHANGE: Not giving enough. Expecting ") + - ItemString(o->expectItem, o->expectAmount) + "."); - u->Error(AString("EXCHANGE: Exchange aborted. Not enough ") + - "recieved. Expecting " + - ItemString(o->expectItem, o->expectAmount) + "."); - o->exchangeStatus = 0; - return; - }*/ - - //exchange status is initially -1 - int exchangeOrderFound = 0; - // Check if other unit has a reciprocal exchange order - forlist ((&t->exchangeorders)) { - ExchangeOrder *tOrder = (ExchangeOrder *) elem; - Unit *ptrUnitTemp = r->GetUnitId(tOrder->target, t->faction->num); - if (ptrUnitTemp == u) { - if (tOrder->expectItem == o->giveItem) { - if (tOrder->giveItem == o->expectItem) { - exchangeOrderFound = 1; - if (tOrder->giveAmount < o->expectAmount) { - t->Error(AString("EXCHANGE: Not giving enough. ") + - "Expecting " + - ItemString(o->expectItem, o->expectAmount) + - ".", o->quiet); - u->Error(AString("EXCHANGE: Exchange aborted. ") + - "Not enough recieved. Expecting " + - ItemString(o->expectItem, o->expectAmount) + - ".", o->quiet); - tOrder->exchangeStatus = 0; - o->exchangeStatus = 0; - return; - } else if (tOrder->giveAmount > o->expectAmount) { - t->Error(AString("EXCHANGE: Exchange aborted. Too ") + - "much given. Expecting " + - ItemString(o->expectItem, o->expectAmount) + - ".", o->quiet); - u->Error(AString("EXCHANGE: Exchange aborted. Too ") + - "much offered. Expecting " + - ItemString(o->expectItem, o->expectAmount) + - ".", o->quiet); - tOrder->exchangeStatus = 0; - o->exchangeStatus = 0; - } else if (tOrder->giveAmount == o->expectAmount) - o->exchangeStatus = 1; - - if ((o->exchangeStatus == 1) && - (tOrder->exchangeStatus == 1) && - u->GetSharedNum(o->giveItem, o->giveAmount) && - t->GetSharedNum(tOrder->giveItem, tOrder->giveAmount)) { - u->Event(AString("Exchanges ") + - ItemString(o->giveItem, o->giveAmount) + - " with " + *t->name + " for " + - ItemString(tOrder->giveItem, - tOrder->giveAmount) + - "."); - t->Event(AString("Exchanges ") + - ItemString(tOrder->giveItem, - tOrder->giveAmount) + " with " + - *u->name + " for " + - ItemString(o->giveItem, o->giveAmount) + "."); - u->ConsumeShared(o->giveItem, o->giveAmount); - t->items.SetNum(o->giveItem, t->items.GetNum(o->giveItem) + o->giveAmount); - t->ConsumeShared(tOrder->giveItem, tOrder->giveAmount); - u->items.SetNum(tOrder->giveItem, - u->items.GetNum(tOrder->giveItem) + - tOrder->giveAmount); - u->faction->DiscoverItem(tOrder->giveItem, 0, 1); - t->faction->DiscoverItem(o->giveItem, 0, 1); - u->exchangeorders.Remove(o); - t->exchangeorders.Remove(tOrder); - return; - } else if ((o->exchangeStatus >= 0) && - (tOrder->exchangeStatus >= 0)) { - u->exchangeorders.Remove(o); - t->exchangeorders.Remove(tOrder); - } - } - } - } - } - if (!exchangeOrderFound) { - if(!u->CanSee(r, t)) { - u->Error(AString("EXCHANGE: Nonexistent target (") + - o->target->Print() + ").", o->quiet); - u->exchangeorders.Remove(o); - return; - } else { - u->Error("EXCHANGE: target unit did not issue a matching " - "exchange order.", o->quiet); - u->exchangeorders.Remove(o); - return; - } - } -} - -int Game::DoGiveOrder(ARegion *r, Unit *u, GiveOrder *o) -{ - // Check there is enough to give - int amt = o->amount; - if (amt != -2 && amt > u->items.GetNum(o->item)) { - u->Error("GIVE: Not enough.", o->quiet); - amt = u->items.GetNum(o->item); - } else if (amt == -2) { - amt = u->items.GetNum(o->item); - if(o->except) { - if(o->except > amt) { - amt = 0; - u->Error("GIVE: EXCEPT value greater than amount on hand.", o->quiet); - } else { - amt = amt - o->except; - } - } - } - - if (o->target->unitnum == -1) { - /* Give 0 */ - if (amt == -1) { - Faction *civfac = GetFaction(&factions, peasantfaction); - if(!civfac) { - u->Error("Can't discard a whole unit.", o->quiet); - return 0; - } - u->Event(AString("Gives unit to ") + *(civfac->name) + "."); - u->faction = civfac; - u->Event("Is given to your faction."); - u->guard = GUARD_AVOID; - u->reveal = REVEAL_FACTION; - AString *temp = new AString("Peasantfolk"); - u->SetName(temp); - u->ClearOrders(); - return 1; //returning 1 means it does no further give orders. - } - - if (amt < 0) { - u->Error("Cannot give a negative number of items.", o->quiet); - return 0; - } - - if(ItemDefs[o->item].flags & ItemType::NEVERLOST) { - u->Error("Cannot discard that item.", o->quiet); - return 0; - } - - AString temp = "Discards "; - if (ItemDefs[o->item].type & IT_MAN) { - u->SetMen(o->item, u->GetMen(o->item) - amt); - r->DisbandInRegion(o->item, amt); - temp = "Disbands "; - } else if(Globals->RELEASE_MONSTERS && - (ItemDefs[o->item].type & IT_MONSTER)) { - temp = "Releases "; - u->items.SetNum(o->item, u->items.GetNum(o->item) - amt); - if(Globals->WANDERING_MONSTERS_EXIST) { - Faction *mfac = GetFaction(&factions, monfaction); - Unit *mon = GetNewUnit(mfac, 0); - MonType *mp = FindMonster(ItemDefs[o->item].abr, - (ItemDefs[o->item].type & IT_ILLUSION)); - mon->MakeWMon(mp->name, o->item, amt); - mon->MoveUnit(r->GetDummy()); - // This will result in 0 unless MONSTER_NO_SPOILS or - // MONSTER_SPOILS_RECOVERY are set. - mon->free = Globals->MONSTER_NO_SPOILS + - Globals->MONSTER_SPOILS_RECOVERY; - } - } else { - u->items.SetNum(o->item, u->items.GetNum(o->item) - amt); - } - u->Event(temp + ItemString(o->item, amt) + "."); - return 0; - } - - Unit *t = r->GetUnitId(o->target, u->faction->num); - if (!t) { - u->Error(AString("GIVE: Nonexistent target (") + o->target->Print() + - ").", o->quiet); - return 0; - } - - if(u == t) { - u->Error(AString("GIVE: Attempt to give ")+ItemString(o->item, amt)+ - " to self.", o->quiet); - return 0; - } - - // New RULE -- Must be able to see unit to give something to them! - if(!u->CanSee(r, t) && - (t->faction->GetAttitude(u->faction->num) < A_FRIENDLY)) { - u->Error(AString("GIVE: Nonexistent target (") + o->target->Print() + - ").", o->quiet); - return 0; - } - - if (o->item != I_SILVER && - t->faction->GetAttitude(u->faction->num) < A_FRIENDLY) { - //This eliminates guards, monsters, ghosts and peasant factions. - u->Error("GIVE: Target is not a member of a friendly faction.", o->quiet); - return 0; - } - - - if (amt == -1) { - /* Give unit */ - if(u->GetFlag(FLAG_COMMANDER)) { - u->Error("GIVE: Cannot GIVE your commanding unit."); - return 0; - } - if (u->type == U_MAGE) { - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - if (CountMages(t->faction) >= AllowedMages(t->faction)) { - u->Error("GIVE: Faction has too many mages.", o->quiet); - return 0; - } - } - } - if(u->type == U_APPRENTICE) { - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - if(CountApprentices(t->faction) >= - AllowedApprentices(t->faction)){ - u->Error("GIVE: Faction has too many apprentices.", o->quiet); - return 0; - } - } - } - - if (u->GetRealSkill(S_QUARTERMASTER)) { - if (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - if (Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT) { - if (CountQuarterMasters(t->faction) >= - AllowedQuarterMasters(t->faction)) { - u->Error("GIVE: Faction has too many quartermasters.", o->quiet); - return 0; - } - } - } - } - - if (u->GetRealSkill(S_TACTICS) == 5) { - if (Globals->FACTION_LIMIT_TYPE == GameDefs::FACLIM_FACTION_TYPES) { - if (Globals->TACTICS_NEEDS_WAR) { - if (CountTacticians(t->faction) >= - AllowedTacticians(t->faction)) { - u->Error("GIVE: Faction has too many tacticians.", o->quiet); - return 0; - } - } - } - } - - int notallied = 1; - if (t->faction->GetAttitude(u->faction->num) == A_ALLY) { - notallied = 0; - } - - u->Event(AString("Gives unit to ") + *(t->faction->name) + "."); - u->faction = t->faction; - u->Event("Is given to your faction."); - - if (notallied && u->monthorders && u->monthorders->type == O_MOVE && - ((MoveOrder *) u->monthorders)->advancing) { - u->Error("Unit cannot advance after being given.", 0); - delete u->monthorders; - u->monthorders = 0; - } - - /* Check if any new skill reports have to be shown */ - forlist(&(u->skills)) { - Skill *skill = (Skill *) elem; - int newlvl = u->GetRealSkill(skill->type); - int oldlvl = u->faction->skills.GetDays(skill->type); - if (newlvl > oldlvl) { - for (int i=oldlvl+1; i<=newlvl; i++) { - u->faction->shows.Add(new ShowSkill(skill->type, i)); - } - u->faction->skills.SetDays(skill->type, newlvl); - } - } - - // Okay, not for each item that the unit has, tell the new faction - // about it in case they don't know about it yet. - { - forlist(&u->items) { - Item *i = (Item *)elem; - u->faction->DiscoverItem(i->type, 0, 1); - } - } - - return notallied; //if it returns 1, it does no further give orders. - } - - int newtype = -1; - - /* If the item to be given is a man, combine skills */ - if (ItemDefs[o->item].type & IT_MAN) { - if (u->type == U_MAGE || u->type == U_APPRENTICE || - t->type == U_MAGE || t->type == U_APPRENTICE) { - u->Error("GIVE: Heroes can't give or recieve men.", o->quiet); - return 0; - } - if (u->type != t->type) { - if(t->GetMen()) { - //changed for new leader handling - u->Error("GIVE: Can't mix leaders and normal men.", o->quiet); - return 0; - } else { - newtype = u->type; - } - } - - // Small hack for Ceran - if(o->item == I_MERC && t->GetMen()) { - u->Error("GIVE: Can't mix mercenaries with other men.", o->quiet); - return 0; - } - - if (u->faction != t->faction) { - u->Error("GIVE: Can't give men to another faction.", o->quiet); //would be nice to be able to give men to a unit which you have just given to another faction - return 0; - } - - if (u->nomove) t->nomove = 1; - - SkillList *temp = u->skills.Split(u->GetMen(), amt); //Is it really a good idea to do this here, when men could potentially be labelled as cantgive or max_inventory below? - t->skills.Combine(temp); - delete temp; - - //mark which units men have gone to. - UnitId *id = new UnitId; - id->unitnum = t->num; - if(o->target) id->alias = o->target->alias; - else id->alias = 0; - id->faction = t->faction->num; - u->gavemento.Add(id); - } - - if(ItemDefs[o->item].flags & ItemType::CANTGIVE) { - u->Error(AString("GIVE: Can't give ") + ItemDefs[o->item].names + ".", o->quiet); - return 0; - } - - if (ItemDefs[o->item].max_inventory) { - int cur = t->items.GetNum(o->item) + amt; - if (cur > ItemDefs[o->item].max_inventory) { - u->Error(AString("GIVE: Unit cannot have more than ")+ - ItemString(o->item, ItemDefs[o->item].max_inventory), o->quiet); - return 0; - } - } - - u->Event(AString("Gives ") + ItemString(o->item, amt) + " to " + - *t->name + "."); - if (u->faction != t->faction) { - t->Event(AString("Receives ") + ItemString(o->item, amt) + - " from " + *u->name + "."); - } - u->items.SetNum(o->item, u->items.GetNum(o->item) - amt); - t->items.SetNum(o->item, t->items.GetNum(o->item) + amt); - t->faction->DiscoverItem(o->item, 0, 1); - - if (ItemDefs[o->item].type & IT_MAN) { - if(newtype != -1) t->type = newtype; - t->AdjustSkills(); //no overflow when acquiring new men into a unit - } - return 0; -} - -int Sqrt(int input) -{ - int num = 1; - while(num*num <= input && num < 1000) num++; - return(num-1); - - //if input is 0 or less, returns 0. -} - - -int Game::DoSendOrder(ARegion *r, Unit *u, SendOrder *o) -{ - // Check there is enough to send - int amt = o->amount; - if (amt != -2 && amt > u->GetSharedNum(o->item)) { - amt = u->GetSharedNum(o->item); - u->Error(AString("SEND: Not enough. Sending ") + ItemString(o->item, amt) + " instead.", o->quiet); - } else if (amt == -2) { - amt = u->items.GetNum(o->item); //if sending "ALL" do not check other inventories. - if(o->except) { - if(o->except > amt) { - amt = 0; - u->Error("SEND: EXCEPT value greater than amount on hand.", o->quiet); - return 0; - } else { - amt = amt - o->except; - } - } - } - - Unit *tar = NULL; - ARegion *reg; - if(o->direction >= 0) { - if(o->direction < NDIRS && r->neighbors[o->direction]) - reg = r->neighbors[o->direction]; - else if(o->direction == MOVE_IN) { - if(u->object->inner >= 0) { - reg = regions.GetRegion(u->object->inner); - } else { - u->Error("SEND: Cannot send IN there.", o->quiet); - return 0; - } - } else if(o->direction > MOVE_ENTER) { - int inreg = r->GetObject(o->direction - MOVE_ENTER)->inner; - if(inreg < 0) { - u->Error("SEND: Cannot send IN that.", o->quiet); - return 0; - } else reg = regions.GetRegion(inreg); - } - if(!reg) { - u->Error("SEND: No region in that direction.", o->quiet); - return 0; - } - //we now have the specified region 'reg'. - if(o->target) { - tar = reg->GetUnitId(o->target, u->faction->num); - } else { - //no specified target unit! - forlist(®->objects) { - Object *o = (Object *) elem; - if(tar) continue; - forlist(&o->units) { - Unit *unit = (Unit *) elem; - if (unit->faction == u->faction && unit->IsStationary()) { - tar = unit; - break; - } - } - } - } - if(!tar) { - u->Error("SEND: No unit in that direction able to recieve sent goods"); - return 0; - } - } else { - //try all directions for target unit - int i=0; - while(ineighbors[i]) - tar = r->neighbors[i]->GetUnitId(o->target, u->faction->num); - i++; - } - if(tar) { - //setting up reg and direction for later - o->direction = i-1; - reg = r->neighbors[i-1]; - } - } - int cost = 0; - Unit *bestquartermaster = NULL; - if (o->via || (!tar && o->target) ) { - Location *target = regions.GetUnitId(o->target, u->faction->num, r); - Location *quartermaster = NULL; - - if(o->via) quartermaster = regions.GetUnitId(o->via, u->faction->num, r); - int level = 0; - if(u->GetSkill(S_ARCADIA_QUARTERMASTERY) > level) { - level = u->GetSkill(S_ARCADIA_QUARTERMASTERY); - bestquartermaster = u; - } - if(target && target->unit->GetSkill(S_ARCADIA_QUARTERMASTERY) > level) { - level = target->unit->GetSkill(S_ARCADIA_QUARTERMASTERY); - bestquartermaster = target->unit; - } - if(quartermaster && quartermaster->unit->GetSkill(S_ARCADIA_QUARTERMASTERY) > level) { - level = quartermaster->unit->GetSkill(S_ARCADIA_QUARTERMASTERY); //is ok to use other level if greater, as that is equivalent to not using the VIA command at all ... - bestquartermaster = quartermaster->unit; - } - if(!level || !target) { - //the target is not adjacent, and no-one has a quartermastery skill. - if(target) delete target; - if(quartermaster) delete quartermaster; - u->Error(AString("SEND: Cannot find target ") + o->target->unitnum + " or target is not a member of a friendly faction", o->quiet); - return 0; - } - //we now have a SEND order using the QUARTERMASTERY skill. - if (quartermaster && quartermaster->unit->faction->GetAttitude(u->faction->num) < A_FRIENDLY) { - //This eliminates guards, monsters, ghosts and peasant factions. - //These errors all have to be the same to prevent any way of players finding the location of stealth units. - u->Error(AString("SEND: Cannot find target ") + o->via->unitnum + " or target is not a member of a friendly faction", o->quiet); - delete target; - if(quartermaster) delete quartermaster; - return 0; - } - if(quartermaster && level < 4) { - u->Error("SEND: Insufficient quartermastery level to use VIA", o->quiet); - delete target; - if(quartermaster) delete quartermaster; - return 0; - } - - if (quartermaster && !quartermaster->unit->IsStationary()) { - u->Error(AString("SEND: Cannot send goods via a moving unit."), o->quiet); - delete target; - if(quartermaster) delete quartermaster; - return 0; - } - // Need to check the ranges - // make sure target is in range. - int dist = regions.GetDistance(r, target->region); - if(quartermaster) dist = regions.GetDistance(r,quartermaster->region)+regions.GetDistance(quartermaster->region,target->region); - if (dist > level) { - u->Error("SEND: Target is too far away.", o->quiet); - delete target; - if(quartermaster) delete quartermaster; - return 0; - } - - //all done, set up for final code. - tar = target->unit; - delete target; - if(quartermaster) delete quartermaster; - } else { - //need to stick in here any checks that DO NOT apply to QUARTERMASTERY skilled transfers. - - //we now have the target unit 'tar', which is stationary, the item 'o->item', - //the amount 'amt' and the target region 'reg'. We should now transfer it. - //Check if the target hex can be walked to. - int level = u->GetSkill(S_ARCADIA_QUARTERMASTERY); - if(level) bestquartermaster = u; - if( tar->GetSkill(S_ARCADIA_QUARTERMASTERY) > level) { - level = tar->GetSkill(S_ARCADIA_QUARTERMASTERY); - bestquartermaster = tar; - } - - int multiplier = 1; - cost = reg->MoveCost(M_WALK, r, o->direction, 0); //movement cost - if(cost < 0 && !level) { - u->Error(AString("SEND: Intervening terrain blocks sending."), o->quiet); - return 0; - } - if(cost > Globals->FOOT_SPEED) multiplier = 2; - if((cost > Globals->HORSE_SPEED) && !level) { - u->Error(AString("SEND: Target region cannot be ridden to."), o->quiet); - return 0; - } - - int weight = Sqrt(ItemDefs[o->item].weight - ItemDefs[o->item].walk); - if(multiplier > 1) weight = Sqrt(ItemDefs[o->item].weight - ItemDefs[o->item].ride); - // if(weight < 1) weight = 1; //this makes weightless items cost money to send - - cost = amt*weight*multiplier*Globals->SEND_COST; //silver cost - if(level) cost = 0; //quartermasters get free transport. - } - if (tar->faction->GetAttitude(u->faction->num) < A_FRIENDLY) { - //This eliminates guards, monsters, ghosts and peasant factions. - u->Error("SEND: Cannot find target or target is not a member of a friendly faction", o->quiet); - return 0; - } - - if (!tar->IsStationary()) { - u->Error(AString("SEND: Cannot send goods to a moving unit."), o->quiet); - return 0; - } - - //last minute checks that item type is ok. Should never be needed, but just in case. - if( (ItemDefs[o->item].flags & ItemType::CANTGIVE) || - (ItemDefs[o->item].type & IT_MAN) || - (ItemDefs[o->item].type & IT_MONSTER) || - (ItemDefs[o->item].type & IT_ILLUSION) ) { - u->Error(AString("SEND: Can't send ") + ItemDefs[o->item].names + ".", o->quiet); - return 0; - } - if (ItemDefs[o->item].max_inventory) { - int cur = tar->items.GetNum(o->item) + tar->itemsintransit.GetNum(o->item) + amt; - if (cur > ItemDefs[o->item].max_inventory) { - u->Error(AString("SEND: Target unit cannot have more than ")+ - ItemString(o->item, ItemDefs[o->item].max_inventory), o->quiet); - return 0; - } - } - - //cost is zero if a quartermaster transfer! - if(!u->GetSharedMoney(cost)) { - u->Error(AString("SEND: Not enough silver to SEND that."), o->quiet); - return 0; - } //don't forget to double count if sending silver and also paying with it: - if(o->item == I_SILVER && cost+amt > u->GetSharedNum(I_SILVER)) { - u->Error(AString("SEND: Not enough silver to SEND that."), o->quiet); - return 0; - } - - u->ConsumeSharedMoney(cost); //pays SEND cost - - u->Event(AString("Sends ") + ItemString(o->item, amt) + " to " + - *tar->name + " at a cost of " + cost + " silver."); - if(u->faction != tar->faction) tar->Event(AString("Is sent ") + ItemString(o->item, amt) + - " from " + *u->name); - u->ConsumeShared(o->item, amt); - tar->itemsintransit.SetNum(o->item, tar->itemsintransit.GetNum(o->item) + amt); - tar->faction->DiscoverItem(o->item, 0, 1); - - if(bestquartermaster) bestquartermaster->numquartermastered += amt*ItemDefs[o->item].baseprice; - - return 0; -} - -void Game::DoGuard1Orders() -{ - forlist((®ions)) { - ARegion *r = (ARegion *) elem; - forlist((&r->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->guard == GUARD_SET || u->guard == GUARD_GUARD) { - if (!u->Taxers(1)) { - u->guard = GUARD_NONE; - u->Error("Must be combat ready to be on guard."); - continue; - } - if (u->type != U_GUARD && r->HasCityGuard()) { - u->guard = GUARD_NONE; - u->Error("Is prevented from guarding by the " - "Guardsmen."); - continue; - } - u->guard = GUARD_GUARD; - } - } - } - } -} - -void Game::FindDeadFactions() -{ - forlist((&factions)) { - ((Faction *) elem)->CheckExist(®ions); - } -} - -void Game::DeleteEmptyUnits() -{ - forlist((®ions)) { - ARegion *region = (ARegion *) elem; - DeleteEmptyInRegion(region); - } -} - -void Game::DeleteEmptyInRegion(ARegion *region) -{ - forlist(®ion->objects) { - Object *obj = (Object *) elem; - forlist (&obj->units) { - Unit *unit = (Unit *) elem; - if (unit->IsAlive() == 0) { //don't want to discard mages here, so don't use "reallyalive"! if no men, then returns 0 anyway. - region->Kill(unit); - } - } - } -} - -void Game::CheckTransportOrders() -{ - if (!(Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT)) - return; - - forlist ((®ions)) { - ARegion *r = (ARegion *)elem; - forlist((&r->objects)) { - Object *obj = (Object *)elem; - forlist((&obj->units)) { - Unit *u = (Unit *)elem; - forlist ((&u->transportorders)) { - // make sure target exists - TransportOrder *o = (TransportOrder *)elem; - AString ordertype = - (o->type == O_DISTRIBUTE) ? "DISTRIBUTE" : - "TRANSPORT"; - if (!o->target || o->target->unitnum == -1) { - u->Error(ordertype + ": Target does not exist.", o->quiet); - o->type = NORDERS; - continue; - } - - Location *tar = regions.GetUnitId(o->target, - u->faction->num, r); - if (!tar) { - u->Error(ordertype + ": Target does not exist.", o->quiet); - o->type = NORDERS; - continue; - } - - // Make sure target isn't self - if (tar->unit == u) { - u->Error(ordertype + ": Target is self.", o->quiet); - o->type = NORDERS; - continue; - } - - // Make sure the target and unit are at least friendly - if (tar->unit->faction->GetAttitude(u->faction->num) < - A_FRIENDLY) { - u->Error(ordertype + - ": Target is not a member of a friendly " - "faction.", o->quiet); - o->type = NORDERS; - continue; - } - - // Make sure the target of a transport order is a unit - // with the quartermaster skill who owns a transport - // structure - if (o->type == O_TRANSPORT) { - if (tar->unit->GetSkill(S_QUARTERMASTER) == 0) { - u->Error(ordertype + - ": Target is not a quartermaster", o->quiet); - o->type = NORDERS; - continue; - } - if ((tar->obj->GetOwner() != tar->unit) || - !(ObjectDefs[tar->obj->type].flags & - ObjectType::TRANSPORT) || - (tar->obj->incomplete > 0)) { - u->Error(ordertype + ": Target does not own " - "a transport structure.", o->quiet); - o->type = NORDERS; - continue; - } - } - - // make sure target is in range. - int maxdist; - int dist = regions.GetDistance(r, tar->region); - if ((o->type == O_TRANSPORT) && - (u == obj->GetOwner()) && - (ObjectDefs[obj->type].flags & ObjectType::TRANSPORT)) { - maxdist = Globals->NONLOCAL_TRANSPORT; - if (maxdist >= 0 && - Globals->TRANSPORT & GameDefs::QM_AFFECT_DIST) { - int level = u->GetSkill(S_QUARTERMASTER); - maxdist += ((level + 1)/3); - } else if (maxdist == 0) - maxdist = 10000000; - } else - maxdist = Globals->LOCAL_TRANSPORT; - if (dist > maxdist) { - u->Error(ordertype + ": Recipient is too far away.", o->quiet); - o->type = NORDERS; - continue; - } - - // On long range transport or distribute, make sure the - // issuer is a quartermaster and is owner of a structure - if ((o->type == O_DISTRIBUTE) || - ((dist > Globals->LOCAL_TRANSPORT) && - (o->type == O_TRANSPORT))) { - if (u->GetSkill(S_QUARTERMASTER == 0)) { - u->Error(ordertype + - ": Unit is not a quartermaster", o->quiet); - o->type = NORDERS; - continue; - } - if ((u != obj->GetOwner()) || - !(ObjectDefs[obj->type].flags & - ObjectType::TRANSPORT) || - (obj->incomplete > 0)) { - u->Error(ordertype + - ": Unit does not own transport structure.", o->quiet); - o->type = NORDERS; - continue; - } - } - - // make sure amount is available (all handled later) - if (o->amount > 0 && o->amount > u->items.GetNum(o->item)) { - u->Error(ordertype + ": Not enough.", o->quiet); - o->type = NORDERS; - continue; - } - - if (o->amount > 0 && ItemDefs[o->item].max_inventory) { - int cur = tar->unit->items.GetNum(o->item) + o->amount; - if (cur > ItemDefs[o->item].max_inventory) { - u->Error(ordertype + - ": Target cannot have more than " + - ItemString(o->item, - ItemDefs[o->item].max_inventory), o->quiet); - o->type = NORDERS; - continue; - } - } - - // Check if we have a trade hex - if (!TradeCheck(r, u->faction)) { - u->Error(ordertype + ": Faction cannot transport or " - "distribute in that many hexes.", o->quiet); - o->type = NORDERS; - continue; - } - } - } - } - } -} - -void Game::RunTransportOrders() -{ - if (!(Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT)) - return; - forlist ((®ions)) { - ARegion *r = (ARegion *)elem; - forlist((&r->objects)) { - Object *obj = (Object *)elem; - forlist((&obj->units)) { - Unit *u = (Unit *)elem; - forlist ((&u->transportorders)) { - TransportOrder *t = (TransportOrder *)elem; - if (t->type != O_TRANSPORT && t->type != O_DISTRIBUTE) - continue; - Location *tar = regions.GetUnitId(t->target, - u->faction->num, r); - if (!tar) continue; - AString ordertype = (t->type == O_TRANSPORT) ? - "TRANSPORT" : "DISTRIBUTE"; - - int amt = t->amount; - if (amt < 0) { - amt = u->items.GetNum(t->item); - if (t->except) { - if (t->except > amt) { - amt = 0; - u->Error(ordertype + - ": EXCEPT value greater than amount " - "on hand.", t->quiet); - } else { - amt = amt - t->except; - } - } - } else if (amt > u->items.GetNum(t->item)) { - u->Error(ordertype + ": Not enough.", t->quiet); - amt = u->items.GetNum(t->item); - } - - if (ItemDefs[t->item].max_inventory) { - int cur = tar->unit->items.GetNum(t->item) + amt; - if (cur > ItemDefs[t->item].max_inventory) { - u->Error(ordertype + - ": Target cannot have more than " + - ItemString(t->item, - ItemDefs[t->item].max_inventory), t->quiet); - continue; - } - } - - u->items.SetNum(t->item, u->items.GetNum(t->item) - amt); - // now see if the unit can pay for shipping - int dist = regions.GetDistance(r, tar->region); - int weight = ItemDefs[t->item].weight * amt; - if (weight == 0 && Globals->FRACTIONAL_WEIGHT > 0) - weight = (amt/Globals->FRACTIONAL_WEIGHT) + 1; - int cost = 0; - if (dist > Globals->LOCAL_TRANSPORT) { - cost = Globals->SHIPPING_COST * weight; - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_COST) - cost *= (4 - ((u->GetSkill(S_QUARTERMASTER)+1)/2)); - } - - // if not, give it back - if (cost > u->items.GetNum(I_SILVER)) { - u->Error(ordertype + ": Cannot afford shipping cost.", t->quiet); - u->items.SetNum(t->item, u->items.GetNum(t->item)+amt); - continue; - } - u->items.SetNum(I_SILVER, u->items.GetNum(I_SILVER) - cost); - - ordertype = (t->type == O_TRANSPORT) ? - "Transports " : "Distributes "; - u->Event(ordertype + ItemString(t->item, amt) + " to " + - *tar->unit->name + " for $" + cost + "."); - if (u->faction != tar->unit->faction) { - tar->unit->Event(AString("Receives ") + - ItemString(t->item, amt) + " from " + - *u->name + "."); - } - - tar->unit->items.SetNum(t->item, - tar->unit->items.GetNum(t->item) + amt); - tar->unit->faction->DiscoverItem(t->item, 0, 1); - - u->Practice(S_QUARTERMASTER); - u->Experience(S_QUARTERMASTER,10); - - } - u->transportorders.DeleteAll(); - } - } - } -} -// Shouldn't the locations be deleted? - diff --git a/arcadia/shields.cpp b/arcadia/shields.cpp deleted file mode 100644 index ab15183ca..000000000 --- a/arcadia/shields.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "army1.h" - -Shield * ShieldList::GetHighShield(int type) -{ - Shield * hi = 0; - forlist(this) { - Shield * sh = (Shield *) elem; - if (sh->shieldtype == type) { - if (!hi) { - hi = sh; - } else { - if (sh->shieldskill > hi->shieldskill) - hi = sh; - } - } - } - return hi; -} - -void Army::DowngradeShield(Shield *hi) -{ - hi->shieldskill--; - if(!hi->shieldskill) { - shields.Remove(hi); - if(hi->pCaster->unit->GetEnergy()) hi->pCaster->unit->energy -= 1; //destroyed shield costs energy. - delete hi; - } -} diff --git a/arcadia/shields.h b/arcadia/shields.h deleted file mode 100644 index e429e96f7..000000000 --- a/arcadia/shields.h +++ /dev/null @@ -1,43 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef SHIELD_CLASS -#define SHIELD_CLASS - -#include "alist.h" - -class Shield : public AListElem { -public: - - int shieldtype; - int shieldskill; - Soldier * pCaster; -}; - -class ShieldList : public AList { -public: - Shield * GetHighShield(int); -}; - -#endif /* SHIELD_CLASS */ diff --git a/arcadia/skills.cpp b/arcadia/skills.cpp deleted file mode 100644 index 032eb2568..000000000 --- a/arcadia/skills.cpp +++ /dev/null @@ -1,493 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "skills.h" -#include "items.h" -#include "gamedata.h" - -RangeType *FindRange(char *range) -{ - if (range == NULL) return NULL; - for (int i = 0; i < NUMRANGES; i++) { - if (RangeDefs[i].key == NULL) continue; - if (AString(range) == RangeDefs[i].key) - return &RangeDefs[i]; - } - return NULL; -} - -SpecialType *FindSpecial(char *key) -{ - if (key == NULL) return NULL; - for (int i = 0; i < NUMSPECIALS; i++) { - if (SpecialDefs[i].key == NULL) continue; - if (AString(key) == SpecialDefs[i].key) - return &SpecialDefs[i]; - } - return NULL; -} - -EffectType *FindEffect(char *effect) -{ - if (effect == NULL) return NULL; - for (int i = 0; i < NUMEFFECTS; i++) { - if (EffectDefs[i].name == NULL) continue; - if (AString(effect) == EffectDefs[i].name) - return &EffectDefs[i]; - } - return NULL; -} - -AttribModType *FindAttrib(char *attrib) -{ - if (attrib == NULL) return NULL; - for (int i = 0; i < NUMATTRIBMODS; i++) { - if (AttribDefs[i].key == NULL) continue; - if (AString(attrib) == AttribDefs[i].key) - return &AttribDefs[i]; - } - return NULL; -} - -SkillType *FindSkill(char *skname) -{ - if (skname == NULL) return NULL; - for (int i = 0; i < NSKILLS; i++) { - if (SkillDefs[i].abbr == NULL) continue; - if (AString(skname) == SkillDefs[i].abbr) - return &SkillDefs[i]; - } - return NULL; -} - -int LookupSkill(AString *token) -{ - for (int i=0; iname) + " [" + pS->abbr + "]"; - return temp; -} - -AString SkillStrs(int i) -{ - AString temp = AString(SkillDefs[i].name) + " [" + - SkillDefs[i].abbr + "]"; - return temp; -} - -int SkillCost(int skill) -{ - return SkillDefs[skill].cost; -} - -int IsSpeciality(char *skill, int race) -{ - ManType *mt = FindRace(ItemDefs[race].abr); - - if (mt == NULL) return 0; - - SkillType *pS = FindSkill(skill); - if(!Globals->MAGE_NONLEADERS) { - if (pS && (pS->flags & SkillType::MAGIC)) { - if(!(ItemDefs[race].type & IT_LEADER)) return(0); - } - } - - AString skname = pS->abbr; - for(unsigned int c=0; c < sizeof(mt->skills)/sizeof(mt->skills[0]); c++) { - if(skname == mt->skills[c]) - return 1; - } - for(unsigned int c=0; c < sizeof(mt->mage_skills)/sizeof(mt->mage_skills[0]); c++) { - if(skname == mt->mage_skills[c]) - return 1; - } - return 0; -} - -int SkillMax(char *skill, int race) -//there seems to be a lot of overlap between use of this to find unit's max skill level, and use of IsASpeciality(). Maybe combine them sometime -{ - ManType *mt = FindRace(ItemDefs[race].abr); - - if (mt == NULL) return 0; - - SkillType *pS = FindSkill(skill); - if(!Globals->MAGE_NONLEADERS) { - if (pS && (pS->flags & SkillType::MAGIC)) { - if(!(ItemDefs[race].type & IT_LEADER)) return(0); - } - } - - if(pS->flags & SkillType::MAGIC) { - pS = FindSkill(SkillDefs[pS->baseskill].abbr); - AString skname = pS->abbr; - for(unsigned int c=0; c < sizeof(mt->mage_skills)/sizeof(mt->mage_skills[0]); c++) { - if(skname == mt->mage_skills[c]) - return mt->speciallevel-1; - } - return mt->defaultlevel-1; - - - } else { - AString skname = pS->abbr; - for(unsigned int c=0; c < sizeof(mt->skills)/sizeof(mt->skills[0]); c++) { - if(skname == mt->skills[c]) - return mt->speciallevel; - } - return mt->defaultlevel; - } -} - -int SkillExperMax(char *skill, int race) -/* REAL_EXPERIENCE Patch */ -{ - int max = SkillMax(skill,race); //set experience and knowledge maxes equal. Only for Arc IV - return max; -/* - ManType *mt = FindRace(ItemDefs[race].abr); - - if (mt == NULL) return 0; - - SkillType *pS = FindSkill(skill); - if(!Globals->MAGE_NONLEADERS) { - if (pS && (pS->flags & SkillType::MAGIC)) { - if(!(ItemDefs[race].type & IT_LEADER)) return(0); - } - } - - AString skname = pS->abbr; - for(unsigned int c=0; c < sizeof(mt->skills)/sizeof(mt->skills[0]); c++) { - if(skname == mt->skills[c]) - return mt->specialexperlevel; - } - return mt->defaultexperlevel; - */ -} - -int GetLevelByDays(int dayspermen) -{ - int z = 30; - int i = 0; - while (dayspermen >= z) { - i++; - dayspermen -= z; - z += 30; - } - return i; -} - -/* REAL_EXPERIENCE Patch */ -int GetLevelByDays(int dayspermen, int experpermen) -{ - int i = GetLevelByDays(dayspermen); - if(Globals->REAL_EXPERIENCE) i += GetLevelByDays(experpermen); - return i; -} - -int GetDaysByLevel(int level) -{ - int days = 0; - - for (;level>0; level--) { - days += level * 30; - } - - return days; -} - -ShowSkill::ShowSkill(int s, int l) -{ - skill = s; - level = l; -} - -Skill::Skill() -{ - days = 0; - experience = 0; - type = -1; - disabled = 0; -} - -Skill::~Skill() -{ -} - -void Skill::Readin(Ainfile *f) -{ - AString *temp, *token; - - temp = f->GetStr(); - token = temp->gettoken(); - type = LookupSkill(token); - delete token; - - token = temp->gettoken(); - days = token->value(); - delete token; - if(Globals->REAL_EXPERIENCE) { - token = temp->gettoken(); - experience = token->value(); - delete token; - } - token = temp->gettoken(); - if(token) disabled = token->value(); //enables version changes - else disabled = 0; - - delete token; - - delete temp; -} - -void Skill::Writeout(Aoutfile *f) -{ - AString temp; - - if (type != -1) { - temp = AString(SkillDefs[type].abbr) + " " + days; - if(Globals->REAL_EXPERIENCE) temp += AString(" ") + experience; - } else { - temp = AString("NO_SKILL 0"); - if(Globals->REAL_EXPERIENCE) temp += AString(" 0"); - } - temp += AString(" ") + disabled; - f->PutStr(temp); -} - -Skill *Skill::Split(int total, int leave) -{ - Skill *temp = new Skill; - temp->type = type; - temp->days = (days * leave) / total; - days = days - temp->days; - temp->experience = (experience * leave) / total; /* REAL_EXPERIENCE Patch*/ - experience = experience - temp->experience; - return temp; -} - -int SkillList::IsDisabled(int skill) -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - return s->disabled; - } - } - return 1; -} - -int SkillList::SetDisabled(int skill, int off) -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - s->disabled = off; - return 1; - } - } - return 0; -} - -int SkillList::GetDays(int skill) -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - return s->days; - } - } - return 0; -} - -int SkillList::GetExper(int skill) -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - return s->experience; - } - } - return 0; -} - -void SkillList::SetDays(int skill, int days) -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - if (days == 0 && s->experience == 0) { - Remove(s); - delete s; - return; - } else { - s->days = days; - return; - } - } - } - if (days == 0) return; - Skill *s = new Skill; - s->type = skill; - s->days = days; - s->experience = 0; /* REAL_EXPERIENCE Patch */ - Add(s); -} - -void SkillList::SetDays(int skill, int days, int exper) -/* REAL_EXPERIENCE Patch */ -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - if (days == 0 && exper == 0) { - Remove(s); - delete s; - return; - } else { - s->days = days; - s->experience = exper; - return; - } - } - } - if (days == 0 && exper == 0) return; - Skill *s = new Skill; - s->type = skill; - s->days = days; - s->experience = exper; - Add(s); -} - -void SkillList::SetExper(int skill, int exper) -/* REAL_EXPERIENCE Patch */ -{ - forlist(this) { - Skill *s = (Skill *) elem; - if (s->type == skill) { - if (exper == 0 && s->days == 0) { - Remove(s); - delete s; - return; - } else { - s->experience = exper; - return; - } - } - } - if (exper == 0) return; - Skill *s = new Skill; - s->type = skill; - s->experience = exper; - s->days = 0; - Add(s); -} - -SkillList *SkillList::Split(int total, int leave) -{ - SkillList *ret = new SkillList; - forlist (this) { - Skill *s = (Skill *) elem; - Skill *n = s->Split(total, leave); - if (s->days == 0 && s->experience == 0) { - Remove(s); - delete s; - } - ret->Add(n); - } - return ret; -} - -void SkillList::Combine(SkillList *b) -{ - forlist(b) { - Skill *s = (Skill *) elem; - SetDays(s->type, GetDays(s->type) + s->days, GetExper(s->type) + s->experience); - } -} - -AString SkillList::Report(int nummen) -{ - AString temp; - if (!Num()) { - temp += "none"; - return temp; - } - int i = 0; - forlist (this) { - Skill *s = (Skill *) elem; - if (i) { - temp += ", "; - } else { - i=1; - } - temp += SkillStrs(s->type); - temp += AString(" ") + GetLevelByDays(s->days/nummen,s->experience/nummen) + - AString(" (") + AString(s->days/nummen); - if(Globals->REAL_EXPERIENCE) temp += AString("/") + AString(s->experience/nummen); - temp += AString(")"); - if(s->disabled) temp += AString(" [DISABLED]"); - } - return temp; -} - -void SkillList::Readin(Ainfile *f) -{ - int n = f->GetInt(); - for (int i=0; iReadin(f); - if (s->days == 0 && s->experience == 0) delete s; /* REAL_EXPERIENCE Patch */ - else if (s->type == -1) delete s; //BS mod for changing gamefiles. - else Add(s); - } -} - -void SkillList::Writeout(Aoutfile *f) -{ - f->PutInt(Num()); - forlist(this) ((Skill *) elem)->Writeout(f); -} diff --git a/arcadia/skills.h b/arcadia/skills.h deleted file mode 100644 index c900d55cb..000000000 --- a/arcadia/skills.h +++ /dev/null @@ -1,352 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comment -// ---- ------ ------- -// 2001/Feb/18 Joseph Traub Added apprentice support from Lacandon Conquest -// 2001/Feb/18 Joseph Traub Added support for conquest -// -#ifndef SKILL_CLASS -#define SKILL_CLASS - -class Faction; -class Skill; -class SkillList; - -#include "fileio.h" -#include "astring.h" -#include "gamedefs.h" -#include "alist.h" - -/* For dependencies: - A value of depend == -1 indicates no more dependencies. - If depend is set to a skill, to study this skill, you must know - the depended skill at level equal to (at least) the level in the - structure, or at the level you are trying to study to. - - Example: - SANDLE has depends[0].skill = SHOE and depends[0].level = 3. - - To study: requires: - SANDLE 1 SHOE 3 - SANDLE 2 SHOE 3 - SANDLE 3 SHOE 3 - SANDLE 4 SHOE 4 - SANDLE 5 SHOE 5 -*/ - -struct SkillDepend -{ - char *skill; - int level; -}; - -class SkillType -{ - public: - char * name; - char * abbr; - int cost; - - enum { - MAGIC = 0x1, - COMBAT = 0x2, - CAST = 0x4, - FOUNDATION = 0x8, - APPRENTICE = 0x10, - DISABLED = 0x20, - SLOWSTUDY = 0x40, - BATTLEREP = 0x80, - NOTIFY = 0x100, - DAMAGE = 0x200, - FEAR = 0x400, //only used in tax calculations (can mages with fear spell tax) - MAGEOTHER=0x800, //not sure what the purpose of this is. Only used in taxing - NOSTUDY=0x1000, - NOTEACH=0x2000, - COSTVARIES=0x4000, //makes the energy cost of casting a spell decrease with the spell level - STUDYOR=0x8000, - UPGRADE=0x10000, - }; - int flags; - - // - // special for combat spells only - // - char *special; - - // range class for ranged skills (-1 for all others) - char *range; - - int baseskill; - - SkillDepend depends[3]; - - int cast_cost; - int combat_first; - int combat_cost; -}; -extern SkillType *SkillDefs; - -SkillType *FindSkill(char *skname); -int LookupSkill(AString *); -int ParseSkill(AString *); -AString SkillStrs(int); -AString SkillStrs(SkillType *); - -class ShowType { - public: - int skill; - int level; - char * desc; -}; -extern ShowType * ShowDefs; - -int SkillCost(int); /* skill */ -int IsSpeciality(char *,int); /* skill, race */ -int SkillMax(char *,int); /* skill, race */ -int SkillExperMax(char *,int); /* skill, race */ -int GetLevelByDays(int); -int GetLevelByDays(int, int); -int GetDaysByLevel(int); - -class ShowSkill : public AListElem { - public: - ShowSkill(int,int); - - AString * Report(Faction *); - - int skill; - int level; -}; - -class Skill : public AListElem { - public: - Skill(); //added constructor/destructor for 'disabled' flag - ~Skill(); - void Readin(Ainfile *); - void Writeout(Aoutfile *); - - Skill * Split(int,int); /* total num, num leaving */ - - int type; - unsigned int days; - unsigned int experience; /* REAL_EXPERIENCE Patch */ - int disabled; -}; - -class SkillList : public AList { - public: - int GetDays(int sk); - int GetExper(int sk); - int IsDisabled(int sk); - - int SetDisabled(int sk,int off); - void SetDays(int sk,int days); - void SetDays(int sk,int days,int exper); - void SetExper(int sk,int exper); - void Combine(SkillList *); - SkillList * Split(int,int); /* total men, num to split */ - AString Report(int); /* Number of men */ - void Readin(Ainfile *); - void Writeout(Aoutfile *); -}; - -class HealType { - public: - int num; - int rate; -}; -extern HealType * HealDefs; - -class DamageType { - public: - int type; - int minnum; - int value; - int flags; - int dclass; - char *effect; -}; - -class ShieldType { - public: - int type; - int value; -} -; -class DefenseMod { - public: - int type; - int val; -}; - -class SpecialType { - public: - char *key; - char *specialname; - - enum { - HIT_BUILDINGIF = 0x0001, /* mutually exclusive (1) */ - HIT_BUILDINGEXCEPT = 0x0002, /* mutually exclusive (1) */ - HIT_SOLDIERIF = 0x0004, /* mutually exclusive (2) */ - HIT_SOLDIEREXCEPT = 0x0008, /* mutually exclusive (2) */ - HIT_MOUNTIF = 0x0010, /* mutually exclusive (2) */ - HIT_MOUNTEXCEPT = 0x0020, /* mutually exclusive (2) */ - HIT_EFFECTIF = 0x0040, /* mutually exclusive (3) */ - HIT_EFFECTEXCEPT = 0x0080, /* mutually exclusive (3) */ - HIT_ILLUSION = 0x0100, //currently all illusions are monsters, so to hit_nomonsters will not hit illusions. This may change, in which case some changes need to be done. - HIT_NOILLUSION = 0x0200, - HIT_NOMONSTER = 0x0400, - HIT_MONSTEREXCEPT = 0x0800, //not used yet, planned for transfiguration - HIT_OWN_ARMY = 0x1000, //spell designed to hit own army - }; - int targflags; - - int buildings[3]; - int targets[7]; - char *effects[3]; - - enum { - FX_SHIELD = 0x001, - FX_DAMAGE = 0x002, // Needed to use during combat round (eg not shields) - FX_USE_LEV = 0x004, // multiplies damage by skill level - FX_DEFBONUS = 0x008, // gives def bonus to caster (?) - FX_NOBUILDING = 0x010, // no def bonus from building? - FX_DONT_COMBINE=0x020, // horrible report format! - FX_FOG = 0x040, // spell which affects taccontrol. Mututally exclusive with FX_SHIELD (changed?) - FX_ARMYBONUS = 0x080, // spell which affects armies. Mutually exclusive with FX_DEFBONUS (changed?) - FX_DUAL = 0x100, // affects both armies equally (fog spells only) - }; - int effectflags; - - int shield[4]; - DefenseMod defs[4]; - char *shielddesc; - - DamageType damage[4]; - char *spelldesc; - char *spelldesc2; - char *spelltarget; -}; -extern SpecialType *SpecialDefs; -extern int NUMSPECIALS; - -extern SpecialType *FindSpecial(char *key); - -class EffectType { - public: - int effectnum; //hack because mapping of effects in battle was not working in modified combat code - don't know why. These need to numbered sequentially from zero, and must be less or equal effects than size of effect array in soldiers.h - char *name; - int attackVal; - DefenseMod defMods[4]; - char *cancelEffect; - - enum { - EFF_ONESHOT = 0x001, //gets cleared at the end of combat round (Arcadian system only) - EFF_NOSET = 0x002, //soldier gets penalty, but is not flagged as having that effect - EFF_TRANSFIGURE = 0x004, //special spell, transfigures down to rats. Not tested on 'men', only monsters. - }; - int flags; - int monster; -}; -extern EffectType *EffectDefs; -extern int NUMEFFECTS; - -extern EffectType *FindEffect(char *effect); - -class RangeType { - public: - char *key; - enum { - RNG_NEXUS_TARGET = 0x0001, // Can cast *to* Nexus - RNG_NEXUS_SOURCE = 0x0002, // Can cast *from* Nexus - RNG_CROSS_LEVELS = 0x0004, // Spell can cross levels - RNG_SURFACE_ONLY = 0x0008, // Target region must be on surface - }; - int flags; - - enum { - RNG_ABSOLUTE = 0, // Range is not based on skill - RNG_LEVEL, // Range is based on skill - RNG_LEVEL2, // Range is based on skill level squared - RNG_LEVEL3, // Range is based on skill level cubed - NUMRANGECLASSES - }; - int rangeClass; - - int rangeMult; - - int crossLevelPenalty; // How much extra distance to cross levels? -}; -extern RangeType *RangeDefs; -extern int NUMRANGES; - -extern RangeType *FindRange(char *range); - -class AttribModItem { - public: - enum { - SKILL = 0x0001, - ITEM = 0x0002, - FLAGGED = 0x0004, - NOT = 0x0100, - CUMULATIVE = 0x0200, - PERMAN = 0x400 - }; - int flags; - - char *ident; - - enum { - CONSTANT, - UNIT_LEVEL, - UNIT_LEVEL_HALF, - FORCECONSTANT, - NUMMODTYPE, - }; - int modtype; - - int val; -}; - -class AttribModType { - public: - char *key; - - enum { - CHECK_MONSTERS = 0x01, - USE_WORST = 0x02, - }; - int flags; - - AttribModItem mods[6]; // BS mod to expand stealth -}; - -extern AttribModType *AttribDefs; -extern int NUMATTRIBMODS; - -extern AttribModType *FindAttrib(char *attrib); - -#endif diff --git a/arcadia/skillshows.cpp b/arcadia/skillshows.cpp deleted file mode 100644 index 1df9b9d52..000000000 --- a/arcadia/skillshows.cpp +++ /dev/null @@ -1,3467 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2001/Feb/23 Joseph Traub Made skill texts runtime generated -// -#include "skills.h" -#include "items.h" -#include "object.h" -#include "gamedata.h" -#include "astring.h" - -#define ITEM_ENABLED(X) (!(ItemDefs[(X)].flags & ItemType::DISABLED)) -#define ITEM_DISABLED(X) (ItemDefs[(X)].flags & ItemType::DISABLED) -#define SKILL_ENABLED(X) (!(SkillDefs[(X)].flags & SkillType::DISABLED)) -#define SKILL_DISABLED(X) (SkillDefs[(X)].flags & SkillType::DISABLED) -#define OBJECT_ENABLED(X) (!(ObjectDefs[(X)].flags & ObjectType::DISABLED)) -#define OBJECT_DISABLED(X) (ObjectDefs[(X)].flags & ObjectType::DISABLED) - -int SkillCost(int skill, int level, int multiplier) -{ - float cost = (float) SkillDefs[skill].cast_cost; - cost *= multiplier; - if(SkillDefs[skill].flags & SkillType::COSTVARIES) { - float leveleffect = (float) (2 + level ) / 3; - cost /= leveleffect; - } - - cost += 0.99; - - return (int) cost; -} - -AString CostString(int skill, int fromlevel, int tolevel, int multiplier) -{ - AString temp; - for(int i=fromlevel; i<=tolevel; i++) { - if(i != fromlevel) temp += ", "; - if(i == tolevel) temp += "or "; - temp += AString(SkillCost(skill,i,multiplier)); - } - return temp; -} - -AString EnergyString(int skill, int fromlevel, int tolevel, int multiplier) -{ - AString message; - message = "will cost a mage "; - if(SkillDefs[skill].flags & SkillType::COSTVARIES) { - message += CostString(skill,fromlevel,tolevel,multiplier) + - " energy at skill levels " + fromlevel + " to " + tolevel + " respectively," ; - } else message += AString(SkillCost(skill,fromlevel,multiplier)) + " energy."; - - return message; -} - -AString *ShowSkill::Report(Faction *f) -{ - if(SkillDefs[skill].flags & SkillType::DISABLED) return NULL; - AString *str = new AString; - RangeType *range = NULL; -//Awrite(AString("starting") + skill); - // Here we pick apart the skill - switch (skill) { - case S_FARMING: - if(level > 1) break; - *str += "This skill deals with all aspects of grain production."; - break; - case S_RANCHING: - if(level > 1) break; - *str += "This skill deals with all aspects of livestock " - "production."; - break; - case S_MINING: - if(level > 1) break; - *str += "This skill deals with all aspects of extracting raw " - "metals and gems from the earth. Metals and gems tend to be " - "found more often in mountainous regions, but may be found " - "elsewhere as well."; - break; - case S_LUMBERJACK: - if(level > 1) break; - *str += "This skill deals with all aspects of various wood " - "production. Woods are more often found in forests, but " - "may also be found elsewhere."; - break; - case S_BANKING: - if(level > 1) break; - *str += "This skill deals with all aspects of depositing and " - "withdrawing funds from banks."; - break; - case S_QUARTERMASTER: - if (level > 1) break; - if (!(Globals->TRANSPORT & GameDefs::ALLOW_TRANSPORT)) - break; - *str += "This skill deals with transporting and " - "distributing goods between non-local units " - "and transport structures."; - if (Globals->SHIPPING_COST > 0) { - *str += " The cost of shipping one weight unit from one " - "transport structure to another transport structure is "; - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_COST) - *str += AString("4-((level+1)/2) * "); - *str += AString(Globals->SHIPPING_COST) + " silver."; - if (Globals->FRACTIONAL_WEIGHT) { - *str += " Items with a normal weight of 0 are " - "treated as if "; - *str += Globals->FRACTIONAL_WEIGHT; - *str += " of the item in question weigh one weight unit."; - } - } - - if (Globals->NONLOCAL_TRANSPORT > 0) { - *str += " Items may be shipped between two transport " - "structures which are up to "; - *str += Globals->NONLOCAL_TRANSPORT; - if (Globals->TRANSPORT & GameDefs::QM_AFFECT_DIST) - *str += " plus (level+1)/3 "; - *str += (Globals->NONLOCAL_TRANSPORT != 1) ? "hexes" : "hex"; - *str += " distant from each other."; - } else if (Globals->NONLOCAL_TRANSPORT == 0) { - *str += " Items may be instantaneously " - "shipped between any two transport " - "structures."; - } - if (Globals->LOCAL_TRANSPORT > 0) { - *str += " Items may be distributed from a transport " - "structure to any unit or transported to a transport " - "structure by any unit located within "; - *str += Globals->LOCAL_TRANSPORT; - *str += (Globals->LOCAL_TRANSPORT != 1) ? " hexes" : " hex"; - *str += " of the transport structure."; - } - break; - case S_QUARRYING: - if(level > 1) break; - *str += "This skill deals with all aspects of various stone " - "production. Mountains are the main producers of stone, but " - "it may be found in other regions as well."; - break; - case S_HUNTING: - if(level > 1) break; - *str += "This skill deals with all aspects of animal hide " - "production."; - break; - case S_FISHING: - if(level > 1) break; - *str += "This skill deals with all aspects of fish production."; - break; - case S_HERBLORE: - if(level > 1) break; - *str += "This skill deals with all aspects of herb production."; - break; - case S_HORSETRAINING: - if(level > 1) break; - *str += "This skill deals with all aspects of horse production."; - break; - case S_WEAPONSMITH: - if(level > 1) break; - *str += "This skill deals with all aspects of weapon " - "construction and production."; - break; - case S_ARMORER: - if(level > 1) break; - *str += "This skill deals with all aspects of armour construction " - "and production."; - break; - case S_CARPENTER: - if(level > 1) break; - *str += "This skill deals with all aspects of wood based item " - "production other than for use as weapons."; - break; - case S_BUILDING: - if(level > 1) break; - *str += "This skill deals with the construction of " - "fortifications, roads and other buildings, except for " - "most trade structures."; - break; - case S_SHIPBUILDING: - if(level > 1) break; - *str += "This skill deals with the construction of all types " - "of ships."; - break; - case S_CONSTRUCTION: - if(level > 1) break; - *str += "This skill deals with the construction of mobile " - "items and structures, such as wagons or ships."; - break; - case S_ENTERTAINMENT: - if(level > 1) break; - *str += "A unit with this skill may use the ENTERTAIN order " - "to generate funds. The amount of silver gained will " - "be 20 per man, times the level of the entertainers. " - "This amount is limited by the region that the unit is in."; - break; - case S_TACTICS: - if(level == 1) { - *str += "Tactics allows a unit to command soldiers during a " - "battle. The highest level tactitian on each side in a " - "battle commands their army, and determines their army's overall " - "strategy to the best of their ability. At skill level 1 " - "a tactics leader understands the basics of using foot and " - "ranged formations in battle. In addition, tactics leaders " - "may act as officers, enabling them to convey the orders of " - "the overall battle commander to other soldiers in the " - "battle. At skill level 1, a soldier may control ten " - "soldiers, including himself, in normal battle conditions."; - } else if(level == 2) { - *str += "With tactics skill level 2, a battle commander may " - "make use of cavalry formations in battle, comprised of " - "soldiers with mounts capable of riding."; - } else if(level == 3) {/* - *str += "With tactics skill level 3, a battle commander may " - "form his troops into square formation, if necessary " - "to protect small numbers of behind troops. (Not implemented as of 040120)";*/ - } else if(level == 4) { - *str += "With tactics skill level 4, a battle commander may " - "make use of aerial cavalry formations in battle, comprised of " - "soldiers with mounts capable of flying."; - } else if(level == 5) { - } - if(level>1 && level<5) *str += AString(" In addition, an officer with tactics level ") - + level + " may control " + (level*(15 + 5*level) / 2) + - " soldiers, including himself, in normal battle conditions."; - if(level >= 5) *str += AString(" An officer with tactics level ") - + level + " may control " + (level*(15 + 5*level) / 2) + - " soldiers, including himself, in normal battle conditions."; - break; - - case S_COMBAT: - if(level > 1) break; - *str += "This skill gives the unit a bonus in hand to hand " - "combat. Also, a unit with this skill may TAX or PILLAGE."; - break; - case S_RIDING: - if(level > 1) break; - *str += "A unit with this skill, if possessing a mount, may " - "gain a bonus in combat, if the battle is in a location " - "where that mount may be utilized and if the skill of the " - "rider is sufficient to control that mount. The bonus " - "gained can vary with the mount, the riders skill, and the " - "terrain."; - break; - case S_CROSSBOW: - if(level > 1) break; - *str += "A unit with this skill may use a crossbow or other bow " - "derived from one, either in battle, or to TAX or PILLAGE a " - "region."; - break; - case S_LONGBOW: - if(level > 1) break; - *str += "A unit with this skill may use a longbow or other bow " - "derived from one, either in battle, or to TAX or PILLAGE a " - "region."; - break; - case S_STEALTH: - if(level > 1) break; - *str += "A unit with this skill is concealed from being seen"; - if(SKILL_ENABLED(S_OBSERVATION)) { - *str += ", except by units with an Observation skill greater " - "than or equal to the stealthy unit's Stealth level"; - } - *str += "."; - break; - case S_OBSERVATION: - if(level > 1) break; - *str += "A unit with this skill can see stealthy units or " - "monsters whose stealth rating is less than or equal to " - "the observing unit's Observation level. The unit can " - "also determine the faction owning a unit, provided its " - "Observation level is higher than the other unit's Stealth " - "level."; - break; - case S_HEALING: - if(level > 1) break; - *str += AString("A unit with this skill is able to attempt to heal ") + - Globals->HEALS_PER_MAN + " times his skill " - "level units hurt in a battle which is won. This skill requires " - "one herb for every healing attempt made."; - break; - case S_SAILING: - if(level > 1) break; - *str += "A unit with this skill may use the SAIL order to sail " - "ships."; - break; - case S_FORCE: - if(level > 1) break; - *str += "The Force skill is not directly useful to a mage, but " - "is rather one of the Foundation skills on which other " - "magical skills are based. The Force skill determines the " - "power of the magical energy that a mage is able to use. " - "Note that a Force skill level of 0 does not indicate that " - "a mage cannot use magical energy, but rather can only " - "perform magical acts that do not require great amounts of " - "power."; - break; - case S_PATTERN: - if(level > 1) break; - *str += "The Pattern skill is not directly useful to a mage, but " - "is rather one of the Foundation skills on which other " - "magical skills are based. A mage's Pattern skill indicates " - "the ability to handle complex magical patterns, and is " - "important for complicated tasks such as healing and " - "controlling nature."; - break; - case S_SPIRIT: - if(level > 1) break; - *str += "The Spirit skill is not directly useful to a mage, but " - "is rather one of the Foundation skills on which other " - "magical skills are based. Spirit skill indicates the mage's " - "ability to control and affect magic and other powers beyond " - "the material world."; - break; - case S_FIRE: - if(level > 1) break; - break; - case S_EARTHQUAKE: - if(level > 1) break; - break; - case S_FORCE_SHIELD: - if(level > 1) break; - break; - case S_ENERGY_SHIELD: - if(level > 1) break; - break; - case S_SPIRIT_SHIELD: - if(level > 1) break; - break; - case S_MAGICAL_HEALING: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "This skill enables the mage to magically heal units " - "after battle. "; - } - *str += AString("A mage at this level can heal up to ") + HealDefs[level].num + - " casualties, with a " + HealDefs[level].rate + - " percent rate of success. No order " - "is necessary to use this spell, it will be used " - "automatically when the mage is involved in battle."; - if(Globals->ARCADIA_MAGIC && level == 1 && SkillDefs[skill].combat_cost > 0) - *str += AString(" A mage will require one energy for every ") - + 120/SkillDefs[skill].combat_cost + " casualties he " - "attempts to heal."; - break; - case S_GATE_LORE: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "Gate Lore is the art of detecting and using magical " - "Gates, which are spread through the world. The Gates are " - "numbered in order, but spread out randomly, so there is " - "no correlation between the Gate number and the Gate's " - "location. A mage with skill 1 in Gate Lore can see a " - "Gate if one exists in the same region as the mage. This " - "detection is automatic; the Gate will appear in the " - "region report. A mage with skill 1 in Gate Lore may " - "also jump through a Gate into another region on the same " - "level containing a gate, selected at random. To use " - "Gate Lore in this manner, use the syntax CAST Gate_Lore " - "RANDOM UNITS ... UNITS is followed by a list " - "of units to follow the mage through the Gate. The mage " - "always jumps through the Gate, it is not possible to send " - "units without the mage jumping with them. " - "If only the mage wishes " - "to jump, then the syntax CAST Gate_Lore RANDOM is " - "sufficient. "; - if(!Globals->ARCADIA_MAGIC) { - *str += "At level 1, the mage " - "may carry 15 weight units through the Gate (including " - "the weight of the mage)."; - } else { - *str += "A mage may transport up to 3 " - "times his level squared weight units per energy used. The mage will always be " - "transported, and his weight is included in the total. " - "There is no limit to how many units a mage may " - "transport, provided he has sufficient " - "energy to do so. For instance, a mage at " - "level 1 with 15 energy may transport up to 3*1*1*15 = 45 " - "weight units."; - } - } else if (level == 2) { - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with Gate Lore skill 2 can detect Gates in " - "adjacent regions. The mage should use the syntax CAST " - "Gate_Lore DETECT in order to detect these nearby Gates. " - "Also, at level 2 Gate Lore, the mage may carry 100 " - "weight units through a Gate when doing a random jump."; - } else { - *str += AString("A mage with Gate Lore skill 2 can detect Gates in " - "adjacent regions. This spell ") + EnergyString(skill,2,6,1) + - " The mage should use the syntax CAST " - "Gate_Lore DETECT in order to detect these nearby Gates."; - } - } else if(level == 3) { - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with Gate Lore skill 3 and higher can step " - "through a Gate into another region containing a specific " - "Gate. To use this spell, use the syntax CAST Gate_Lore " - "GATE UNITS ... specifies the " - "Gate that the mage will jump to. UNITS is followed by a " - "list of units to follow the mage through the gate (the " - "mage always jumps through the gate). At level 3, the " - "mage may carry 15 weight units through the Gate " - "(including the mage). Also, a level 3 or higher mage " - "doing a random gate jump may carry 1000 weight units " - "through the Gate."; - } else { - *str += "A mage with Gate Lore skill 3 and higher can step " - "through a Gate into another region containing a specific " - "Gate. To use this spell, use the syntax CAST Gate_Lore " - "GATE UNITS ... specifies the " - "Gate that the mage will jump to. UNITS is followed by a " - "list of units to follow the mage through the gate (the " - "mage always jumps through the gate). If only the mage " - "is to jump, then the syntax CAST Gate_Lore GATE " - "may be used. A mage may transport up to " - "his skill level minus two, squared, times 3 weight units " - "per energy used. There is no limit on how many units a mage may " - "transport provided he has sufficient energy to transport " - "both the units and himself. For instance, a mage " - "with level 3 gate lore and 40 energy may transport up to " - "1*1*3*40 = 120 weight units, including the weight of the " - "mage."; - } - } else if(level == 4 && !Globals->ARCADIA_MAGIC) { - *str += "A mage with Gate Lore skill 4 may carry 100 weight " - "units through a Gate."; - } else if(level == 5) { - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with Gate Lore skill 5 can detect gates two " - "regions away."; - } else { - *str += AString("A mage with Gate Lore skill 5 can detect gates up " - "to two regions away. The mage should use the syntax 'CAST " - "Gate_Lore DETECT LARGE' in order to detect all gates within " - "a distance of two regions or less. This spell ") + EnergyString(skill,2,6,1); - } - } - break; - case S_PORTAL_LORE: - if(level > 1) break; - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_PORTAL)) break; - *str += "A mage with the Portal Lore skill may, with the aid of " - "another mage, make a temporary Gate between two regions, and " - "send units from one region to another. In order to do this, " - "both mages (the caster, and the target mage) must have " - "Portals, and the caster must be trained in Portal Lore. The " - "caster may teleport units weighing up to 50 weight units " - "times his skill level, to the target mage's region. "; - range = FindRange(SkillDefs[skill].range); - if(range) { - *str += " The target region must be within "; - *str += range->rangeMult; - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += " times the caster's skill level "; - break; - case RangeType::RNG_LEVEL2: - *str += " times the caster's skill level squared "; - break; - case RangeType::RNG_LEVEL3: - *str += " times the caster's skill level cubed "; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += "regions of the caster. "; - } - *str += "To use this skill, CAST Portal_Lore UNITS " - " ..., where is the unit number of the " - "target mage, and is a list of units to be " - "teleported (the casting mage may teleport himself, if " - "he so desires)."; - break; - case S_FARSIGHT: - if(level == 1) { - *str += "A mage with this skill may obtain region reports on " - "distant regions. The report will be as if the mage was in " - "the distant region himself."; - if(Globals->ARCADIA_MAGIC) *str += AString(" This skill") + EnergyString(skill,1,6,1); - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of the " - "world."; - } - *str += " The target region must be within "; - *str += range->rangeMult; - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += " times the caster's skill level "; - break; - case RangeType::RNG_LEVEL2: - *str += " times the caster's skill level squared "; - break; - case RangeType::RNG_LEVEL3: - *str += " times the caster's skill level cubed "; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += "regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface are " - "scaled to the surface coordinates for this " - "calculation. Attempting to view across different " - "levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Farsight REGION " - " where , , and are the coordinates of " - "the region that you wish to view. If you omit the " - " coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is '1' " - "and the -coordinate for the underworld is " - "'2'."; - } - *str += " Note that Farsight cannot be used either into " - "or out of the Nexus."; - } else { - *str += "To use this skill, CAST Farsight REGION " - ", where and are the coordinates of the " - "region that you wish to view."; - } - } - if(Globals->IMPROVED_FARSIGHT) { - *str += " Any other skills which the mage has which give " - "region information will be used when farsight is used."; - } else { - *str += " Note that Farsight does not work in conjunction " - "with other skills or spells; the mage can only rely on " - "his normal facilities while casting Farsight."; - } - } else if(level == 4 && Globals->ARCADIA_MAGIC) { - *str += AString("At level 4, a mage may cast farsight on a region and all six " - "surrounding regions at once. This skill ") + EnergyString(skill,4,6,4) - + "To use the spell in this fashion, " - "CAST Farsight LARGE"; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += " REGION where , , and are the " - "coordinates of the central region around which you wish to " - "cast farsight. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - } else { - *str += " REGION , where and are the " - "coordinates of the central region around which you " - "wish to cast farsight."; - } - *str += " This spell uses the same range calculation as the " - "normal farsight spell, but the caster's effective skill " - "level is reduced by 2 for calculating the maximum range"; - } - } - break; - case S_MIND_READING: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "A mage with Mind Reading skill 1 may cast the spell " - "and determine the faction affiliation of any unit he can " - "see. To use the spell in this manner, CAST Mind_Reading " - ", where is the target unit."; - if(Globals->ARCADIA_MAGIC) *str += " This spell does not " - "require any energy to cast."; - } else if ((level == 2 && Globals->ARCADIA_MAGIC) || (level == 3 && !Globals->ARCADIA_MAGIC)) { - *str += AString("A mage with Mind Reading skill ") + level + " will automatically " - "determine the faction affiliation of any unit he can " - "see. Usage of this skill is automatic, and no order is " - "needed to use it."; - } else if ((level == 3 && Globals->ARCADIA_MAGIC) || (level == 5 && !Globals->ARCADIA_MAGIC)) { - *str += AString("A mage with Mind Reading skill ") + level + " can get a full " - "unit report on any unit he can see. To use this skill, " - "CAST Mind_Reading where is the target " - "unit."; - } - break; - case S_TELEPORTATION: - if(level > 1) break; - /* XXX -- This should be cleaner somehow. */ - *str += "A mage with this skill may teleport himself across" - "great distances, even without the use of a gate. The mage " - "may teleport up to 50 weight units per skill level"; - if(Globals->ARCADIA_MAGIC) *str += AString(" squared. For every " - "50 times his skill level, weight units, that are transported, this spell ") + EnergyString(skill,1,6,1); - else *str += "."; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of the " - "world."; - } - *str += " The target region must be within "; - *str += range->rangeMult; - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += " times the caster's skill level "; - break; - case RangeType::RNG_LEVEL2: - *str += " times the caster's skill level squared "; - break; - case RangeType::RNG_LEVEL3: - *str += " times the caster's skill level cubed "; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += "regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface are " - "scaled to the surface coordinates for this " - "calculation. Attempting to view across different " - "levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Teleportation REGION " - " where , , and are the " - "coordinates of the region that you wish to " - "teleport to. If you omit the coordinate, the " - " coordinate of the caster's current region will " - "be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is '1' " - "and the -coordinate for the underworld is " - "'2'."; - } - *str += " Note that Teleportation cannot be used either " - "into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Teleportation REGION " - " , where and are the coordinates of " - "the region that you wish to teleport to."; - } - } - break; - case S_WEATHER_LORE: - if(level > 1) break; - /* XXX -- This should be templated */ - *str += "Weather Lore is the magic of the weather; a mage with " - "this skill can predict the weather in nearby regions. " - "Weather Lore also allows further study into more powerful " - "areas of magic. The weather may be predicted for 3 months " - "at level 1, 6 months at level 3 and a full year at level " - "5."; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of the " - "world."; - } - *str += " The target region must be within "; - *str += range->rangeMult; - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += " times the caster's skill level "; - break; - case RangeType::RNG_LEVEL2: - *str += " times the caster's skill level squared "; - break; - case RangeType::RNG_LEVEL3: - *str += " times the caster's skill level cubed "; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += "regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface are " - "scaled to the surface coordinates for this " - "calculation. Attempting to view across different " - "levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Weather_Lore REGION " - " where , , and are the " - "coordinates of the region where you wish to " - "predict the weather. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is '1' " - "and the -coordinate for the underworld is " - "'2'."; - } - *str += " Note that Weather Lore cannot be used either " - "into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Weather_Lore REGION " - " , where and are the coordinates of " - "the region where you wish to predict the weather."; - } - } - *str += " A mage with Weather Lore skill will perceive the use " - "of Weather Lore by any other mage in the same region."; - break; - case S_SUMMON_WIND: - if(Globals->ARCADIA_MAGIC) { - if(level == 1) { - *str += "A mage with knowledge of Summon Wind can summon " - "up the powers of the wind to aid him in sea or " - "air travel. Usage of this spell is automatic. " - "At level 1, the mage may speed a "; - int found = 0; - AString temp = ""; - for(int i=0; i 0 && ObjectDefs[i].capacity < 500) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += ". This spell has two effects: the ship will not be slowed " - "by bad weather (winter, monsoons"; - if(!(SkillDefs[S_BLIZZARD].flags & SkillType::DISABLED)) { - *str += " or blizzards"; - } - *str += "), and will also travel 20% times his skill level faster " - "than the normal good weather speed (rounded down, but with a minimum of +1 speed)."; - *str += AString(" However, the act of speeding the ship ") + - EnergyString(skill,1,6,1) + - " If the mage does not have this much energy, the ship " - "speed will not be affected. Only the highest level mage onboard " - "(who is able to cast this spell) will cast this spell."; - *str += " Also, if the mage is flying, he will receive 2 extra " - "movement points; this does not cost the mage any energy."; - } else if (level == 2) { - *str += "With level 2 Summon Wind, a mage may speed the passage " - "of a "; - int found = 0; - AString temp = ""; - for(int i=0; i 499 && ObjectDefs[i].capacity < 1201) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += AString(", to travel 20% times his skill level faster, " - "without delay by bad weather. This spell ") + - EnergyString(skill,2,6,2); - } else if (level == 3) { - *str += "With level 3 Summon Wind, a mage may speed the passage " - "of a "; - int found = 0; - AString temp = ""; - for(int i=0; i 1200) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += AString(", to travel 20% times his skill level faster, " - "without delay by bad weather. This spell ") + - EnergyString(skill,2,6,3); - } - break; - } else { - if(level == 1) { - *str += "A mage with knowledge of Summon Wind can summon " - "up the powers of the wind to aid him in sea or " - "air travel. Usage of this spell is automatic."; - if(OBJECT_ENABLED(O_LONGBOAT)) { - *str += " At level 1, if the mage is in a Longboat, that " - "ship will get 2 extra movement points."; - } - *str += " If the mage is flying, he will receive 2 extra " - "movement points."; - } else if (level == 2) { - if(OBJECT_DISABLED(O_MERCHANT)) break; - *str += "With level 2 Summon Wind, any ship of Clipper size " - "or smaller that the mage is inside will receive a " - "2 movement point bonus."; - } else if (level == 3) { - *str += "At level 3 of Summon Wind, any ship the mage is in " - "will receive a 2 movement point bonus. Note that " - "study of Summon Wind beyond level 3 does not " - "yield any further powers."; - } - break; - } - case S_SUMMON_STORM: - if(level > 1) break; - break; - case S_SUMMON_TORNADO: - if(level > 1) break; - break; - case S_CALL_LIGHTNING: - if(level > 1) break; - break; - case S_CLEAR_SKIES: - /* XXX -- this range stuff needs cleaning up */ - if(level == 1) { - if(SkillDefs[skill].flags & SkillType::CAST) { - *str += "When cast using the CAST order, this skill causes the " - "region to have good weather for the entire month; " - "movement is at the normal rate (even if it is winter) " - "and the economic and food production of the region is improved " - "for a month. Note that the good weather will take effect during the turn " - "in which the spell is cast, but the economy bonus will " - "take effect during the turn after the spell " - "is cast. Clear skies overwrites any other magical weather " - "effects"; - if(!(SkillDefs[S_BLIZZARD].flags & SkillType::DISABLED)) { - *str += ", such as blizzards."; - } else *str += "."; - if(Globals->ARCADIA_MAGIC) { - *str += " In addition, this spell counteracts the effects " - "of fog both in battle and when CAST on the same region, " - "by reducing the effectiveness of the fog spell by the " - "skill of the mage casting clear skies."; - *str += AString(" This spell ") + EnergyString(skill,1,6,1); - } - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - *str += range->rangeMult; - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += " times the caster's skill level "; - break; - case RangeType::RNG_LEVEL2: - *str += " times the caster's skill level squared "; - break; - case RangeType::RNG_LEVEL3: - *str += " times the caster's skill level cubed "; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += "regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to view across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Clear_Skies REGION " - " where , , and are the " - "coordinates of the region where you wish to " - "improve the weather. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Clear Skies cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Clear_Skies REGION " - " , where and are the coordinates " - "of the region where you wish to improve the " - "weather."; - } - } - } else { - *str += " To use the spell in this fashion, CAST " - "Clear_Skies; no arguments are necessary."; - } - } else if(level == 4 && Globals->ARCADIA_MAGIC) { - *str += AString("At level 4, a mage may cast clear skies on a region and all six " - "surrounding regions at once. This spell ") - + EnergyString(skill,4,6,4) + - " To use the spell in this fashion, " - "CAST Clear_Skies LARGE"; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += " REGION where , , and are the " - "coordinates of the central region around which you wish to " - "cast clear skies. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - } else { - *str += " REGION , where and are the " - "coordinates of the central region around which you " - "wish to cast clear skies."; - } - *str += " This spell uses the same range calculation as the " - "normal clear skies spell, but the caster's effective skill " - "level is reduced by 2 for calculating the maximum range"; - } - *str += "."; - } - break; - case S_EARTH_LORE: - if(level == 1) { - *str += "Earth Lore is the study of nature, plants, and animals. " - "A mage with knowledge of Earth Lore can use his knowledge " - "of nature to aid local farmers, raising money for himself, " - "and aiding the production of grain or livestock in the " - "region. This increased production will take place the turn " - "after the spell is cast. Also, a mage with knowledge of Earth " - "Lore will detect the use of Earth Lore by any other mage in " - "the same region."; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - *str += range->rangeMult; - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += " times the caster's skill level "; - break; - case RangeType::RNG_LEVEL2: - *str += " times the caster's skill level squared "; - break; - case RangeType::RNG_LEVEL3: - *str += " times the caster's skill level cubed "; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += "regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to view across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Earth_Lore REGION " - " where , , and are the " - "coordinates of the region where you wish to " - "improve the weather. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Earth Lore cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Earth_Lore REGION " - " , where and are the coordinates " - "of the region where you wish to improve the " - "weather."; - } - } else { - *str += " To use this skill, CAST Earth_Lore."; - } - if(Globals->ARCADIA_MAGIC) { - *str += AString(" This spell ") + EnergyString(skill,1,6,1); - } - } else if(level == 4) { - *str += "At level 4, a mage may cast earth lore on a region and all six " - "surrounding regions at once. To use the spell in this fashion, " - "CAST Earth_Lore Large"; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += " REGION where , , and are the " - "coordinates of the central region around which you wish to " - "cast earth lore. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - } else { - *str += " REGION , where and are the " - "coordinates of the central region around which you " - "wish to cast earth lore."; - } - *str += " This spell uses the same range calculation as the " - "normal earth lore spell, but the caster's effective skill " - "level is reduced by 2 for calculating the maximum range"; - } - if(Globals->ARCADIA_MAGIC) { - *str += AString(" This spell ") + EnergyString(skill,4,6,4); - } - } - break; - case S_WOLF_LORE: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_WOLF)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Wolf Lore skill may summon wolves, who will " - "fight for him in combat. A mage may summon a number of " - "wolves equal to his skill level, and control a total number " - "of his skill level squared times 4 wolves; the wolves will " - "be placed in the mages inventory. Note, however, that wolves " - "may only be summoned in mountain and forest regions. To " - "summon wolves, the mage should issue the order CAST " - "Wolf_Lore."; - } else { - *str += "A hero with the Wolf Lore skill may tame wolves, who will " - "fight for him in combat. A hero may tame a number of " - "wolves each month equal to his skill level, and control a total number " - "of his skill level squared times 4 wolves; the wolves will " - "be placed in the mages inventory. Note, however, that wolves " - "may only be summoned in mountain and forest regions. To " - "summon wolves, the mage should issue the order CAST " - "Wolf_Lore."; - } - break; - case S_BIRD_LORE: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "A hero with Bird Lore learns to control the birds of the " - "sky. At skill level 1, the hero can tame small " - "birds, sending them to nearby regions to obtain " - "reports on those regions. (This skill only works on the " - "surface of the world, as there are no birds elsewhere). " - "To use this skill, CAST Bird_Lore DIRECTION , " - "where is the direction the hero wishes the birds " - "to report on. The hero will recieve reports on the " - "the first n regions in that direction, where n is the " - "hero's bird lore skill level."; - } else if (level == 3) { - if(ITEM_DISABLED(I_EAGLE)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with Bird Lore 3 can summon eagles to join " - "him, who will aid him in combat, and provide for flying " - "transportation. A mage may summon a number of eagles " - "equal to his skill level minus 2, squared; the eagles " - "will appear in his inventory. To summon an eagle, issue " - "the order CAST Bird_Lore EAGLE."; - } else { - *str += "A hero with Bird Lore 3 can tame eagles " - "to join him or her, which will aid in combat and provide " - "flying transportation. A hero may tame a total " - "number of eagles equal to their skill level minus 2, squared. " - " To use this skill, " - "the hero should issue the order CAST Bird_Lore EAGLE, " - "and the hero will tame an extra eagle in the coming month."; - } - }/* else if (level == 4) { - if(Globals->ARCADIA_MAGIC) { - *str += AString("A mage with Bird Lore 4 can send small birds to spy " - "on all neighbouring regions at once. This skill ") - + EnergyString(skill,4,6,4) + - " To use this skill in this fashion, CAST Bird_Lore LARGE."; - } - }*/ - break; - case S_DRAGON_LORE: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_DRAGON)) break; - *str += "A mage with Dragon Lore skill can summon dragons to " - "join him, to aid in battle, and provide flying " - "transportation. A mage at level 1 has a low chance of " - "successfully summoning a dragon, gradually increasing until " - "at level 5 he may summon one dragon per turn; the total " - "number of dragons that a mage may control at one time is " - "equal to his skill level. To attempt to summon a dragon, " - "CAST Dragon_Lore."; - break; - case S_NECROMANCY: - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "Necromancy is the magic of death; a mage versed in " - "Necromancy may raise and control the dead, and turn the " - "powers of death to his own nefarious purposes. The " - "Necromancy skill does not have any direct application, but " - "is required to study the more powerful Necromantic skills. " - "A mage with knowledge of Necromancy will detect the use of " - "Necromancy by any other mage in the same region."; - } else { - *str += "Necromancy is the magic of death; a mage versed in " - "Necromancy may raise and control the dead, and turn the " - "powers of death to his own nefarious purposes. This skill " - "enables the mage to create skeletons from units which have " - "died in battle. This spell will be used automatically by " - "a mage on the winning side of a battle, and will attempt to " - "turn the battle corpses into " - "skeletons, with a base success rate of 30%, plus 10% times " - "the mage's skill level."; - if(SkillDefs[skill].combat_cost > 0) *str += AString(" For every ") + 120/SkillDefs[skill].combat_cost + - " corpses which this spell is cast on, a mage will " - "lose 1 energy. Note that skeletons, and all other undead, " - " have a 6.7% chance of decaying each month."; - *str + " A mage with knowledge of Necromancy will also detect the use of " - "necromancy skills by any other mage in the same region."; - } - break; - case S_SUMMON_SKELETONS: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_SKELETON)) break; - *str += "A mage with the Summon Skeletons skill may summon " - "skeletons into his inventory, to aid him in battle. " - "Skeletons may be given to other units, as they follow " - "instructions mindlessly; however, they have a 10 percent " - "chance of decaying each turn. A mage can summon skeletons " - "at an average rate of 40 percent times his level squared. " - "To use the spell, use the order CAST Summon_Skeletons, " - "and the mage will summon as many skeletons as he is able."; - break; - case S_RAISE_UNDEAD: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_UNDEAD)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Raise Undead skill may summon undead " - "into his inventory, to aid him in battle. Undead may be " - "given to other units, as they follow instructions " - "mindlessly; however, they have a 10 percent chance of " - "decaying each turn. A mage can summon undead at an average " - "rate of 10 percent times his level squared. To use the " - "spell, use the order CAST Raise_Undead and the mage will " - "summon as many undead as he is able."; - } else { - *str += AString("A mage with the Raise Undead skill may summon undead " - "into his inventory, to aid him in combat. Undead may be given " - "to other units, as they follow instructions " - "mindlessly; however, they have a 6.7% chance of " - "decaying each turn. " - "For every ten undead summoned, this spell ") - + EnergyString(skill,1,6,1) + - " To use this spell, " - "the mage should issue the order CAST Raise_Undead , " - "where is the number of undead the mage wishes to " - "summon. If no number is specified, then the mage will " - "summon as many undead as he is able."; - } - break; - case S_SUMMON_LICH: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_LICH)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Summon Lich skill may summon a lich " - "into his inventory, to aid him in battle. Liches may be " - "given to other units, as they follow instructions " - "mindlessly; however, they have a 10 percent chance of " - "decaying each turn. A mage has a 2 percent times his level " - "squared chance of summoning a lich; to summon a lich, use " - "the order CAST Summon_Lich."; - } else { - *str += AString("A mage with the Summon Lich skill may summon liches " - "into his inventory, to aid him in battle. A mage may summon " - "one lich per month. Each lich " - "has a 6.7% chance of decaying each month. " - " This spell ") + EnergyString(skill,1,6,1) + - "To use this spell, the mage should issue the order CAST Summon_Lich."; - } - break; - case S_CREATE_AURA_OF_FEAR: - if(level > 1) break; - break; - case S_SUMMON_BLACK_WIND: - if(level > 1) break; - break; - case S_BANISH_UNDEAD: - if(level > 1) break; - break; - case S_DEMON_LORE: - if(level > 1) break; - *str += "Demon Lore is the art of summoning and controlling " - "demons. The Demon Lore skill does not give the mage any " - "direct skills, but is required to study further into the " - "Demonic arts. A mage with knowledge of Demon Lore will " - "detect the use of Demon Lore by any other mage in the same " - "region."; - break; - case S_SUMMON_IMPS: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_IMP)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Summon Imps skill may summon imps into " - "his inventory, to aid him in combat. A mage may summon one " - "imp per skill level; however, the imps have a chance of " - "breaking free of the mage's control at the end of each " - "turn. This chance is based on the number of imps in the " - "mage's control; if the mage has his skill level squared " - "times 4 imps, the chance is 5 percent; this chance goes " - "up or down quickly if the mage controls more or fewer imps. " - "To use this spell, the mage should issue the order CAST " - "Summon_Imps, and the mage will summon as many imps as he " - "is able."; - } else { - *str += AString("A mage with the Demon Lore skill can summon imps " - "into his inventory, to aid him in combat. Imps have a chance of " - "breaking free of the mage's control at the end of each " - "turn. This chance is based on the number of imps in the " - "mage's control; if the mage has his skill level squared " - "times 4 imps, the chance is 5 percent; this chance goes " - "up or down quickly if the mage controls more or fewer imps. " - "For every ten imps summoned, this spell ") - + EnergyString(skill,1,6,1) + " In addition, " - "the mage will spend energy every turn maintaining control " - "over the imps in his possession. This maintenance " - "cost is one energy per ten imps at level 1 for a mage, " - "decreases with increasing skill level. " - "To use this spell, " - "the mage should issue the order CAST Demon_Lore , " - "where is the number of imps the mage wishes to " - "summon. If no number is specified, then the mage will " - "summon as many imps as he is able."; - } - break; - case S_SUMMON_DEMON: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_DEMON)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Summon Demon skill may summon demons " - "into his inventory, to aid him in combat. A mage may summon " - "one demon each turn; however, the demons have a chance of " - "breaking free of the mage's control at the end of each " - "turn. This chance is based on the number of demons in the " - "mage's control; if the mage has a number of demons equal " - "to his skill level squared, the chance is 5 percent; this " - "chance goes up or down quickly if the mage controls more or " - "fewer demons. To use this spell, the mage should issue the " - "order CAST Summon_Demon."; - } else { - *str += AString("A mage with the Summon Demon skill can summon demons " - "into his inventory, to aid him in combat. Demons have a chance of " - "breaking free of the mage's control at the end of each " - "turn. This chance is based on the number of demons in the " - "mage's control; if the mage has his skill level squared " - "demons, the chance is 5 percent; this chance goes " - "up or down quickly if the mage controls more or fewer demons. " - "For every ten demons summoned, this spell ") - + EnergyString(skill,1,6,1) + " In addition, " - "the mage will spend energy every turn maintaining control " - "over the demons in his possession. This maintenance " - "cost is one energy per demon at level 1, and " - "decreases with increasing skill level. " - "To use this spell, " - "the mage should issue the order CAST Summon_Demon , " - "where is the number of demons the mage wishes to " - "summon. If no number is specified, then the mage will " - "summon as many demons as he is able."; - } - break; - case S_SUMMON_BALROG: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_BALROG)) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Summon Balrog skill may summon a balrog " - "into his inventory, to aid him in combat. A mage has a 20 " - "percent times his skill level chance of summoning a balrog, " - "but may only summon a balrog if one is not already under " - "his control. As with other demons, the balrog has a chance " - "of breaking free of the mage's control at the end of each " - "turn. This chance is equal to 1 over 4 times the mage's " - "skill level to the fourth power (or, from 1 over 4 at " - "level 1, to 1 over 2500 at level 5). To use this spell, " - "the mage should issue the order CAST Summon_Balrog."; - } else { - *str += AString("A mage with the Summon Balrog skill may summon balrogs " - "into his inventory, to aid him in battle. A mage may summon " - "one balrog per month, and have up to his skill level divided " - "by 2, rounded up, balrogs in his inventory at once. As with " - "other demons, balrogs have a chance " - "of breaking free of the mage's control at the end of each " - "turn. This chance is equal to the number of balrogs, squared, " - "over 10 times the mage's skill level squared (or, from 1 " - "over 10 with one balrog at level 1, to 9 over 360 with three " - "balrogs at level 6). This spell ") - + EnergyString(skill,1,6,1) + " If the mage already has a balrog " - "under his control, then the mage's skill level will be reduced by " - "2 per balrog in energy calculations (thus, summoning a second balrog " - "at level 3 costs the same as the first balrog at level 1).In addition, " - "the mage will spend energy every turn maintaining control " - "over the balrogs in his possession. This maintenance " - "cost is seven energy per balrog at level 1, and " - "decreases with increasing skill level. " - "To use this spell, " - "the mage should issue the order CAST Summon_Balrog."; - } - break; - case S_BANISH_DEMONS: - if(level > 1) break; - break; - case S_ILLUSION: - if(level > 1) break; - *str += "Illusion is the magic of creating images of things that " - "do not actually exist. The Illusion skill does not have any " - "direct applications, but is required for further study of " - "Illusionary magic. A mage with knowledge of the Illusion " - "skill will detect the use of Illusion by any other mage in " - "the same region."; - break; - case S_PHANTASMAL_ENTERTAINMENT: - /* XXX -- This should be cleaner somehow */ - if(level > 1) break; - if(Globals->ARCADIA_MAGIC) { - *str += "Gladiators are trained to use their battle skills " - "for entertainment, and the best gladiators can earn " - "far more money than regular entertainers. The " - "Gladiator skill effectively grants a hero an " - "entertainment bonus equal to ten times his Gladiator " - "skill level. To use this skill, use the ENTERTAIN " - "order."; - } else { - *str += "A mage with the Phantasmal Entertainment skill may use " - "his powers of Illusion to earn money by creating " - "illusionary fireworks, puppet shows, etc. In effect, " - "Phantasmal Entertainment grants the mage Entertainment " - "skill equal to five times his Phantasmal Entertainment " - "level. To use this skill, use the ENTERTAIN order."; - } - break; - case S_CREATE_PHANTASMAL_BEASTS: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "A mage with Create Phantasmal Beasts may summon " - "illusionary beasts that appear in the mage's inventory. " - "These beasts will fight in combat, but do not attack, " - "and are killed whenever they are attacked."; - if(ITEM_ENABLED(I_IWOLF)) { - *str += " Create Phantasmal Beasts at level 1 allows the " - "mage to summon illusionary wolves; the number the " - "mage can summon, or have in his inventory at one " - "time is equal to the mage's skill squared times 4. " - "To use this spell, the mage should CAST " - "Create_Phantasmal_Beasts WOLF , where " - " is the number of wolves that the mage " - "wishes to have appear in his inventory."; - } - *str += " Note: illusionary beasts will appear on reports as " - "if they were normal items, except on the owner's " - "report, where they are marked as illusionary. To " - "reference these items in orders, you must prepend an " - "'i' to the normal string. (For example: to reference " - "an illusionary wolf, you would use 'iwolf')."; - } else if (level == 3) { - if(ITEM_DISABLED(I_IEAGLE)) break; - *str += "Create Phantasmal Beasts at level 3 allows the mage " - "to summon illusionary eagles into his inventory. To " - "summon illusionary eagles, the mage should CAST " - "Create_Phantasmal_Beasts EAGLE , where " - "is the number of eagles that the mage wishes to have " - "appear in his inventory. The number of eagles that a " - "mage may have in his inventory is equal to his skill " - "level, minus 2, squared."; - } else if(level == 5) { - if(ITEM_DISABLED(I_IDRAGON)) break; - *str += "Create Phantasmal Beasts at level 5 allows the " - "mage to summon an illusionary dragon into his " - "inventory. To summon an illusionary dragon, the mage " - "should CAST Create_Phantasmal_Beasts DRAGON; the mage " - "can only have one illusionary dragon in his inventory " - "at one time."; - } - break; - case S_CREATE_PHANTASMAL_UNDEAD: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "A mage with Create Phantasmal Undead may summon " - "illusionary undead that appear in the mage's inventory. " - "These undead will fight in combat, but do not attack, " - "and are killed whenever they are attacked."; - if(ITEM_ENABLED(I_ISKELETON)) { - *str += " Create Phantasmal Undead at level 1 allows the " - "mage to summon illusionary skeletons; the number " - "the mage can summon, or have in his inventory at " - "one time is equal to the mage's skill squared times " - "4. To use this spell, the mage should CAST " - "Create_Phantasmal_Undead SKELETON , where " - " is the number of skeletons that the mage " - "wishes to have appear in his inventory."; - } - *str += " Note: illusionary undead will appear on reports as " - "if they were normal items, except on the owner's " - "report, where they are marked as illusionary. To " - "reference these items in orders, you must prepend an " - "'i' to the normal string. (Example: to reference an " - "illusionary skeleton, you would use 'iskeleton')."; - } else if(level == 3) { - if(ITEM_DISABLED(I_IUNDEAD)) break; - *str += "Create Phantasmal Undead at level 3 allows the mage " - "to summon illusionary undead into his inventory. To " - "summon illusionary undead, the mage should CAST " - "Create_Phantasmal_Undead UNDEAD , where " - "is the number of undead that the mage wishes to have " - "appear in his inventory. The number of undead that a " - "mage may have in his inventory is equal to his skill " - "level, minus 2, squared."; - } else if (level == 5) { - if(ITEM_DISABLED(I_ILICH)) break; - *str += "Create Phantasmal Undead at level 5 allows the mage " - "to summon an illusionary lich into his inventory. To " - "summon an illusionary lich, the mage should CAST " - "Create_Phantasmal_Undead LICH; the mage can only have " - "one illusionary lich in his inventory at one time."; - } - break; - case S_CREATE_PHANTASMAL_DEMONS: - /* XXX -- This should be cleaner somehow. */ - if(level == 1) { - *str += "A mage with Create Phantasmal Demons may summon " - "illusionary demons that appear in the mage's " - "inventory. These demons will fight in combat, but " - "do not attack, and are killed whenever they are " - "attacked."; - if(ITEM_ENABLED(I_IIMP)) { - *str += " Create Phantasmal Demons at level 1 allows the " - "mage to summon illusionary imps; the number the " - "mage can summon, or have in his inventory at one " - "time is equal to the mage's skill squared times 4. " - "To use this spell, the mage should CAST " - "Create_Phantasmal_Demons IMP , where " - " is the number of imps that the mage wishes " - "to have appear in his inventory."; - } - *str += " Note: illusionary demons will appear on reports as " - "if they were normal items, except on the owner's " - "report, where they are marked as illusionary. To " - "reference these items in orders, you must prepend an " - "'i' to the normal string. (Example: to reference an " - "illusionary imp, you would use 'iimp')."; - } else if (level == 3) { - if(ITEM_DISABLED(I_IDEMON)) break; - *str += "Create Phantasmal Demons at level 3 allows the mage " - "to summon illusionary demons into his inventory. To " - "summon illusionary demons, the mage should CAST " - "Create_Phantasmal_Demons DEMON , where " - "is the number of demons that the mage wishes to have " - "appear in his inventory. The number of demons that a " - "mage may have in his inventory is equal to his skill " - "level, minus 2, squared."; - } else if (level == 5) { - if(ITEM_DISABLED(I_IBALROG)) break; - *str += "Create Phantasmal Demons at level 5 allows the mage " - "to summon an illusionary balrog into his inventory. To " - "summon an illusionary balrog, the mage should CAST " - "Create_Phantasmal_Demons BALROG; the mage can only have " - "one illusionary balrog in his inventory at one time."; - } - break; - case S_INVISIBILITY: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - *str += "The Invisibility skill allows a mage to render other " - "units nearly invisible to other factions, giving them a +"; - if(Globals->ARCADIA_MAGIC) *str += AString(2); - else *str += AString(3); - *str += " bonus to Stealth. This invisibility will last until the " - "next Magic round. To cast this spell, use the order CAST " - "Invisibility UNITS ..., where is a list of " - "the units that the mage wishes to render invisible. A mage " - "may render invisible a number of men or creatures up to " - "his skill level squared."; - if(Globals->ARCADIA_MAGIC) - *str += AString(" For every (skill level) units that the mage casts " - "invisibility on, this spell ") + EnergyString(skill,1,6,1) + - " In addition, a mage with invisibility will gain a bonus " - "to his Stealth skill equal to his Invisibility skill " - "divided by 2, rounded up (ie 1 at level 1 up to 3 at level 6)."; - break; - case S_TRUE_SEEING: - if(level > 1) break; - *str += "A mage with the True Seeing spell can see illusions " - "for what they really are. Whether or not the mage can see " - "through the illusion depends on his True Seeing skill " - "being higher that the Illusion skill of the mage casting " - "the illusion. This spell does not require any order to " - "use; it is used automatically."; - if(SKILL_ENABLED(S_OBSERVATION)) { - *str += "In addition, a mage with the True Seeing skill " - "receives a bonus to his Observation skill equal to his " - "True Seeing skill divided by 2, rounded up."; - } - break; - case S_DISPEL_ILLUSIONS: - if(level > 1) break; - break; - case S_ARTIFACT_LORE: - if(level == 1) { - *str += "Artifact Lore is one of the most advanced forms of " - "magic; in general, creation of an artifact requires both " - "Artifact Lore, and the appropriate skill for the item being " - "created. A mage with knowledge of the Artifact Lore skill " - "will detect the use of Artifact Lore by any other mage in " - "the region."; - if(Globals->ARCADIA_MAGIC) { - *str += AString(" In addition, a mage at level 1 may create amulets of " - "protection, which grant the possessor a " - "personal Spirit Shield of 3. A mage may create up to his skill " - "level squared of these amulets per turn. For every skill " - "level amulets created, this spell ") + EnergyString(skill,1,6,1) + - " To use this spell, CAST Artifact_Lore Protection, and " - "the mage will create as many amulets of protection as he " - "is able."; - } - } else if(level == 3) { - if(Globals->ARCADIA_MAGIC) { - *str += AString("A mage with artifact lore at level 3 may create " - "shieldstones, which grant the possessor a " - "personal Energy Shield of 3. A mage may create up to his skill " - "level squared of shieldstones per turn. For every skill " - "level shieldstones created, this spell ") + EnergyString(skill,3,6,1) + - " To use this spell, CAST Artifact_Lore Shieldstone, and " - "the mage will create as many shieldstones as he " - "is able."; - } - } - break; - case S_CREATE_RING_OF_INVISIBILITY: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_RINGOFI)) break; - if(level > 1) break; - *str += "A mage with the Create Ring of Invisibility skill may " - "create a Ring of Invisibility, which grants a 3 bonus to a " - "unit's effective Stealth (note that a unit must possess " - "one ring for each man to gain this bonus)."; - if(ITEM_ENABLED(I_AMULETOFTS)) { - *str += " A Ring of Invisibility has one limitation; a " - "unit possessing a ring cannot assassinate, nor steal " - "from, a unit with an Amulet of True Seeing."; - } - if(!Globals->ARCADIA_MAGIC) { - *str += " A mage has a 20 percent times his level chance to " - "create a Ring of Invisibility. To use this spell, the mage " - "should CAST Create_Ring_of_Invisibility."; - } else { - *str += AString(" This skill ") + - EnergyString(skill,1,6,1) + " To use this " - "spell, CAST Create_Ring_of_Invisibility."; - } - break; - case S_CREATE_CLOAK_OF_INVULNERABILITY: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_CLOAKOFI)) break; - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Create Cloak of Invulnerability skill " - "may create a Cloak of Invulnerability. A mage has a 20 " - "percent times his level chance to create a Cloak of " - "Invulnerability. To use this spell, the mage should CAST " - "Create_Cloak_of_Invulnerability."; - } else { - *str += AString("A mage with the Create Cloak of Invulnerability skill " - "may create a Cloak of Invulnerability. This " - "skill ") + EnergyString(skill,1,6,1) + " To use this " - "spell, CAST Create_Cloak_of_Invulnerability."; - } - break; - case S_CREATE_STAFF_OF_FIRE: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_STAFFOFF)) break; - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Create Staff of Fire skill may create a " - "Staff of Fire. A Staff of Fire allows any mage to throw " - "fireballs in combat as if he had a Fire skill of 3. A mage " - "has a 20 percent times his level chance to create a Staff " - "of Fire. To use this spell, CAST Create_Staff_of_Fire."; - } else { - *str += AString("A mage with the Create Staff of Fire skill may create a " - "Staff of Fire. A Staff of Fire allows any mage to throw " - "fireballs in combat as if he had a Fire skill of 3. This " - "skill ") + EnergyString(skill,1,6,1) + " To use this " - "spell, CAST Create_Staff_of_Fire."; - } - break; - case S_CREATE_STAFF_OF_LIGHTNING: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_STAFFOFL)) break; - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Create Staff of Lightning skill may " - "create a Staff of Lightning. A Staff of Lightning allows " - "any mage to call down lightning bolts as if he had Call " - "Lightning skill of 3. A mage has a 20 percent times his " - "level chance to create a Staff of Lightning. To use this " - "spell, CAST Create_Staff_of_Lightning."; - } else { - *str += AString("A mage with the Create Staff of Lightning skill may " - "create a Staff of Lightning. A Staff of Lightning allows " - "any mage to call down lightning bolts as if he had Call " - "Lightning skill of 3. This skill ") + - EnergyString(skill,1,6,1) + " To use this " - "spell, CAST Create_Staff_of_Lightning."; - } - break; - case S_CREATE_AMULET_OF_TRUE_SEEING: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_AMULETOFTS)) break; - if(level > 1) break; - *str += "A mage with the Create Amulet of Tree Seeing skill may " - "create an Amulet of True Seeing. This amulet gives the " - "possessor a bonus of 2 to his effective Observation skill."; - if(ITEM_ENABLED(I_RINGOFI)) { - *str += "Also, a unit with an Amulet of True Seeing cannot " - "be assassinated by, nor have items stolen by, a unit " - "with a Ring of Invisibility (Note that the unit must " - "have at least one Amulet of True Seeing per man to " - "repel a unit with a Ring of Invisibility)."; - } - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage has a 20 percent times his skill level chance to " - "create an Amulet of True Seeing. To use this spell, CAST " - "Create_Amulet_of_True_Seeing."; - } else { - *str += AString(" This skill ") + - EnergyString(skill,1,6,1) + " To use this " - "spell, CAST Create_Amulet_of_True_Seeing."; - } - break; - case S_CREATE_AMULET_OF_PROTECTION: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_AMULETOFP)) break; - if(level > 1) break; - *str += "A mage with the Create Amulet of Protection skill may " - "create Amulets of Protection, which grants the possesor a " - "personal Spirit Shield of 3. A mage may create his skill " - "level of these amulets per turn. To use this spell, CAST " - "Create_Amulet_of_Protection."; - break; - case S_CREATE_RUNESWORD: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_RUNESWORD)) break; - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Create Runesword skill may create a " - "Runesword, which when wielded in combat gives the wielder " - "a plus 5 bonus to Combat skill, and also allows the wielder " - "to project an Aura of Fear in battle, as if he had Create " - "Aura of Fear skill of level 2 (provided the wielder is " - "not casting any other combat spells). A mage has a 20 " - "percent times his skill level chance of creating a " - "Runesword. To cast this spell, CAST Create_Runesword."; - } else { - WeaponType *pW = FindWeapon("RUNE"); - BattleItemType *bt = FindBattleItem("RUNE"); - *str += AString("A mage with the Create Runesword skill may create a " - "Runesword, which when wielded in combat "); - if(pW) *str += AString("gives the wielder a plus ") + pW->attackBonus + - " bonus to Combat skill"; - if(pW && bt) *str += ", and also "; - if(bt) *str += AString("allows the wielder " - "to project an Aura of Fear in battle, as if he had Create " - "Aura of Fear skill of level ") + bt->skillLevel + " (provided the wielder is " - "not casting any other combat spells). This skill " + - EnergyString(skill,1,6,1) + " To use this " - "spell, CAST Create_Runesword."; - } - break; - case S_CREATE_SHIELDSTONE: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_SHIELDSTONE)) break; - if(level > 1) break; - *str += "A mage with the Create Shieldstone skill may create " - "Shieldstones, which confers upon the possessor a personal " - "Energy Shield of 3. A mage may create his skill level in " - "Shieldstones per turn. To use this spell, CAST " - "Create_Shieldstone"; - break; - case S_CREATE_MAGIC_CARPET: - /* XXX -- This should be cleaner somehow. */ - if(ITEM_DISABLED(I_MCARPET)) break; - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Create Magic Carpet skill may create " - "Magic Carpets, which provide for flying transportation. A " - "Magic Carpet can carry up to 15 weight units in the air. " - "Casting this spell allows the mage to create his skill " - "level in Magic Carpets. To cast the spell, CAST " - "Create_Magic_Carpet."; - } else { - *str += AString("A mage with the Create Magic Carpet skill may create " - "Magic Carpets, which provide for flying transportation. A " - "Magic Carpet can carry up to ") + ItemDefs[I_MCARPET].fly + - " weight units in the air. A mage may create up to his skill " - "level squared carpets per turn. For every skill " - "level carpets created, this spell " + EnergyString(skill,1,6,1) + - " To use this spell, CAST Create_Magic_Carpet, and " - "the mage will create as many magic carpets as he " - "is able."; - } - break; - case S_ENGRAVE_RUNES_OF_WARDING: - /* XXX -- This should be cleaner somehow. */ - if(!Globals->ARCADIA_MAGIC) { - if(level == 1) { - *str += "A mage with the Engrave Runes of Warding may " - "engrave runes of warding on a building; these runes " - "will give any occupants of the building a personal " - "Energy Shield and Spirit Shield, both at level 3. A " - "mage has a 20 percent chance per level of succeeding " - "with each attempt to cast this spell. To use this " - "spell, the mage should CAST Engrave_Runes_of_Warding, " - "and be within the building he wishes to engrave runes " - "upon. This spell costs 600 silver to cast."; - if(OBJECT_ENABLED(O_TOWER)) { - *str += " At level 1, the mage may engrave runes of " - "warding upon a Tower."; - } - } else if (level == 2) { - int comma = 0; - if(OBJECT_DISABLED(O_FORT) && OBJECT_DISABLED(O_MTOWER)) - break; - *str += "At this level, the mage may engrave runes of " - "warding upon "; - if(OBJECT_ENABLED(O_FORT)) { - *str += "a Fort"; - comma = 1; - } - if(OBJECT_ENABLED(O_MTOWER)) { - if(comma) *str += ", and "; - *str += "a Magic Tower"; - } - *str += "."; - } else if (level == 3) { - if(OBJECT_ENABLED(O_CASTLE)) { - *str += "At this level, the mage may engrave runes of " - "warding upon a Castle."; - } - } else if (level == 4) { - if(OBJECT_ENABLED(O_CITADEL)) { - *str += "At this level, the mage may engrave runes of " - "warding upon a Citadel."; - } - } else if(level == 5) { - if(OBJECT_ENABLED(O_MFORTRESS)) { - *str += "At this level, the mage may engrave runes of " - "warding upon a Magical Fortress, which grants " - "the inhabitants an Energy Shield and Spirit " - "Shield at level 5."; - } - } - break; - } else { - if(level == 1) { - *str += "A mage with the Engrave Runes of Warding may " - "engrave runes of warding on a building; these runes " - "will increase the defence skill of any occupants " - "against energy, spirit and weather attacks by the mage's skill " - "level (at time of casting). To use this " - "spell, the mage should CAST Engrave_Runes_of_Warding, " - "and be within the building he wishes to engrave runes " - "upon. At level 1 this spell may be cast on a "; - - int found = 0; - AString temp = ""; - for(int i=0; i 0 && ObjectDefs[i].protect < 40) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += AString(", which ") + EnergyString(skill,1,6,1); - - } else if (level == 2) { - *str += "At level 2 this spell may be cast on a "; - - int found = 0; - AString temp = ""; - for(int i=0; i 39 && ObjectDefs[i].protect < 200) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += AString(", which ") + EnergyString(skill,2,6,2); - } else if (level == 3) { - *str += "At level 3 this spell may be cast on a "; - - int found = 0; - AString temp = ""; - for(int i=0; i 199 && ObjectDefs[i].protect < 1000) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += AString(", which ") + EnergyString(skill,3,6,3); - } else if (level == 4) { - *str += "At level 4 this spell may be cast on a "; - - int found = 0; - AString temp = ""; - for(int i=0; i 999) { - if(found++) { - *str += temp; - *str += ", "; - } - temp = ObjectDefs[i].name; - } - } - if(found>1) *str += AString("or ") + temp; - else *str += temp; - *str += AString(", which ") + EnergyString(skill,4,6,4); - } - break; - } - case S_CONSTRUCT_GATE: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(!Globals->ARCADIA_MAGIC) { - *str += "A mage with the Construct Gate skill may construct a " - "Gate in a region. The mage has a 20 percent times his " - "skill level chance of success, and the attempt costs 1000 " - "silver. To use this spell, the mage should issue the order " - "CAST Construct_Gate."; - } else { - *str += AString("A mage with the Construct Gate skill may construct a " - "Gate in a region. This spell ") + EnergyString(skill,1,6,1) + - " To use this spell, the mage should issue the order " - "CAST Construct_Gate."; - } - break; - case S_ENCHANT_SWORDS: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_MSWORD)) break; - *str += "A mage with the Enchant Swords skill may convert " - "swords to mithril swords. A mage may convert 5 times his " - "skill level swords to mithril swords per turn. The mage should " - "issue the order CAST Enchant_Swords to cast this spell."; - if(Globals->ARCADIA_MAGIC) *str += AString(" For every two swords " - "enchanted, this spell ") + EnergyString(skill,1,6,2); - break; - case S_ENCHANT_ARMOR: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_MPLATE)) break; - *str += "A mage with the Enchant Armour skill may magically " - "convert plate armour to mithril armour. A mage may create 5 times his skill " - "level mithril armours per turn. The mage should issue the " - "order CAST Enchant_Armour to cast this spell."; - if(Globals->ARCADIA_MAGIC) *str += AString(" For every two armour " - "enchanted, this spell ") + EnergyString(skill,1,6,2); - break; - case S_CONSTRUCT_PORTAL: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_MPLATE)) break; - *str += "A mage with the Construct Portal skill may construct a " - "Portal"; - if(SKILL_ENABLED(S_PORTAL_LORE)) { - *str += " for use with the Portal Lore skill"; - } - *str += ". The mage has a 20 percent times his skill level " - "chance of creating a Portal, and the attempt costs 600 " - "silver. To use this spell, CAST Construct_Portal."; - break; - case S_MANIPULATE: - if(!Globals->APPRENTICES_EXIST) break; - if(level > 1) break; - *str += "A unit with this skill becomes an apprentice mage. " - "While apprentices cannot cast spells directly, they can " - "use magic items normally only usable by mages. Continued " - "study of this skill gives no further advantages."; - break; - case S_WEAPONCRAFT: - if(level > 1) break; - *str += "The weaponcraft skill is an advanced version of the " - "weaponsmith skill."; - break; - case S_ARMORCRAFT: - if(level > 1) break; - *str += "The armourcraft skill is an advanced version of the " - "armoursmith skill."; - break; - case S_CAMELTRAINING: - if(level > 1) break; - *str += "This skill deals with all aspects of camel production."; - break; - case S_GEMCUTTING: - if(level > 1) break; - *str += "This skill enables a unit to fashion higher quality " - "gems from lower quality ones."; - break; - case S_MONSTERTRAINING: - if(level > 1) break; - *str += "This skill deals with all aspects of training monster " - "mounts."; - break; - case S_COOKING: - if(level > 1) break; - *str += "This skill deals with creating provisions from basic " - "foodstuffs. A skilled cook can feed many more people " - "than a farmer alone."; - break; - case S_CREATE_FOOD: - /* XXX -- This should be cleaner somehow. */ - if(level > 1) break; - if(ITEM_DISABLED(I_FOOD)) break; - *str += "A mage with the Create Food skill may magically " - "create food. A mage may create 5 times his skill level " - "provisions per turn. The mage should issue the order " - "CAST Create_Food to cast this spell."; - break; - case S_BLIZZARD: //Arcadia - if(level == 1) { - *str += AString("A mage with the Blizzard skill may cast blizzards on distant regions. " - "The blizzard will make movement into the region take ten times as " - "many movement points as normal, effectively preventing movement into " - "the region in almost all cases. "); - if(!(SkillDefs[S_CLEAR_SKIES].flags & SkillType::DISABLED)) { - *str += AString(" This spell is overwritten by the spell ") + - SkillDefs[S_CLEAR_SKIES].name + ", that is, if both are cast " - "on the same region, blizzard will have no effect. "; - } - *str += AString("This spell ") + EnergyString(skill,1,6,1); - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to cast across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Blizzard REGION " - " where , , and are the " - "coordinates of the region where you wish to " - "cast the blizzard. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Blizzard cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Blizzard REGION " - " , where and are the coordinates " - "of the region where you wish to cast the " - "blizzard."; - } - } else { - *str += " To use the spell in this fashion, CAST " - "Blizzard; no arguments are necessary."; - } - } else if(level == 4) { - *str += AString("At level 4, a mage may cast a blizzard on a region and all six " - "surrounding regions at once. This spell ") + EnergyString(skill,4,6,4) + - " To use the spell in this fashion, " - "CAST Blizzard LARGE"; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += " REGION where , , and are the " - "coordinates of the central region around which you wish to " - "cast the large blizzard. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - } else { - *str += " REGION , where and are the " - "coordinates of the central region around which you " - "wish to cast the large blizzard."; - } - *str += " This spell uses the same range calculation as the " - "normal blizzard spell, but the caster's effective skill " - "level is reduced by 2 for calculating the maximum range"; - } - *str += AString(". This skill costs ") + (4*SkillDefs[S_BLIZZARD].cast_cost) - + " energy if cast by a " + SkillDefs[SkillDefs[S_BLIZZARD].baseskill].name - + " mage, or " + ((SkillDefs[S_BLIZZARD].cast_cost * 3 * 4)/2) - + " energy when cast by any other mage."; - } - break; - case S_FOG: //Arcadia - if(level == 1) { - *str += AString("A mage with the Fog skill may summon fog into a region, " - "concealing all units in the hex from being seen by factions " - "other than the faction which owns them for the month after " - "the spell is cast. Note that this applies only to the report, " - "it does not allow units to steal or assassinate from enemies if " - "they would normally not be able to do so, nor prevent exchanges, " - "attacks, or give orders, if the target unit number is known. " - "This spell may be dispelled by " - "clear skies cast at equal or higher skill level. To use the spell, " - "a mage should CAST Fog, no arguments are necessary. This skill ") - + EnergyString(skill,1,6,1) + " When " - "used in battle, this spell interferes with the tactical " - "effectiveness of enemy officers, by a multiplicative factor of " - "0.7 per skill level (ie at skill level 2, the tactics effectiveness " - "would be 0.7 squared times their usual effectiveness). This " - "is cumulative with any reduction due to the darkness spell. " - "If multiple mages cast fog in battle, only the highest level " - "spell will have an effect."; - } else if (level == 4) { - *str = AString("At skill level 4, a fog mage may summon fog into a region and " - "all neighbouring regions at once. The fog need not be centred on the " - "mage, it can be centred on any of the six regions surrounding him. " - "To use this spell, CAST Fog Large , where direction is " - "the direction in which the fog should be centred, relative to the " - "mage. If no direction is specified, then the fog will be centred on " - "the region the mage is located in. This spell ") - + EnergyString(skill,4,6,4); - } - break; - case S_SEAWARD: //Arcadia - if(level == 1) { - *str += AString("A mage with the Sea Ward skill may harness the furies of the " - "wind to keep the ocean from invading a region which would otherwise " - "sink. This ward will last for half the mage's skill level, rounded up, months, " - "after which, if it is not recast, the region will sink. This ward " - "will also be destroyed if another mage rejuvenates this region to " - "ocean. This spell ") + EnergyString(skill,1,6,1); - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to cast across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Sea_Ward REGION " - " where , , and are the " - "coordinates of the region from which you wish to " - "ward the sea. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Sea Ward cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Sea_Ward REGION " - " , where and are the coordinates " - "of the region from which you wish to ward the " - "sea."; - } - *str += " This spell will fail if cast on a region which " - "is not sinking in the month the spell is cast."; - } else { - *str += " To use this spell, CAST " - "Sea_Ward; no arguments are necessary."; - } - } else if(level == 4) { - *str += AString("At level 4, a mage may cast a sea ward on a region and all six " - "surrounding regions at once. This spell ") + EnergyString(skill,4,6,3) + - " To use the spell in this fashion, " - "CAST Sea_Ward LARGE"; - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += " REGION where , , and are the " - "coordinates of the central region around which you wish to " - "cast the sea ward. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - } else { - *str += " REGION , where and are the " - "coordinates of the central region around which you " - "wish to cast the sea ward."; - } - *str += " This spell uses the same range calculation as the " - "normal sea ward spell, but the caster's effective skill " - "level is reduced by 2 for calculating the maximum range"; - } - *str += ". This spell will fail if none of the affected regions are " - "sinking in the month the spell is cast, though the central region " - "need not be sinking itself."; - } - break; - case S_CONCEALMENT: //Arcadia - if(level > 1) break; - *str += "Concealment is a combat spell. When cast in a combat round, " - "any formation from the caster's army which attempt to " - "flank around the enemy in that round will have a 33% chance, " - "times the skill level of the caster, to remain unseen and " - "unintercepted. If an enemy mage casts 'dispel illusions' in " - "the same combat round, then the effective skill level of this " - "spell will be reduced by the skill level of that enemy mage. " - "Only the best mage casting concealment has an effect. Unfortunately, " - "battle commanders are not yet intelligent enough to factor this " - "spell into their decisions, so this spell will not cause " - "cavalry to flank if they normally would not due to too much " - "enemy cavalry opposition."; - break; - case S_ILLUSORY_CREATURES: //Arcadia - if(level > 4) break; - //quick coding, doesn't write properly if GM disables any of the illusory creatures. - //also the maintenance costs of illusory creatures (and summoned creatures) are currently hardcoded. - if(level == 1) { - *str += "A mage with Create Illusory Creatures may summon " - "illusionary creaturess that appear in the mage's inventory. " - "These beasts will fight in combat, but attack and defend with a skill of -10, " - "giving them no chance to hit anything, " - "nor to survive an attack. At skill " - "level 1, a mage may create illusionary"; - if(ITEM_ENABLED(I_IWOLF)) *str += " wolves,"; - if(ITEM_ENABLED(I_IIMP)) *str += " imps,"; - if(ITEM_ENABLED(I_ISKELETON)) *str += " and skeletons."; - *str += "To use this spell, the mage should CAST " - "Create_Illusory_Creatures , " - "where is the type of illusion the mage " - "wishes to summon, and is how many of that " - "illusion the mage wishes to have appear in his inventory."; - *str += " Note: illusionary beasts will appear on reports as " - "if they were normal items, except on the owner's " - "report, where they are marked as illusionary. To " - "reference these items in orders, you must prepend an " - "'i' to the normal string. (For example: to reference " - "an illusionary wolf, you would use 'iwolf'). " - "For every point of energy, a mage can " - "create 20 illusions, multiplied by his skill level " - "plus two, and divided by three (that is, 20 illusions " - "at level 1, up to 53 illusions at level 6). Provided a mage has sufficient energy, " - "there is no limit to how many illusions he can create, " - "note however that there is an additional 'maintenance' " - "cost to sustain these illusions, equal to 1 energy " - "per 80 illusions per month at level 1, decreasing " - "with skill level."; - } else if (level == 2) { - *str += "Create Illusory Creatures at level 2 allows the mage " - "to summon illusionary eagles, demons and undead into his " - "inventory. To summon these illusions, a mage should use the " - "usual order for creating illusory creatures, with the appropriate " - "type of creature used in the order. These illusions cost " - "ten times more to summon and sustain than illusory imps, " - "wolves, or skeletons."; - } else if(level == 3) { - *str += "Create Illusory Creatures at level 3 allows the mage " - "to summon illusionary gryffins, balrogs and liches into his " - "inventory. To summon these illusions, a mage should use the " - "usual order for creating illusory creatures, with the appropriate " - "type of creature used in the order. These illusions cost " - "forty times more to summon and sustain than illusory imps, " - "wolves, or skeletons."; - } else if(level == 4) { - *str += "Create Illusory Creatures at level 4 allows the mage " - "to summon illusionary dragons into his " - "inventory. To summon illusory dragons, a mage should use the " - "usual order for creating illusory creatures, with 'DRAGON' " - "as the creature used in the order. Illusory dragons cost " - "160 times more to summon, and 80 times more to sustain, than illusory imps, " - "wolves, or skeletons (4 energy per dragon to summon at level 4)."; - } - break; - case S_SUMMON_MEN: //Arcadia - if(level > 1) break; - *str += AString("A mage with this skill may summon men into a unit belonging " - "to his faction, and in the same region as the mage. To use " - "this skill, CAST Summon_Men unit , where " - "is the number of men the mage wishes to summon, is the race " - "the mage wishes to summon, and is the unit which the men are " - "to be summoned into. A mage using this skill may not summon leaders, nor " - "summon men into a unit containing leaders, nor summon men into a unit " - "controlled by another faction. This skill costs 50 silver " - "to hire each man which is summoned. A mage may summon at most 10 times " - "his skill level squared men. For every ten men summoned, this spell ") - + EnergyString(skill,1,6,1); - break; - - case S_RESURRECTION: //Arcadia - if(level == 1) { - *str += "This skill enables the mage to resurrect men who would " - "usually be given up for dead. At higher levels, a mage with this skill may " - "attempt to resurrect units from his own or an allied " - "faction who have been assassinated in " - "the mage's region, or even resurrect him/herself. " - "From level 1, in battle a mage may attempt to resurrect " - "up to 4 times his skill level squared men who died and could " - "not be healed (from 4 corpses at level 1, up to 144 corpses " - "at level 6). All resurrection attempts have a 50 percent " - "rate of success."; - if(Globals->ARCADIA_MAGIC && SkillDefs[skill].combat_cost > 0) - *str += AString(" For every skill level times 3 corpses that " - "a mage attempts to raise, this spell will cost a " - "mage ") + SkillDefs[skill].combat_cost + " energy."; - *str += " No order is necessary to use this spell, " - "it will be used automatically when the mage is involved in " - "battle. Note that if a mage is resurrected, he will suffer " - "a penalty to his energy levels thereafter."; - } else if(level == 3) { - *str += "At level 3, a mage will automatically attempt to resurrect " - "men from his own or allied factions which are assassinated in " - "the mage's region. Because the mage has only one corpse to focus " - "on, his success rate may be higher than that following battles; " - "the chance of success is 15% multiplied by the mage's skill level."; - if(Globals->ARCADIA_MAGIC && SkillDefs[skill].cast_cost > 0) - *str += AString(" This spell ") + EnergyString(skill,3,6,1); - } else if(level == 5) { - *str += "At level 5, a mage can practise the greatest art of resurrection, " - "raising himself from the dead when killed in combat. " - "This skill will always work, providing the mage has enough " - "energy to cast it at the time of his death, but it exacts " - "the usual power toll on the mage. The mage will come back to life after the " - "end of the battle or assassination he was killed in. "; - *str += AString("This spell ") + EnergyString(skill,5,6,4); - } - break; - case S_SPIRIT_OF_DEAD: //Arcadia - if(level > 1) break; - *str += AString("A mage with this skill may summon the spirit of a long dead mage, " - "and attempt to convert them to their cause. To use" - "this skill, CAST Summon_Spirit_of_the_Dead UNITS , where " - "is the unit number of a dead mage who died at the mage's current " - "location. If no number is specified, then the mage " - "will receive a list of all the shades which are at his current " - "location. The chance of this spell succeeding " - "is the caster's skill level divided by 6 (ie 1 chance in 6 at level 1). If the target mage was from " - "a different faction, then it may not be willing to join you; there is " - "a twenty percent chance per month that a dead mage will lose loyalty " - "to it's previous faction. Any resurrected mage will suffer a penalty to " - "their energy supply, equivalent to having N less levels in each " - "foundation skill, where N is the total number of times they have been " - "resurrected. For every month that the mage has lain in the land of the " - "dead, they will lose 30 days of study or experience in a random magic skill. " - "To resurrect a spirit, this spell ") + EnergyString(skill,1,6,1) + - " To check if spirits are present in a location, this cost is divided by " - "five, rounded up."; - break; - case S_INNER_STRENGTH: //Arcadia - if(level > 1) break; - *str += "A mage with this skill learns to focus inwards, and " - "concentrate on harnessing his magics more efficiently. This " - "skill gives a bonus to the rate a mage recharges his magic energies, " - "equal to 5% of his normal rate (rounded down), plus one energy per skill level per month."; - break; - case S_TRANSMUTATION: //Arcadia - if(level == 1) { - *str += AString("This skill deals with the alteration of all objects. " - "At level 1, a mage with this skill may magically transmute any " - "item into one normal primary item of a different type. " - "Primary items are ones produced directly from " - "a region, not manufactured from other items. To use this spell, CAST Transmutation " - " , and the mage will transmute as many items " - "in his possession as he is able. A mage is able to transmute up to " - "four times his skill level squared " - "items. Each eight items which are transmuted, ") - + EnergyString(skill,1,6,1); - break; - } else if(level == 2) { - *str += "At level 2, a mage with this skill may magically transmute any " - "manufactured item into one normal item of a different type. " - "To use this spell, CAST Transmutation " - " , and the mage will transmute as many items " - "in his possession as he is able. A mage is able to transmute up to " - "four times his skill level squared " - "items. Items which require " - "more than one material to manufacture, such as Plate Armour, cannot be " - "produced with this spell."; - break; - } else if(level == 5) { - *str += "At level 5, a mage with this skill may magically transmute any three " - "normal primary items into one advanced item of similar type, if one exists. " - "The possible conversions which may be made are:"; - if(!(ItemDefs[I_IRON].flags & ItemType::DISABLED) && !(ItemDefs[I_MITHRIL].flags & ItemType::DISABLED) ) - *str += " iron to mithril"; - if(!(ItemDefs[I_WOOD].flags & ItemType::DISABLED) && !(ItemDefs[I_IRONWOOD].flags & ItemType::DISABLED) ) - *str += ", wood to ironwood"; - if(!(ItemDefs[I_WOOD].flags & ItemType::DISABLED) && !(ItemDefs[I_YEW].flags & ItemType::DISABLED) ) - *str += ", wood to yew"; - if(!(ItemDefs[I_FISH].flags & ItemType::DISABLED) && !(ItemDefs[I_PEARL].flags & ItemType::DISABLED) ) - *str += ", fish to pearls"; - if(!(ItemDefs[I_STONE].flags & ItemType::DISABLED) && !(ItemDefs[I_ROOTSTONE].flags & ItemType::DISABLED) ) - *str += ", stone to rootstone"; - if(!(ItemDefs[I_HERBS].flags & ItemType::DISABLED) && !(ItemDefs[I_MUSHROOM].flags & ItemType::DISABLED) ) - *str += ", herbs to mushrooms"; - if(!(ItemDefs[I_FUR].flags & ItemType::DISABLED) && !(ItemDefs[I_FLOATER].flags & ItemType::DISABLED) ) - *str += ", furs to floater"; - if(!(ItemDefs[I_HORSE].flags & ItemType::DISABLED) && !(ItemDefs[I_WHORSE].flags & ItemType::DISABLED) ) - *str += ", horses to winged horses"; - *str += AString(". To use this spell, CAST Transmutation " - ", and the mage will transmute as many items " - "in his possession as he is able. A mage is able to transmute up to " - "six times his skill level squared items, into two times his " - "skill level squared advanced items. " - "Each two items which are produced, ") - + EnergyString(skill,4,6,1); - break; - } - break; - case S_MODIFICATION: //Earthsea - if(level == 1) { - *str += AString("This skill allows a mage to harness the magics " - "of the land itself, and use it to modify the terrain " - "around him. At level 1, a mage may increase the base amount " - "of any normal resource that is already present in a " - "region, at the cost of reducing the amount of another normal " - "resource. For every (4+skill) for which the sought " - "resource is increased, the other resource will be " - "decreased by 5, resulting in a net increase in " - "production at level 2 or higher. " - "The amount of the sought resource " - "will be increased by 6 times the mage's skill level, " - " up to a maximum of " - "(1+skill/2) times the minimum amount the region would " - "naturally support. For every resource increased, this spell ") - + EnergyString(skill,1,6,1); - - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to view across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Modification Increase REGION " - " where , , and are the " - "coordinates of the region you wish to " - "modify. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Modification cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Modification Increase REGION " - " , where and are the coordinates " - "of the region you wish to modify."; - } - } else { - *str += " To use the spell in this fashion, CAST " - "Modification Increase ."; - } - } else if(level == 3) { - *str += "At level 3, a mage with modification may decrease " - "the base amount " - "of any normal resource present in a " - "region, at the cost of increasing the amount of another normal " - "resource. For every (skill) by which the unwanted " - "resource is decreased, the other resource will be " - "increased by 3, resulting in a net loss of production " - "at level 4 or higher. " - "The amount of the unwanted resource " - "will be decreased by 6 times the mage's skill level, " - "to a minimum of 1, provided that the other resource is " - "not increased beyond a maximum of " - "(1+skill/2) times the minimum amount the region would " - "naturally support. The energy cost of this spell is the " - "same, per resource decreased, as the cost per resource " - "increased when increasing resources."; - - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to view across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Modification Decrease " - " REGION " - " where , , and are the " - "coordinates of the region you wish to " - "modify. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Modification cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Modification Decrease " - " REGION " - " , where and are the coordinates " - "of the region you wish to modify."; - } - } else { - *str += " To use the spell in this fashion, CAST " - "Modification Decrease ."; - } - } else if(level == 4) { - *str += AString("At skill level 4, a modification mage may increase " - "the levels of advanced resources in a region at the " - "cost of decreasing a normal resource. This works " - "exactly the same as with normal resources, except that " - "the mage's effective skill level is reduced by 2 in " - "all calculations, and for every resource increased, this spell ") - + EnergyString(skill,4,6,4); - - } else if(level == 5) { - *str += "At skill level 5, a modification mage may decrease " - "the levels of advanced resources in a region at the " - "cost of increasing another resource. This works " - "exactly the same as with decreasing normal resources, except that " - "the mage's effective skill level is reduced by 2 in " - "all calculations, and the spell cost is as for " - "increasing advanced resources."; - } - break; - case S_REJUVENATION: //Earthsea - if(level == 2) break; - if(level == 4) break; - if(level == 1) { - *str += AString("This skill allows a mage to change the underlying " - "magic of the land itself, converting it to a completely " - "different type of terrain. At skill level 1, a mage may " - "convert any land region into any other type of land " - "region, regenerating local products and wages in the process " - "(the new region may be the same as the old type, in which " - "case only the products and wages will change). Possible " - "land types which may be created are: plain, forest, mountain, " - "swamp, jungle, desert, tundra. This spell ") - + EnergyString(skill,1,6,1); - - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to view across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Rejuvenation " - " REGION " - " where , , and are the " - "coordinates of the region you wish to " - "rejuvenate. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Rejuvenation cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Rejuvenation " - " REGION " - " , where and are the coordinates " - "of the region you wish to rejuvenate."; - } - } else { - *str += " To use the spell in this fashion, CAST " - "Rejuvenation ."; - } - - - - - } else if(level == 3) { - *str += AString("At skill level 3, a mage may convert an ocean or lake " - "region into a land region of any type. Using this spell " - "in this fashion ") + EnergyString(skill,1,4,2); - } else if(level == 5) { - *str += AString("At skill level 5, a mage may convert a region " - "into an ocean or lake region. The change will take place " - "at the end of the month after the spell is cast, and the " - "region will be marked as sinking in the intervening " - "report. Any units which remain when the region sinks " - "will drown. The region specified should be 'ocean', " - "even if it will form a lake when sunk. Casting rejuvenation " - "in this manner ") + EnergyString(skill,1,2,3); - } - break; - case S_DIVERSION: //Earthsea - if(level > 1) break; - *str += AString("This skill allows a mage to divert the flow of major rivers. " - "When cast on a region, rivers will be removed from all edges where " - "they are placed, and transferred to all edges which did not " - "previously have a river or coastline feature (beach, rocks, harbour). " - "In the case whereby two or more rivers join in the region, then the " - "edges will be broken into sections according to where rivers enter/exit the " - "region. The section with no river will have a river added, and the segment " - "clockwise from there will have the river removed. " - "Repeated use of this spell allows the path of an entire river to " - "be diverted. This spell ") + EnergyString(skill,1,6,1); - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to view across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += "To use this skill, CAST Diversion REGION " - " where , , and are the " - "coordinates of the region where you wish to " - "divert the river. If you omit the " - "coordinate, the coordinate of the caster's " - "current region will be used."; - if(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS == 1) { - *str += " The coordinate for the surface is " - "'1' and the -coordinate for the " - "underworld is '2'."; - } - *str += " Note that Diversion cannot be used " - "either into or out of the Nexus."; - } else { - *str += "To use this skill, CAST Diversion REGION " - " , where and are the coordinates " - "of the region where you wish to divert the " - "river."; - } - } else { - *str += " To use the spell in this fashion, CAST " - "Diversion; no arguments are necessary."; - } - break; - case S_GRYFFIN_LORE: //Earthsea - if(level > 1) break; - *str += "A hero with the Gryffin Lore skill can tame gryffins to " - "join him, to aid in battle and provide flying " - "transportation. A hero may have up to his skill level divided " - "by 2, rounded up, gryffins in his inventory at once. When " - "cast, a hero has a 10% chance, times their effective skill level, " - "of taming a new gryffin each month. A hero's effective skill level " - "is equal to their gryffin lore skill, less two times the number " - "of gryffins they already control. To use this spell, " - "the hero should issue the order CAST Gryffin_Lore."; - break; - case S_HYPNOSIS: //Earthsea - if(level == 1) { - *str += AString("This skill allows a mage to obtain limited control " - "over enemy units for a single month. This spell will " - "affect only the target units' month long orders. At " - "skill level 1 a mage may order a target unit to work, " - "tax, or produce. This skill cannot target mages. To use " - "this spell, CAST Hypnosis UNITS ..., " - "where is a list of the units that the mage wishes " - "to hypnotise. A mage may hypnotise a number of men " - "equal to his skill level squared, times ten. For every ten " - "men times his skill level the mage hypnotises, this spell ") + - EnergyString(skill,1,6,1) + " If the mage " - "attempts to hypnotise more men than he is able, then the units " - "at the start of the unit list will be hypnotised, up until " - "the total number of men exceeds the maximum allowed (if " - "this is the case for the first unit, then no units will be " - "hypnotised. Valid " - "arguments for are: 'WORK', 'TAX', 'PRODUCE " - "'."; - } else if(level == 2) { - *str += "At skill level 2, a hypnosis mage may hypnotise " - "unit to study. To use this spell in this fashion, use " - "'STUDY ' as the order in a hypnotise spell. Note " - "that a unit may not be hypnotised into studying magic " - "or apprentice skills."; - } else if(level == 3) { - *str += "At skill level 3, a hypnosis mage may hypnotise a " - "unit to move. To use this spell in this fashion, use" - "'MOVE ...' as the order in a hypnotise spell, where " - " is a list of the directions that the unit(s) should " - "move."; - } else if(level == 4) { - *str += "At skill level 4, a hypnosis mage may hypnotise a " - "unit to advance. To use this spell in this fashion, use" - "'ADVANCE ...' as the order in a hypnosis spell, where " - " is a list of the directions that the unit(s) should " - "advance."; - } else if(level == 5) { - *str += "At skill level 5, a hypnosis mage may hypnotise a " - "unit to pillage or sail. To use this spell in this fashion, use " - "'PILLAGE', or 'SAIL ...' as the order in a hypnosis " - "spell, where is a list of the directions the unit(s) should " - "advance."; - } - break; - case S_BINDING: //Earthsea - if(level > 1) break; - *str += "This is a combat skill. It enables a mage to bind an enemy " - "mage during combat, preventing him from spellcasting for the " - "remainder of the battle. The success of this spell is dependent " - "on the power of the casting and target mage, as well as the mage's " - "skill level. The chance of success is power * level, out of a total " - "of (power * level + enemypower * (3 + enemylevel/2)), where level " - "and enemylevel are the greater of the mage's skill in " - "either binding or dragon lore. Because this skill is a contest " - "of magic between mages, if the caster runs out of energy " - "during the battle, he will not cast this spell again, at " - "a reduced skill or otherwise."; - break; - case S_CREATE_PORTAL: //Earthsea - if(level > 1) break; - *str += "This skill allows a mage to create linked portals, " - "allowing himself and other units to move directly from " - "one land region with a portal to another (portals may " - "not be placed in oceans). A portal may be destroyed " - "by any unit within it, but is otherwise kept open by the mage " - "himself, and will be destroyed if anyone attempts to pass " - "through it after the mage dies or runs out " - "of energy. To create a portal, a mage should issue the order 'CAST " - "Create_Portal'. This will create an unlinked portal in the mage's " - "region."; - range = FindRange(SkillDefs[skill].range); - if(range && (range->flags & RangeType::RNG_CROSS_LEVELS)) { - *str += " To link this portal to another, the mage should issue " - "the order 'CAST Create_Portal REGION , where " - ", and are the coordinates of the region where " - "the portal you wish to link to is located."; - } else { - *str += " To link this portal to another, the mage should issue " - "the order 'CAST Create_Portal REGION , where " - " and are the coordinates of the region where " - "the portal you wish to link to is located."; - } - *str += " This will create a second portal linked to the first portal, " - "through which units may then pass."; - //energy cost from units passing through. Hence should protect from enemies. - - range = FindRange(SkillDefs[skill].range); - if(range) { - if(range->flags & RangeType::RNG_SURFACE_ONLY) { - *str += " This skill only works on the surface of " - "the world."; - } - *str += " The target region must be within "; - if(range->rangeMult != 1) { - *str += range->rangeMult; - if(range->rangeClass != RangeType::RNG_ABSOLUTE) *str += " times "; - } - switch(range->rangeClass) { - case RangeType::RNG_LEVEL: - *str += "the caster's skill level"; - break; - case RangeType::RNG_LEVEL2: - *str += "the caster's skill level squared"; - break; - case RangeType::RNG_LEVEL3: - *str += "the caster's skill level cubed"; - break; - default: - case RangeType::RNG_ABSOLUTE: - break; - } - *str += " regions of the caster. "; - if(range->flags & RangeType::RNG_CROSS_LEVELS) { - *str += "Coordinates of locations not on the surface " - "are scaled to the surface coordinates for this " - "calculation. Attempting to link across " - "different levels increases the distance by "; - *str += range->crossLevelPenalty; - *str += " per level difference. "; - *str += " Note that Create Portal cannot be used " - "either into or out of the Nexus."; - } - } else { - *str += " The range function of this spell seems to be disabled. " - "Please contact your GM to have the problem corrected."; - } - *str += AString("If creating a portal, this spell ") + EnergyString(skill,1,6,1) + - " In addition, for every (40 * skill) weight units (or part " - "thereof) which pass through the portal, the mage will lose a point of " - "energy to maintain the portal connection. " - "If the mage does not have enough energy, the portal will collapse. Portals " - "should be kept well guarded, else hostile troops passing through a portal " - "could quickly drain a mage of energy."; - break; - case S_LIGHT: //Earthsea - if(level > 1) break; - *str += "This skill allows the mage to bend light " - "and concentrate it where he sees fit. If darkness " - "is cast in battle, this spell counteracts it, " - "reducing the darkness mage's effective skill level " - "by the light mage's skill level (to a minimum of zero). "; - break; - case S_DARKNESS: //Earthsea - if(level > 1) break; - *str += "This skill allows a mage to deflect light away from his " - "location, bringing an unnatural darkness to the surrounding " - "area. When cast in combat this spell will act like a fog spell " - "and reduce the tactical effectiveness of tactitians in BOTH " - "armies by a multiplicative factor of 0.7 per skill level (ie " - "at skill level 2, the tactics effectiveness will be " - "0.7 squared). This skill will also reduce the attack " - "skill and chance-to-attack of all troops in the battle by the " - "caster's skill level, drastically reducing casualties in the battle. " - "If multiple mages cast darkness, only the highest level spell " - "will have an effect. While darkness can be a very powerful " - "spell, any mage should be careful in using it as it will " - "affect soldiers on both sides of a battle equally."; - break; - case S_DRAGON_TALK: - if(level == 1) { - *str += "This skill enabled a mage to converse with dragons. At level " - "one, it gives the casting mage a chance to convince a dragon " - "to not fight him and his allies, and leave a battle. If the " - "mage fails at this, he may instead be able to bind the " - "dragon from spellcasting during the battle. Each dragon may " - "only be targetted by this spell once per battle, so if " - "multiple mages are casting this spell, the highest level " - "mage may not be the one to target the dragon. The chance " - "of success for this spell is (approximately) dependent on the mage's skill " - "level multiplied by the mage's power (maximum energy). If there are " - "no dragons present to target, then this spell will revert to " - "a normal binding spell, allowing a mage to bind enemy mages. " - "Like binding, if the caster runs our of energy during the " - "battle, he will not cast any more spells in the battle."; - } else if (level == 4) { - *str += "At level 4 of this skill, a mage has an addition chance " - "to convince a dragon to join him in his quests. This chance " - "increases considerably at higher skill levels."; - } - break; - case S_BASE_WINDKEY: //Earthsea - if(level > 1) break; - *str += "Windkey is one of the Foundation skills on which other " - "magical skills are based. This skill deals with the mage's ability " - "to control the wind, weather, and air around them. Mages skilled in windkey are well " - "known for their ability at sea, where they may calm the waters or " - "bring wind to speed a ship. Lesser known skills include the " - "ability to turn air into flame, and to listen on the wind to " - "things far away."; - break; - case S_BASE_ILLUSION: //Earthsea E - if(level > 1) break; - *str += "Illusion is one of the Foundation skills on which other " - "magical skills are based. This skill deals with the mage's ability " - "to summon illusions, which distort the appearance of the world, but " - "have no permanent effects. At their most base level, mages skilled " - "in weaving illusions may be skilled entertainers, but illusions " - "can be used for more insidious purposes as well. Some mages may devote " - "their studies not to creating illusions, but to the ability to see " - "through them and know the world as it truly is. Although these mages " - "may be found anywhere, they are most common in the east."; - break; - case S_BASE_SUMMONING: //Earthsea S - if(level > 1) break;/* - *str += "Summoning is one of the Foundation skills on which other " - "magical skills are based. This skill deals with the mage's ability " - "to summon creatures from other planes of existance into this world, " - "and control them when summoned. Summoners are usually skilled at " - "summoning either from the plane of demons or the lands of death, " - "though some have been known to summon living men as well. Although these mages " - "may be found anywhere, they are most common in the dark southern lands.";*/ - *str += "Summoning is one of the Foundation skills on which other " - "magical skills are based. This skill deals with the mage's ability " - "to summon creatures from other planes of existance into this world, " - "and control them when summoned. Summoners are usually skilled at " - "summoning either from the plane of demons or the lands of death, " - "though some have been known to summon living men as well. And " - "whilst many have learnt to banish summoned creatures, it is rumoured " - "that some summoners even learn to banish the sun itself."; - break; - case S_BASE_PATTERNING: //Earthsea N - if(level > 1) break;/* - *str += "Patterning is one of the Foundation skills on which other " - "magical skills are based. This skill deals with the mage's ability " - "to interact with nature and the magic intrinsic to the land and creatures " - "around him. Skilled patterners may control the beasts of the land, " - "heal creatures or men, or use the " - "magical energy of the land to modify their surroundings in numerous " - "ways. Although these mages " - "may be found anywhere, they are most common in the northern lands.";*/ - *str += "Patterning is one of the Foundation skills on which other " - "magical skills are based. This skill deals with the mage's ability " - "to interact with nature and the magic intrinsic to the world and land " - "around themself. Skilled patterners may alter items in their vicinity, " - "heal creatures or men, or use the " - "magical energy of the land to modify their surroundings in numerous " - "ways."; - break; - case S_BASE_MYSTICISM: //Earthsea - if(level > 1) break; -/* *str += "Mysticism is the most unusual of the magic arts, often spurned by " - "mages as delving into the dark arts. In truth, like any magic, " - "knowledge of mysticism can be used for good or bad. However, any " - "mage who has knowledge of mysticism will be tainted by this knowledge, " - "whatever spell he may be casting. Mages skilled in mysticism draw " - "power from outside themselves, and may channel this great power in " - "their spells. A side effect of this is that many spells cast by " - "mystics will backfire or have unintended consequences. The likelihood " - "of this occuring increases as mysticism makes up a large fraction of the mage's " - "power supply, but decreases slightly as mages become more skilled in " - "the mystic arts. Mages with an innate talent in mysticism are less " - "likely to have spells backfire on them than other mages with similar " - "power drawn from mysticism; however, they will usually also have more " - "of their power drawn from this supply.";*/ - *str += "Mysticism is one of the Foundation skills on which other " - "magical skills are based. It is the most unusual of the magic arts, often spurned by " - "mages as delving into the dark arts. In truth, like any magic, " - "knowledge of mysticism can be used for good or bad, and offense or defence."; - break; - case S_BASE_ARTIFACTLORE: //Earthsea - if(level == 1) { - *str += "Artifact Lore is one of the Foundation skills on which other " - "magical skills are based. This skill deals with a mage's ability " - "to channel magical energy into artifacts, which can be used to " - "aid a mage without drawing on their power. Many artifacts " - "may also be used by men who are neither mages nor heroes."; - *str += AString(" A mage at level 1 may create amulets of " - "protection, which grant the possessor a " - "personal Spirit Shield of 3. A mage may create up to his skill " - "level squared of these amulets per turn. For every skill " - "level amulets created, this spell ") + EnergyString(skill,1,6,1) + - " To use this spell, CAST Artifact_Lore Protection, and " - "the mage will create as many amulets of protection as he " - "is able."; - } else if(level == 3) { - *str += AString("A mage with artifact lore at level 3 may create " - "shieldstones, which grant the possessor a " - "personal Energy Shield of 3. A mage may create up to his skill " - "level squared of shieldstones per turn. For every skill " - "level shieldstones created, this spell ") + EnergyString(skill,3,6,1) + - " To use this spell, CAST Artifact_Lore Shieldstone, and " - "the mage will create as many shieldstones as he " - "is able."; - } - break; - case S_BASE_BATTLETRAINING: //Earthsea - if(level > 1) break; - *str += "This skill allows a hero to gain extra proficiency in battle. The " - "hero's attack skill, and all defence skills, will be increased by " - "his battletraining skill level in combat."; - break; - break; - case S_BASE_CHARISMA: //Earthsea - if(level == 1) { - *str += "Charisma is a powerful tool, and subsequent skills allow heroes to charm or " - "persuade others into aiding the hero. Charisma itself gives a hero " - "the chance to learn from locals of advanced resources in a region, " - "even if the hero would not normally be able to detect them. At skill " - "level 1 the hero has a 50% chance of detecting any advanced resource " - "each month. This skill " - "is used automatically in the region where the hero ends the month, " - "providing there are local peasants."; - } - else { - int cycles = level; - int chance = 1000; - while(cycles--) chance /= 2; - chance = 100 - (chance+5)/10; - *str += AString("At level ") + level + " a hero has a " + chance + "% chance " - "of detecting local advanced resources per month."; - } - break; - case S_TOUGHNESS: //Earthsea - if(level > 1) break; - *str += "A hero with toughness learns to survive the most powerful blows. " - "For each level gained in toughness, the hero will be able to survive " - "an extra (level) hits in battle. That is, 1 extra hit at level 1, 3 " - "at level 2, 6 at level 3, etc. In addition, the hero will be less " - "susceptible to attacks from a distance, gaining a (level):1 chance " - "to avoid ranged or magic attacks that would otherwise be successful."; - break; - case S_UNITY: //Earthsea - if(level > 1) break; - *str += "A hero with unity is able to calm followers, and bring harmony where " - "there was conflict. When used in battle this skill has a 50% chance of eliminating the morale " - "penalty from mixing ethnic types for each of, the hero's skill " - "level squared, times fifty, morale affected soldiers."; - break; - case S_FRENZY: //Earthsea - if(level == 1) { - *str += "A hero with frenzy can perform amaxing feats in battle. " - "At level 1, a hero with frenzy will be more effective against " - "armoured opponents. That is, if the hero's attack is not " - "normally armour-piercing, it will become so, and if it is " - "armour-piercing (due to use of a crossbow or similar) then " - "it will ignore the target's armour altogether. In addition, " - "the hero will gain two extra physical attacks per round; or if using a weapon " - "that only attacks once every 2 rounds, then will make " - "two attacks total per round. Note that this bonus is " - "an addition, not multiplication - if a weapon would usually " - "grant 3 attacks per battle round, then the hero will get " - "3+2 = 5 attacks per round."; - } else { - *str += AString("At level ") + level + " frenzy, a hero gains a bonus " - + 2*level*level + " physical attacks per battle round."; - if(level == 2) *str += " However, if using a weapon that only attacks once " - "every n rounds, then the hero will only get this bonus, divided by n, " - "plus 1 attacks per round."; - *str += AString(" In addition, if the hero scores a hit against a creature " - "with multiple hitpoints, that creature will lose ") + level + - " hitpoints, instead of just 1."; - } - break; - case S_SECSIGHT: //Earthsea - if(level > 1) break; - *str += "Second Sight conveys upon a hero the ability to avoid theft and " - "assassinations directed against him or herself. The hero will get " - "(skill level) attempts to avoid each theft or assassination directed " - "against him or her. Each attempt has a 50% probability of success. " - "This skill has no effect on theft or assassination directed at other " - "units in the region."; - break; - case S_SWIFTNESS: //Earthsea - if(level > 1) break; - *str += "With this skill, heros may become swift as the wind. For " - "can-catch purposes only, the hero's swiftness skill is added " - "to his riding skill, with the following limitations: if the hero's " - "movement mode is walking, he will not get any defensive bonus, " - "if it is riding, he will get a defensive bonus of no more than 3. " - "If the hero does not have an item with sufficient riding capacity " - "to carry the hero, he will not get an offensive bonus, and if he " - "does not have an item with sufficient flying capacity to carry " - "him, he will get an offensive bonus of no more than 3."; - break; - case S_TRADING: //Earthsea - if(level > 1) break; - *str += "Heros can become mighty merchants, and bartering for goods is " - "one of the first skills they learn. For every level in trading, " - "a hero will gain 5% extra above the market price of every item they sell, " - "and pay 5% less for every item they buy (rounded down and up, " - "respectively). Because it is assumed the best person in the " - "region will do the bartering, this bonus also " - "affects any other unit in the region from the same " - "faction or an allied faction. Multiple trading heros do not " - "get any additional bonus; only the highest skill level is used. " - "Also note that, as all your men are natural pessimists, they " - "will never try to buy more items than they could afford at " - "the normal price."; - break; - case S_MERCHANTRY: //Earthsea - if(level == 1) { - *str += "Skilled merchants can find a customer anywhere, although they " - "may not pay well. At skill level 1, this skill allows your hero " - "to sell normal, trade, advanced or magical items at 35% " - "of their withdraw cost (for non-normal items, this value may " - "be found in reference material that comes with the game, or " - "through experimentation). Each additional skill level raises " - "this price by 5% of the withdraw cost. This price will be " - "rounded down, per item. Note that, if a hero attempts to sell " - "items that the local market can buy, the items will be sold " - "through the market at the market price, even if the hero is " - "unable to sell all (or even any) of those items to the local " - "market."; - } else if(level == 4) { - *str += "At level 4, merchants may buy any normal item, anywhere. " - "However, the item will cost 130% of its withdraw price. Each " - "additional level in merchantry reduces the cost by 10% of " - "the withdraw price. This price will be rounded up, per item. " - "Note that, if a hero attempts to buy " - "items that the local market can provide, the items will be bought " - "through the market at the market price, even if the hero is " - "unable to buy all (or even any) of the wanted items from the local " - "market."; - - } else if(level == 6) { - *str += "At level 6, merchants may purchase advanced items, albeit " - "for an arm and a leg. Since spare arms and legs are hard to find, " - "they may instead pay 160% of the withdraw cost of the item, " - "rounded up."; - } - break; - case S_ARCADIA_QUARTERMASTERY: //Earthsea - if(level == 1) { - *str += "The quartermaster skill enables heros to transport items " - "over large distances, free of charge. With this skill, units " - "may use the SEND order to send goods to the hero from up to " - "(skill level) regions away, and the hero may also send goods " - "to other units, up to (skill level) regions away. These " - "transfers will be free, providing either the sender or recipient " - "has the quartermastery skill."; - } else if(level == 4) { - *str += "At level 4, a quartermaster may facilitate the transfer of " - "goods between two other units in a single month. To do so, the " - "sending unit should issue the command 'SEND UNIT VIA " - " '. The specified goods will then " - "be transferred to the target unit for free, provided that the " - "distance from the sender to the quartermaster, plus the distance " - "from the quartermaster to the receiver, is no more than the " - "quartermaster's skill level. Note that, as with the " - "receiver, the quartermaster may not move during the month for " - "this order to succeed."; - } - break; - } - - AString temp; - AString temp1; - AString temp2; - int comma = 0; - int comma1 = 0; - int comma2 = 0; - int last = -1; - int last1 = -1; - int last2 = -1; - unsigned int c; - int i; - - if(level == 1 && (SkillDefs[skill].flags & SkillType::FOUNDATION) ) { - *str += AString(" A mage whose race does not excel in ") + - SkillDefs[skill].name + " will gain an increase to his maximum energy equal to their " + - SkillDefs[skill].name + " skill squared. " - "In addition, the mage's energy recharge will be increased by " - "their " + SkillDefs[skill].name + " skill. If the mage's " - "race does excel in " + SkillDefs[skill].name + ", these " - "energy gains will be doubled."; - } - - - // If this is a combat spell, note it. - if(level == 1 && (SkillDefs[skill].flags & SkillType::COMBAT) && SkillDefs[skill].special) { - *str += AString(" A mage with this skill can cast ") + - ShowSpecial(SkillDefs[skill].special, level, 0, 0); - *str += " In order to use this spell in combat, the mage should use " - "the COMBAT order to set it as his combat spell."; - if(Globals->ARCADIA_MAGIC && SkillDefs[skill].combat_first > 0) { - if(SkillDefs[skill].combat_first == SkillDefs[skill].combat_cost) { - *str += AString(" This spell will cost a mage ") + SkillDefs[skill].combat_cost + - " energy to cast in combat."; - } else { - *str += AString(" This spell will cost a mage ") + SkillDefs[skill].combat_first + - " energy to cast in the first round of combat, or " + SkillDefs[skill].combat_cost + - " energy to cast in subsequent combat rounds."; - } - } - } - - // production and ability to see items - temp += "A unit with this skill is able to determine if a region " - "contains "; - temp1 += "A unit with this skill may PRODUCE "; - temp2 += "A unit with this skill may create "; - SkillType *sk1, *sk2; - sk1 = &SkillDefs[skill]; - for(i = NITEMS - 1; i >= 0; i--) { - if(ITEM_DISABLED(i)) continue; - sk2 = FindSkill(ItemDefs[i].mSkill); - if(sk1 == sk2 && ItemDefs[i].mLevel==level && last2==-1) { - int canmagic = 1; - for(c = 0; c < sizeof(ItemDefs[i].mInput)/sizeof(Materials); c++) { - if(ItemDefs[i].mInput[c].item == -1) continue; - if(ITEM_DISABLED(ItemDefs[i].mInput[c].item)) { - canmagic = 0; - } - } - if(canmagic) { - last2 = i; - } - } - sk2 = FindSkill(ItemDefs[i].pSkill); - if(sk1 == sk2 && ItemDefs[i].pLevel == level) { - int canmake = 1; - int resource = 1; - for(c = 0; c < sizeof(ItemDefs[i].pInput)/sizeof(Materials); c++) { - if(ItemDefs[i].pInput[c].item == -1) continue; - resource = 0; - if(ITEM_DISABLED(ItemDefs[i].pInput[c].item)) { - canmake = 0; - } - } - if(canmake && last1 == -1) { - last1 = i; - } - if(resource && (ItemDefs[i].type & IT_ADVANCED) && last == -1) { - last = i; - } - } - - } - for(i = 0; i < NITEMS; i++) { - if(ITEM_DISABLED(i)) continue; - int illusion = (ItemDefs[i].type & IT_ILLUSION); - sk2 = FindSkill(ItemDefs[i].mSkill); - if(sk1 == sk2 && ItemDefs[i].mLevel == level) { - int canmagic = 1; - for(c = 0; c < sizeof(ItemDefs[i].mInput)/sizeof(Materials); c++) { - if(ItemDefs[i].mInput[c].item == -1) continue; - if(ITEM_DISABLED(ItemDefs[i].mInput[c].item)) { - canmagic = 0; - } - } - if(canmagic) { - if(comma2) { - if(last2 == i) { - if(comma2 > 1) temp2 += ","; - temp2 += " and "; - } else { - temp2 += ", "; - } - } - comma2++; - temp2 += AString(illusion?"illusory ":"") + ItemDefs[i].names; - if(f) { - f->DiscoverItem(i, 1, 1); - } - } - } - sk2 = FindSkill(ItemDefs[i].pSkill); - if(sk1 == sk2 && ItemDefs[i].pLevel == level) { - int canmake = 1; - int resource = 1; - for(c = 0; c < sizeof(ItemDefs[i].pInput)/sizeof(Materials); c++) { - if(ItemDefs[i].pInput[c].item == -1) continue; - resource = 0; - if(ITEM_DISABLED(ItemDefs[i].pInput[c].item)) { - canmake = 0; - } - } - if(canmake) { - if(comma1) { - if(last1 == i) { - if(comma1 > 1) temp1 += ","; - temp1 += " and "; - } else { - temp1 += ", "; - } - } - comma1++; - temp1 += AString(illusion?"illusory ":"") + ItemDefs[i].names; - if(f) { - f->DiscoverItem(i, 1, 1); - } - } - if(resource && (ItemDefs[i].type & IT_ADVANCED)) { - if(comma) { - if(last == i) { - if(comma > 1) temp += ","; - temp += " and "; - } else { - temp += ", "; - } - } - comma++; - temp += AString(illusion?"illusory ":"") + ItemDefs[i].names; - } - } - } - if(comma1) { - if(!(*str == "")) *str += " "; - *str += temp1 + "."; - } - if(comma) { - if(!(*str == "")) *str += " "; - *str += temp + "."; - } - if(comma2) { - if(!(*str == "")) *str += " "; - *str += temp2 + " via magic."; - } - - // Buildings - comma = 0; - temp = "A unit with this skill may BUILD the following structures: "; - for(i = 0; i < NOBJECTS; i++) { - if(OBJECT_DISABLED(i)) continue; - AString skname = SkillDefs[skill].abbr; - if(skname == ObjectDefs[i].skill && ObjectDefs[i].level == level) { - if(comma) temp += ", "; - comma = 1; - temp += ObjectDefs[i].name; - if(f) { - f->objectshows.Add(ObjectDescription(i)); - } - } - } - if(comma) { - if(!(*str == "")) *str += " "; - *str += temp + "."; - } - - //Hexsides - comma = 0; - temp = "A unit with this skill may BUILD the following terrain edge features: "; - for(i = 0; i < NHEXSIDES; i++) { - if(HexsideDefs[i].flags & HexsideType::DISABLED) continue; - AString skname = SkillDefs[skill].abbr; - if(skname == HexsideDefs[i].skill && HexsideDefs[i].level == level) { - if(comma) temp += ", "; - else comma = 1; - temp += HexsideDefs[i].name; - if(f) { - f->terrainshows.Add(HexsideDescription(i)); - } - } - } - if(comma) { - if(!(*str == "")) *str += " "; - *str += temp + "."; - } - - - // Required skills - SkillType *lastpS = NULL; - last = -1; - if(level == 1) { - comma = 0; - int found = 0; - temp = "This skill requires "; - for(c=0; cflags & SkillType::DISABLED)) continue; - found = 1; - if(lastpS == NULL) { - lastpS = pS; - last = c; - continue; - } - temp += SkillStrs(lastpS) + " " + - SkillDefs[skill].depends[last].level + ", "; - lastpS = pS; - last = c; - comma++; - } - if(comma) { - if(SkillDefs[skill].flags & SkillType::STUDYOR) temp += "or "; - else temp += "and "; - } - if (found) { - temp += SkillStrs(lastpS) + " " + - SkillDefs[skill].depends[last].level; - } - - if(found) { - if(!(*str == "")) *str += " "; - *str += temp + " to begin to study."; - } - } - - if(level == 1) { - if(SkillDefs[skill].cost) { - if(!(*str == "")) *str += " "; - *str += AString("This skill costs ") + SkillDefs[skill].cost + - " silver per month of study."; - } - if(SkillDefs[skill].flags & SkillType::SLOWSTUDY) { - if(!(*str == "")) *str += " "; - *str += "This skill is studied at one half the normal speed."; - } - } - - // Tell whether this skill can be taught, studied, or gained through exp - if(SkillDefs[skill].flags & SkillType::NOSTUDY) { - if(!(*str == "")) *str += " "; - *str += "This skill cannot be studied via normal means."; - } - if(SkillDefs[skill].flags & SkillType::NOTEACH) { - if(!(*str == "")) *str += " "; - *str += "This skill cannot be taught to other units."; - } - if((Globals->SKILL_PRACTICE_AMOUNT > 0)) { - if(!(*str == "")) *str += " "; - *str += "This skill cannot be increased through experience."; - } - - temp1 = SkillStrs(skill) + " " + level + ": "; - if(*str == "") { - *str = temp1 + "No skill report."; - } else { - *str = temp1 + *str; - } - return str; -} diff --git a/arcadia/soldier1.cpp b/arcadia/soldier1.cpp deleted file mode 100644 index 56a6262c5..000000000 --- a/arcadia/soldier1.cpp +++ /dev/null @@ -1,741 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#ifndef DEBUG -//#define DEBUG -#endif - -#ifndef DEBUG2 -//#define DEBUG2 -#endif - -#include "army1.h" -#include "formation1.h" -#include "gameio.h" -#include "gamedata.h" - -Soldier::Soldier(Unit * u,Object * o,int regtype,int r,int ass) -{ - inform = 0; - defaultform = 0; - - race = r; - unit = u; - building = 0; - - healing = 0; - healtype = 0; - healitem = -1; - canbehealed = 1; - restinpeace = 0; - regen = 0; - isdead = 0; - exhausted = 0; - illusion = 0; - candragontalk = 0; - if(r == I_DRAGON) candragontalk = 1; - - for(int i=0; icrossbridge); //crossing bridges/walls mod - penalty of 1 usually. Set to zero for others. (Hexside Terrain). - if(u->movementmalus > u->crossbridge) def = - (u->movementmalus); //crossbridge comes from aiding. movementmalus comes from just moving across a bridge. Don't get double penalty if moved across a bridge and aiding across a second bridge. - - if(TerrainDefs[regtype].similar_type == R_OCEAN) def += ObjectDefs[o->type].oceanbonus; - - - askill = def; - - dskill[ATTACK_COMBAT] = def; - dskill[ATTACK_ENERGY] = def; - dskill[ATTACK_SPIRIT] = def; - dskill[ATTACK_WEATHER] = def; - dskill[ATTACK_RIDING] = def; - dskill[ATTACK_RANGED] = def; - for(int i=0; ihits; - maxhits = mt->hits; - if(unit->GetSkill(S_TOUGHNESS)) { - int level = unit->GetSkill(S_TOUGHNESS); - int gain = 0; - while(level > 0) { //2,4,7,11,16,22 - gain += level--; - } - hits += gain; - maxhits += gain; - } - } - - if (ItemDefs[r].type & IT_ILLUSION) { - illusion = 1; - canbehealed = 0; - } - if(ItemDefs[r].type & IT_UNDEAD && Globals->MAGE_UNDEAD_INVINCIBLE) { - canbehealed = 0; - } - - - /* Building bonus */ - if (o->capacity) { - building = o->type; - //should the runes spell be a base or a bonus? Set to a bonus here - for (int i=0; iADVANCED_FORTS) { - protection[i] += ObjectDefs[o->type].defenceArray[i]; - } else - dskill[i] += ObjectDefs[o->type].defenceArray[i]; - } - if (o->runes) { - dskill[ATTACK_ENERGY] += o->runes; - dskill[ATTACK_SPIRIT] += o->runes; - dskill[ATTACK_WEATHER] += o->runes; - } - o->capacity--; - } - /* Is this a monster? */ - if (ItemDefs[r].type & IT_MONSTER) { - MonType *mp = FindMonster(ItemDefs[r].abr, - (ItemDefs[r].type & IT_ILLUSION)); - int illurace = r; - if(ItemDefs[r].type & IT_ILLUSION) { - AString *temp = new AString; - *temp = ItemDefs[r].abr; - illurace = LookupItem(temp); - if(illurace == -1) illurace = r; - delete temp; - } - - if(u->type == U_WMON) - name = AString(mp->name) + " in " + *(unit->name); - else - name = AString(mp->name) + " controlled by " + *(unit->name); - askill += mp->attackLevel; - dskill[ATTACK_COMBAT] += mp->defense[ATTACK_COMBAT]; - dskill[ATTACK_ENERGY] += mp->defense[ATTACK_ENERGY]; - dskill[ATTACK_SPIRIT] += mp->defense[ATTACK_SPIRIT]; - dskill[ATTACK_WEATHER] += mp->defense[ATTACK_WEATHER]; - dskill[ATTACK_RIDING] += mp->defense[ATTACK_RIDING]; - dskill[ATTACK_RANGED] += mp->defense[ATTACK_RANGED]; - - if(ItemDefs[illurace].fly && (terrainflags & TerrainType::FLYINGMOUNTS)) - defaultform = 4; - else if(ItemDefs[illurace].ride && (terrainflags & TerrainType::RIDINGMOUNTS)) - defaultform = 2; - else defaultform = 0; - - damage = 0; - hits = mp->hits; - if (hits < 1) hits = 1; //even illusions get 1 hit. But why list them with 0 in gamedata? - maxhits = hits; - attacks = mp->numAttacks; - if(attacks < 0) attacks = 0; //allow zero attacks for illusions. - special = mp->special; - slevel = mp->specialLevel; - if (Globals->MONSTER_BATTLE_REGEN) { - regen = mp->regen; - if (regen < 0) regen = 0; - } - return; - } - - name = *(unit->name); - - SetupHealing(); //in specials.cpp - SetupSpell(); - SetupCombatItems(); - -#ifdef DEBUG2 -cout << "#"; -#endif - // Set up armor - AString abbr; - int i, item, armorType; - for(i = 0; i < MAX_READY; i++) { - // Check preferred armor first. - item = unit->readyArmor[i]; - if(item == -1) break; - abbr = ItemDefs[item].abr; - item = unit->GetArmor(abbr, ass); - if(item != -1) { - armor = item; - break; - } - } - if(armor == -1) { - for(armorType = 1; armorType < NUMARMORS; armorType++) { - abbr = ArmorDefs[armorType].abbr; - item = unit->GetArmor(abbr, ass); - if(item != -1) { - armor = item; - break; - } - } - } - - //need to check if this works properly! - ArmorType *pa = FindArmor(ItemDefs[armor].abr); - if(pa && pa->flags & ArmorType::ONLYONEHIT) { - hits = 1; - maxhits = 1; - } - - // - // Check if this unit is mounted - // - int canFly = (terrainflags & TerrainType::FLYINGMOUNTS); - int canRide = (terrainflags & TerrainType::RIDINGMOUNTS); - int ocean = (TerrainDefs[regtype].similar_type == R_OCEAN); - - ridingbonus = 0; - int formtype = 0; - if(canFly || canRide || ocean) { - // - // Mounts of some type _are_ allowed in this region - // - int mountType; - for(mountType = 1; mountType < NUMMOUNTS; mountType++) { - abbr = MountDefs[mountType].abbr; - - item = unit->GetMount(abbr, canFly, canRide, ocean, ridingbonus, formtype); - if(item == -1) continue; - // Defer adding the combat bonus until we know if the weapon - // allows it. The defense bonus for riding can be added now - // however. - /* What about buildings? Riding in buildings?! BS */ - if(formtype == 4 && (terrainflags & TerrainType::FLYINGLIMITED)) { - ridingbonus = 0; - } - if(formtype == 2 && (terrainflags & TerrainType::RIDINGLIMITED)) { - ridingbonus = 0; - } - dskill[ATTACK_RIDING] += ridingbonus; - riding = item; - break; - } - } - - // Assign correct formtype for soldier - if(u->GetFlag(FLAG_FIGHTASFOOT)) formtype = 0; - if(formtype>3 && u->GetFlag(FLAG_FIGHTASRIDE)) formtype = 2; - - if(u->GetFlag(FLAG_BEHIND)) formtype += 1; - defaultform = formtype; - - // - // Find the correct weapon for this soldier. - // - int weaponType; - int attackBonus = 0; - int defenseBonus = 0; - int numAttacks = 1; - for(i = 0; i < MAX_READY; i++) { - // Check the preferred weapon first. - item = unit->readyWeapon[i]; - if(item == -1) break; - abbr = ItemDefs[item].abr; - item = unit->GetWeapon(abbr, riding, ridingbonus, attackBonus, - defenseBonus, numAttacks); - if(item != -1) { - weapon = item; - break; - } - } - - if(weapon == -1) { - for(weaponType = 1; weaponType < NUMWEAPONS; weaponType++) { - abbr = WeaponDefs[weaponType].abbr; - item = unit->GetWeapon(abbr, riding, ridingbonus, attackBonus, - defenseBonus, numAttacks); - if(item != -1) { - weapon = item; - break; - } - } - } -#ifdef DEBUG2 -cout << "$"; -#endif - // If we did not get a weapon, set attack and defense bonuses to - // combat skill (and riding bonus if applicable). - if(weapon == -1) { - attackBonus = unit->GetAttribute("combat") + ridingbonus; - defenseBonus = attackBonus; - numAttacks = 1; - } else { - // Okay. We got a weapon. If this weapon also has a special - // and we don't have a special set, use that special. - // Weapons (like Runeswords) which are both weapons and battle - // items will be skipped in the battle items setup and handled - // here. - if ((ItemDefs[weapon].type & IT_BATTLE)) { - BattleItemType *pBat = FindBattleItem(ItemDefs[weapon].abr); - //BS mod - only do so if battleitem is set to make a special; if ever have one which makes a shield, then add the shield coding here. - if(special == NULL && pBat->flags & BattleItemType::SPECIAL) { - special = pBat->special; - slevel = pBat->skillLevel; - } - //BS - BattleItemType::ENERGY is dealt with in DoSpellCost below - } - //set attacktype to weapontype - WeaponType *pWep = FindWeapon(ItemDefs[weapon].abr); - attacktype = pWep->attackType; - } - - unit->PracticeAttribute("combat"); - - // Set the attack and defense skills - // These will include the riding bonus if they should be included. - askill += attackBonus; - dskill[ATTACK_COMBAT] += defenseBonus; - - if(unit->GetSkill(S_BASE_BATTLETRAINING)) { - int gain = unit->GetSkill(S_BASE_BATTLETRAINING); - askill += gain; - dskill[ATTACK_COMBAT] += gain; - dskill[ATTACK_ENERGY] += (gain+1)/2; - dskill[ATTACK_SPIRIT] += (gain+1)/2; - dskill[ATTACK_WEATHER] += (gain+1)/2; - dskill[ATTACK_RIDING] += gain; - dskill[ATTACK_RANGED] += (gain+1)/2; //TODO: Update description - } - - - /* Xanaxino Mod */ -/* if(regtype == R_JUNGLE || regtype == R_FOREST) { - ManType *mt = FindRace(ItemDefs[race].abr); - if(mt->ethnicity == RA_ELF) { - dskill[ATTACK_COMBAT] += 1; - dskill[ATTACK_ENERGY] += 1; - dskill[ATTACK_SPIRIT] += 1; - dskill[ATTACK_WEATHER] += 1; - dskill[ATTACK_RIDING] += 1; - dskill[ATTACK_RANGED] += 1; - } - }*/ - - attacks = numAttacks; - - if(unit->GetSkill(S_FRENZY)) { - int level = unit->GetSkill(S_FRENZY); - int gain = 2*level*level; //+2,8,18,32,50,72 (*50% later) - if(attacks < 0) attacks = 1 - gain/attacks; //ie bonus/rounds + 1. - else attacks += gain; - } -} - -Soldier::~Soldier() -{ - #ifdef DEBUG2 - Awrite("Soldier Destructor"); - #endif -} - - -void Soldier::SetupSpell() -{ - if (unit->type != U_MAGE && unit->type != U_GUARDMAGE) return; - - if (unit->combat != -1) { - slevel = unit->GetSkill(unit->combat); - if(!slevel) { - // - // The unit can't cast this spell! - // - unit->combat = -1; - return; - } - - SkillType *pST = &SkillDefs[unit->combat]; - if(!(pST->flags & SkillType::COMBAT)) { - // - // This isn't a combat spell! - // - unit->combat = -1; - return; - } - - special = pST->special; - unit->Practice(unit->combat); - } -} - -void Soldier::SetupCombatItems() -{ - int battleType; - for(battleType = 1; battleType < NUMBATTLEITEMS; battleType++) { - BattleItemType *pBat = &BattleItemDefs[battleType]; - - AString abbr = pBat->abbr; - int item = unit->GetBattleItem(abbr); - if(item == -1) continue; - - // If we are using the ready command, skip this item unless - // it's the right one, or unless it is a shield which doesn't - // need preparing. - if(!Globals->USE_PREPARE_COMMAND || - ((unit->readyItem == -1) && - (Globals->USE_PREPARE_COMMAND == GameDefs::PREPARE_NORMAL)) || - (item == unit->readyItem) || - (pBat->flags & BattleItemType::SHIELD)) { - if((pBat->flags & BattleItemType::SPECIAL) && special != NULL) { - // This unit already has a special attack so give the item - // back to the unit as they aren't going to use it. - unit->items.SetNum(item, unit->items.GetNum(item)+1); - continue; - } - if(pBat->flags & BattleItemType::MAGEONLY && - unit->type != U_MAGE && unit->type != U_GUARDMAGE && - unit->type != U_APPRENTICE) { - // Only mages/apprentices can use this item so give the - // item back to the unit as they aren't going to use it. - unit->items.SetNum(item, unit->items.GetNum(item)+1); - continue; - } - - /* Make sure amulets of invulnerability are marked */ - if(item == I_AMULETOFI) { - amuletofi = 1; - } - - SET_BIT(battleItems, battleType); - - if(pBat->flags & BattleItemType::SPECIAL) { - special = pBat->special; - slevel = pBat->skillLevel; - } - - if(pBat->flags & BattleItemType::SHIELD) { - SpecialType *sp = FindSpecial(pBat->special); - /* we have a shield item with no shield FX */ - if(!(sp->effectflags & SpecialType::FX_SHIELD)) { - continue; - } - for(int i = 0; i < 4; i++) { - if(sp->shield[i] == NUM_ATTACK_TYPES) { - for(int j = 0; j < NUM_ATTACK_TYPES; j++) { -// if(dskill[j] < pBat->skillLevel) //BS mod, so bonus is cumulative, not constant. - dskill[j] += pBat->skillLevel; - } - } else if(sp->shield[i] >= 0) { -// if(dskill[sp->shield[i]] < pBat->skillLevel) - dskill[sp->shield[i]] += pBat->skillLevel; - } - } - } - } else { - // We are using prepared items and this item is NOT the one - // we have prepared, so give it back to the unit as they won't - // use it. - unit->items.SetNum(item, unit->items.GetNum(item)+1); - continue; - } - } -} - -int Soldier::ArmorProtect(int weaponClass) -// Returns 1 if the armour is successful -{ - if(weaponClass == NUM_WEAPON_CLASSES) return 0; - - ArmorType *pArm = NULL; - if(armor > 0) pArm = FindArmor(ItemDefs[armor].abr); - if (pArm == NULL) return 0; - int chance = pArm->saves[weaponClass]; - - if(chance <= 0) return 0; - if(chance > getrandom(pArm->from)) return 1; - - return 0; -} - -void Soldier::RestoreItems() -{ - if (healing && healitem != -1) { - if(healitem == I_HERBS) { - unit->items.SetNum(healitem, - unit->items.GetNum(healitem) + healing); - } else if(healitem == I_HEALPOTION) { - unit->items.SetNum(healitem, - unit->items.GetNum(healitem)+healing/5); - } - } - if (weapon != -1) - unit->items.SetNum(weapon,unit->items.GetNum(weapon) + 1); - if(armor != -1) - unit->items.SetNum(armor,unit->items.GetNum(armor) + 1); - if(riding != -1) - unit->items.SetNum(riding,unit->items.GetNum(riding) + 1); - - int battleType; - for(battleType = 1; battleType < NUMBATTLEITEMS; battleType++) { - BattleItemType *pBat = &BattleItemDefs[ battleType ]; - - if(GET_BIT(battleItems, battleType)) { - AString itm(pBat->abbr); - int item = LookupItem(&itm); - unit->items.SetNum(item, unit->items.GetNum(item) + 1); - } - } -} - -void Soldier::Alive(int state) -{ - RestoreItems(); - if(maxhits > hits && (ItemDefs[race].type & IT_MAN)) { - if(unit->GetSkill(S_TOUGHNESS)) unit->Experience(S_TOUGHNESS,60*(maxhits-hits)/maxhits); - } - - if (state == LOSS) { - unit->canattack = 0; - /* Guards with amuletofi will not go off guard */ - if (!amuletofi && - (unit->guard == GUARD_GUARD || unit->guard == GUARD_SET)) { - unit->guard = GUARD_NONE; - } - } else { - unit->advancefrom = 0; - } - - if (state == WIN_NO_MOVE) { - unit->canattack = 0; - unit->nomove = 1; - } -} - -void Soldier::Dead() -{ - RestoreItems(); - - //if it's not a mage, or if it's a non-man from a mage unit, remove it. - if(unit->type != U_MAGE || !(ItemDefs[race].type & IT_MAN)) unit->SetMen(race,unit->GetMen(race) - 1); - //setmen changes the experience/skills. - else unit->dead = unit->faction->num; //ARCADIA_MAGIC mod. Mages don't disappear, they become spirits of the dead. -} - -int Soldier::HasEffect(char *eff) -//imported direct from old code. -{ - if(eff == NULL) return 0; - EffectType *e = FindEffect(eff); - return effects[e->effectnum]; -} - -void Soldier::SetEffect(char *eff, int form, Army *army) -{ - if(eff == NULL) return; - int i; - - EffectType *e = FindEffect(eff); - if (e == NULL) return; - - askill += e->attackVal; - for(i = 0; i < 4; i++) { - if(e->defMods[i].type != -1) - dskill[e->defMods[i].type] += e->defMods[i].val; - } - - if(e->cancelEffect != NULL) ClearEffect(e->cancelEffect); - - if(!(e->flags & EffectType::EFF_NOSET)) effects[e->effectnum] = 1; - - if(e->flags & EffectType::EFF_TRANSFIGURE) { - MonType *mpold = FindMonster(ItemDefs[race].abr, (ItemDefs[race].type & IT_ILLUSION)); - int finalrace = e->monster; - if(race == finalrace) return; - int newrace = -1; - if(maxhits <= 2) { - newrace = finalrace; - if(illusion) newrace = I_IRAT; //Arcadia hack. - } else { - //something to get newrace - //not done in time for Nylandor :(. - } - if(newrace < 0) return; - MonType *mp = FindMonster(ItemDefs[newrace].abr, (ItemDefs[newrace].type & IT_ILLUSION)); - if(!mp || !mpold) return; - unit->items.SetNum(race, unit->items.GetNum(race) - 1); - race = newrace; //change soldier's race. - unit->items.SetNum(race, unit->items.GetNum(race) + 1); - int oldhits = maxhits; - maxhits = mp->hits; - if(!illusion) army->hitstotal += maxhits - oldhits; - army->formations[form].AddSize(maxhits - oldhits); - if(hits > maxhits) hits = maxhits; - - askill += mp->attackLevel - mpold->attackLevel; - dskill[ATTACK_COMBAT] += mp->defense[ATTACK_COMBAT] - mpold->defense[ATTACK_COMBAT]; - dskill[ATTACK_ENERGY] += mp->defense[ATTACK_ENERGY] - mpold->defense[ATTACK_ENERGY]; - dskill[ATTACK_SPIRIT] += mp->defense[ATTACK_SPIRIT] - mpold->defense[ATTACK_SPIRIT]; - dskill[ATTACK_WEATHER] += mp->defense[ATTACK_WEATHER] - mpold->defense[ATTACK_WEATHER]; - dskill[ATTACK_RIDING] += mp->defense[ATTACK_RIDING] - mpold->defense[ATTACK_RIDING]; - dskill[ATTACK_RANGED] += mp->defense[ATTACK_RANGED] - mpold->defense[ATTACK_RANGED]; - - if(unit->type == U_WMON) - name = AString(mp->name) + " in " + *(unit->name); - else - name = AString(mp->name) + " controlled by " + *(unit->name); - //if needed, transfer soldier to new formation. - } -} - -void Soldier::ClearEffect(char *eff) -{ - if(eff == NULL) return; - int i; - - EffectType *e = FindEffect(eff); - if (e == NULL) return; - - if(effects[e->effectnum] == 0) return; - - askill -= e->attackVal; - - for(i = 0; i < 4; i++) { - if(e->defMods[i].type != -1) - dskill[e->defMods[i].type] -= e->defMods[i].val; - } - - effects[e->effectnum] = 0; -} - -//this is called at the end of formations phase (from Formation::Reset from Army::Reset) -void Soldier::ClearOneTimeEffects(void) -{ - for(int i = 0; i < NUMEFFECTS; i++) { - if(EffectDefs[i].flags & EffectType::EFF_ONESHOT) ClearEffect(EffectDefs[i].name); - } -} - - -int Soldier::DoSpellCost(int round, Battle *b) -//returns 1 if can cast the spell, 0 if cannot. -{ - if(!Globals->ARCADIA_MAGIC) return 1; - - //staff of yew coding - if (weapon != -1 && (ItemDefs[weapon].type & IT_BATTLE)) { - - BattleItemType *pBat = FindBattleItem(ItemDefs[weapon].abr); - - if(pBat && (pBat->flags & BattleItemType::ENERGY)) { - //can cast, energy cost of zero. - int exper = 8 - round; //7, 6, then 5, then 4 ... sum of 27 in 6 rounds, then 1 per round. - if(exper < 1) exper = 1; - if(unit->combat != -1) unit->Experience(unit->combat, exper, 0); - return 1; - } - } - - if(!exhausted && unit->type == U_MAGE && unit->combat != -1) { - int cost; - if(round == 1) cost = unit->GetFirstCombatCost(unit->combat); - else cost = unit->GetCombatCost(unit->combat); - if(cost > unit->GetEnergy() ) { - exhausted = 1; - slevel /= 2; - if(!slevel) { - special = NULL; - b->AddLine( *(unit->name) + " is exhausted, and cannot cast any more spells."); - return 0; - } else { - b->AddLine( *(unit->name) + " is exhausted, and will cast with reduced effectiveness."); - unit->energy -= unit->GetEnergy(); //do not want to reduce energy below this, because some might have already been "used" by portalling. - } - } else { - unit->energy -= cost; - int exper = 8 - round; //7, 6, then 5, then 4 ... sum of 27 in 6 rounds, then 1 per round. - if(exper < 1) exper = 1; - unit->Experience(unit->combat, exper, 0); - } - //no experience after running out of energy. - } else if(exhausted && unit->type == U_MAGE && unit->combat != -1 && slevel) { - unit->energy -= unit->GetEnergy(); //just in case wasn't set to zero earlier, eg in dospellcheck - } - int mevent = unit->MysticEvent(); - switch(mevent) { - case 4: - b->AddLine( *(unit->name) + "'s spell backfires, hitting the wrong army."); - return 2; - case 3: - case 2: - case 1: - b->AddLine( *(unit->name) + "'s spell fizzles mid-cast."); - return 0; - default: - break; - } - return 1; -} - -void Soldier::DoSpellCheck(int round, Battle *b) -{ - //staff of yew coding. If have a STAY, return and don't halve spell damage. - if (weapon != -1 && (ItemDefs[weapon].type & IT_BATTLE)) { - BattleItemType *pBat = FindBattleItem(ItemDefs[weapon].abr); - if(pBat->flags & BattleItemType::ENERGY) return; - } - - if(!exhausted && unit->type == U_MAGE && unit->combat != -1) { - int cost; - if(round == 1) cost = unit->GetFirstCombatCost(unit->combat); - else cost = unit->GetCombatCost(unit->combat); - if(cost > unit->GetEnergy() ) { - exhausted = 1; - slevel /= 2; - if(!slevel) { - special = NULL; - b->AddLine( *(unit->name) + "is exhausted, and cannot cast any more spells."); - } else b->AddLine( *(unit->name) + "is exhausted, and will cast with reduced effectiveness."); - } - } - return; -} diff --git a/arcadia/soldier1.h b/arcadia/soldier1.h deleted file mode 100644 index 67c20fe9b..000000000 --- a/arcadia/soldier1.h +++ /dev/null @@ -1,131 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifndef SOLDIER_CLASS -#define SOLDIER_CLASS - -#include -#include -using namespace std; - -class Soldier; - -#include "unit.h" -#include "alist.h" -#include "items.h" -#include "object.h" -#include "shields.h" -#include "helper.h" - -#ifndef DEBUG -//#define DEBUG -//#define DEBUG2 -#endif - -enum { - WIN_MOVE, - WIN_NO_MOVE, - LOSS -}; - -class Soldier -{ - public: - Soldier(Unit *unit, Object *object, int regType, int race, int ass=0); - ~Soldier(); - - void SetupSpell(); - void SetupCombatItems(); - - // - // SetupHealing is actually game-specific, and appears in specials.cpp - // - void SetupHealing(); - - int ArmorProtect(int weaponClass ); - - void RestoreItems(); - void Alive(int); - void Dead(); - - int HasEffect(char *); - void SetEffect(char *, int form, Army *army); - void ClearEffect(char *); - void ClearOneTimeEffects(void); - - int DoSpellCost(int round, Battle *b); - void DoSpellCheck(int round, Battle *b); - - /* Unit info */ - AString name; - Unit * unit; - int race; - int riding; - int ridingbonus; - int building; - - /* Healing information */ - int healing; - int healtype; - int healitem; - int canbehealed; - int restinpeace; - int regen; - - /* Attack info */ - int weapon; - int attacktype; - int askill; - int attacks; - char *special; - int slevel; - int exhausted; - int candragontalk; - - /* Defense info */ - int dskill[NUM_ATTACK_TYPES]; - int protection[NUM_ATTACK_TYPES]; - int armor; - int hits; - int maxhits; - int damage; - int illusion; - - int isdead; - - /* Formation info */ - int inform; - int defaultform; - - BITFIELD battleItems; - int amuletofi; - - /* Effects */ -// map< char *, int > effects; - int effects[5]; -}; - -typedef Soldier * SoldierPtr; - -#endif diff --git a/arcadia/specials.cpp b/arcadia/specials.cpp deleted file mode 100644 index ca0c97762..000000000 --- a/arcadia/specials.cpp +++ /dev/null @@ -1,637 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "battle1.h" -#include "gamedata.h" - -#ifndef DEBUG -//#define DEBUG -#endif - -void Soldier::SetupHealing() -{ - if (unit->type == U_MAGE) { - healtype = unit->GetSkill(S_MAGICAL_HEALING); - if (healtype > 6) healtype = 6; - if (healtype > 0) { - healing = HealDefs[healtype].num; - healitem = -1; - return; - } - } - - if(unit->items.GetNum(I_HEALPOTION)) { - healtype = 1; - unit->items.SetNum(I_HEALPOTION, unit->items.GetNum(I_HEALPOTION)-1); - healing = Globals->HEALS_PER_MAN; // Previously 10, too powerful. - healitem = I_HEALPOTION; - } else { - healing = unit->GetSkill(S_HEALING) * Globals->HEALS_PER_MAN; - if (healing) { - healtype = 1; - int herbs = unit->items.GetNum(I_HERBS); - if (herbs < healing) healing = herbs; - unit->items.SetNum(I_HERBS,herbs - healing); - healitem = I_HERBS; - } - } -} - -int Army::IsSpecialTarget(char *special) const -{ - // Search All Formations - for(int i=0; itargflags & SpecialType::HIT_BUILDINGIF) { - match = 0; - if(!pSoldiers[soldiernum]->building) return 0; - for(i = 0; i < 3; i++) { - if (pSoldiers[soldiernum]->building && - (spd->buildings[i] == pSoldiers[soldiernum]->building)) match = 1; - } - if(!match) return 0; - } - - if(spd->targflags & SpecialType::HIT_BUILDINGEXCEPT) { - match = 0; - if(!pSoldiers[soldiernum]->building) return 0; - for(i = 0; i < 3; i++) { - if (pSoldiers[soldiernum]->building && - (spd->buildings[i] == pSoldiers[soldiernum]->building)) match = 1; - } - if(match) return 0; - } - - if(spd->targflags & SpecialType::HIT_SOLDIERIF) { - match = 0; - if (pSoldiers[soldiernum]->race == -1) return 0; - for(i = 0; i < 7; i++) { - if(pSoldiers[soldiernum]->race == spd->targets[i]) match = 1; - } - if(!match) return 0; - } - - if(spd->targflags & SpecialType::HIT_SOLDIEREXCEPT) { - match = 0; - if (pSoldiers[soldiernum]->race == -1) return 0; - for(i = 0; i < 7; i++) { - if(pSoldiers[soldiernum]->race == spd->targets[i]) match = 1; - } - if(match) return 0; - } - - if(spd->targflags & SpecialType::HIT_EFFECTIF) { - match = 0; - for(i = 0; i < 3; i++) { - if(pSoldiers[soldiernum]->HasEffect(spd->effects[i])) match = 1; - } - if(!match) return 0; - } - - if(spd->targflags & SpecialType::HIT_EFFECTEXCEPT) { - for(i = 0; i < 3; i++) { - if(pSoldiers[soldiernum]->HasEffect(spd->effects[i])) return 0; - } - } - - if(spd->targflags & SpecialType::HIT_MOUNTIF) { - match = 0; - if (pSoldiers[soldiernum]->riding == -1) return 0; - for(i = 0; i < 7; i++) { - if(pSoldiers[soldiernum]->riding == spd->targets[i]) match = 1; - } - if(!match) return 0; - } - - if(spd->targflags & SpecialType::HIT_MOUNTEXCEPT) { - match = 0; - if (pSoldiers[soldiernum]->riding == -1) return 0; - for(i = 0; i < 7; i++) { - if(pSoldiers[soldiernum]->riding == spd->targets[i]) match = 1; - } - if(match) return 0; - } - - if(spd->targflags & SpecialType::HIT_ILLUSION) { - // All illusions are of type monster, so lets make sure we get it - // right. If we ever have other types of illusions, we can change - // this. - if(!(ItemDefs[pSoldiers[soldiernum]->race].type & IT_MONSTER)) - return 0; - if(!(ItemDefs[pSoldiers[soldiernum]->race].type & IT_ILLUSION)) - return 0; - } - - if(spd->targflags & SpecialType::HIT_NOILLUSION) { - if(ItemDefs[pSoldiers[soldiernum]->race].type & IT_ILLUSION) return 0; - } - - if(spd->targflags & SpecialType::HIT_NOMONSTER) { - if(ItemDefs[pSoldiers[soldiernum]->race].type & IT_MONSTER) - return 0; - } - - if(spd->targflags & SpecialType::HIT_MONSTEREXCEPT) { - if (!(ItemDefs[pSoldiers[soldiernum]->race].type & IT_MONSTER)) return 0; //only hits monsters - for(i = 0; i < 7; i++) { - if(pSoldiers[soldiernum]->race == spd->targets[i]) return 0; //a match - so can't hit - } - } - - return 1; -} - -int Army::ShieldIsUseful(char *special) const -{ - SpecialType *shi; - shi = FindSpecial(special); - - // Search All Formations - for(int i=0; iattacks > 0 || (pSold->attacks != 0 && (round % ( -1 * pSold->attacks ) == 1)) ) { - for(int shtype = 0; shtype < 4; shtype++) { - if(shi->shield[shtype] == pSold->attacktype) return 1; - } - } - if(pSold->special) { - //limitations: doesn't check the spell has a target, doesn't check the caster has energy. - SpecialType *spd = FindSpecial(pSold->special); - if(spd->effectflags & SpecialType::FX_DAMAGE) { - for(i = 0; i < 4; i++) { - for(int shtype = 0; shtype < 4; shtype++) { - if(shi->shield[shtype] == spd->damage[i].type) return 1; - } - } - } - } - - } - } - return 0; -} - -void Battle::UpdateShields(Army *a, Army *enemy) -{ - for (int i=0; iNumAlive(); i++) { - int shtype = -1; - SpecialType *spd; - - if(a->GetSoldier(i)->special == NULL) continue; - Soldier *pSold = a->GetSoldier(i); - spd = FindSpecial(pSold->special); - - if(!(spd->effectflags & SpecialType::FX_SHIELD) && - !(spd->effectflags & SpecialType::FX_DEFBONUS)) continue; - - if(!enemy->ShieldIsUseful(pSold->special)) { - AddLine(*(pSold->unit->name) + " chooses not to cast a shield."); - continue; //should shields be cast when not useful? - } - - //energy cost for mages using their combat spell only - if(!pSold->DoSpellCost(a->round, this)) continue; - - if(spd->effectflags & SpecialType::FX_SHIELD) { - for(shtype = 0; shtype < 4; shtype++) { - if(spd->shield[shtype] == -1) continue; - Shield *sh = new Shield; - sh->shieldtype = spd->shield[shtype]; - sh->shieldskill = pSold->slevel; - if(Globals->ARCADIA_MAGIC && sh->shieldtype != ATTACK_RANGED) sh->shieldskill++; //+1 bonus to shield strength - sh->pCaster = pSold; - a->shields.Add(sh); - } - } - - if(spd->effectflags & SpecialType::FX_DEFBONUS && a->round == 1) { //first round is round 1, not 0. - for(shtype = 0; shtype < 4; shtype++) { - if(spd->defs[shtype].type == -1) continue; - int bonus = spd->defs[shtype].val; - if(spd->effectflags & SpecialType::FX_USE_LEV) - bonus *= pSold->slevel; - pSold->dskill[spd->defs[shtype].type] += bonus; - } - } - - AddLine(*(pSold->unit->name) + " casts " + - spd->shielddesc + "."); - } -} - -void Battle::DoBinding(Army *atts, Army *defs) -{ - int na = atts->NumAlive(); - //get max spell level in this army - for(int i=0; iGetSoldier(i); - if(pSold->special == NULL) continue; - if(pSold->special == SkillDefs[S_BINDING].special) { - if(pSold->slevel) defs->DoBindingAttack(pSold, this); - } else if(pSold->special == SkillDefs[S_DRAGON_TALK].special) { - if(pSold->slevel) defs->DoDragonBindingAttack(pSold, this, atts); - } - } -} - -void Army::DoBindingAttack(Soldier *pAtt, Battle *b) -//'this' army is the defending army -{ - int mages = 0; - for(int i=0; i target) defender = formations[i].GetMage(target); - else target -= formations[i].CountMages(); - } - if(!defender) return; - - if(!pAtt->DoSpellCost(round, b)) return; - if(pAtt->exhausted) { - pAtt->special = NULL; - pAtt->slevel = 0; - return; //binding is an unusual spell - cannot be cast when exhausted. - } - //defend & attack with better of binding skill & dragontalk skill. - int defenceskill = defender->unit->GetSkill(S_BINDING); - if(defender->unit->GetSkill(S_DRAGON_TALK) > defender->unit->GetSkill(S_BINDING) ) defenceskill = defender->unit->GetSkill(S_DRAGON_TALK); - if(pAtt->unit->GetSkill(S_DRAGON_TALK) > pAtt->slevel) pAtt->slevel = pAtt->unit->GetSkill(S_DRAGON_TALK); //the mage is not exhausted, so this is valid. - int defence = defender->unit->MaxEnergy() * (3 + defenceskill/2); - int attack = pAtt->slevel * pAtt->unit->MaxEnergy(); - - if(getrandom(attack+defence) < attack) { - defender->slevel = 0; - defender->special = NULL; - AString temp = *(pAtt->unit->name) + " binds " + *(defender->unit->name) + " from spellcasting."; - b->AddLine(temp); - } -} - -void Army::DoDragonBindingAttack(Soldier *pAtt, Battle *b, Army *atts) -//'this' army is the defending army -{ - int dragons = 0; - int na = NumAlive(); - Soldier *pDragon = 0; - Soldier *pSold; - for(int i=0; icandragontalk && pSold->race == I_DRAGON) { //each dragon can only have one attempt to convert or bind them. - if(!getrandom(++dragons)) pDragon = pSold; - } - } - - //if no dragons, do a regular binding attack. - if(!pDragon) { - //set the soldier's special to binding here to allow different spell costs - SkillType *pST = &SkillDefs[S_BINDING]; - pAtt->special = pST->special; - pAtt->slevel = pAtt->unit->GetSkill(S_BINDING); - DoBindingAttack(pAtt, b); - return; - } - - #ifdef DEBUG - Awrite("Doing dragon binding"); - #endif - - //defender is our randomly picked dragon. - if(!pAtt->DoSpellCost(round, b)) return; - if(pAtt->exhausted) { - pAtt->special = NULL; - pAtt->slevel = 0; - return; //dragonbinding is an unusual spell - cannot be cast when exhausted. - } - - pDragon->candragontalk = 0; //cannot dragontalk with this dragon again. - - //some stuff to determine result. - //chance to: - //(a) tie down the dragon's special - //(b) convince the dragon to leave the fight - //(c) convince the dragon to join us - //set - - int result = 0; - //result 0: fails - //result 1: dragon's special removed - //result 2: dragon leaves - //result 3: dragon joins us - - int attack = (pAtt->slevel + 2) * pAtt->unit->MaxEnergy(); - //typical scores at lvl 2 are 4*80 (this is a mysticism mage) ~ 320. Max expected score - //would be 8*150 ~ 1200. - if( getrandom(300+attack) < attack ) { - result = 1; - attack = pAtt->slevel * pAtt->unit->MaxEnergy(); - //typical scores at lvl 3 are 3*100 - if(getrandom(300+attack) < attack ) { - result = 2; - attack = (pAtt->slevel - 3) * pAtt->unit->MaxEnergy(); - if(attack>0 && (getrandom(300+attack) < attack) ) result = 3; - } - } - - AString temp = ""; - Soldier * pDragon2 = 0; - int dragonnum; - switch(result) { - case 0: - if(pDragon->unit->GetSoldiers() == 1) temp = "A dragon from "; - if(getrandom(2)) b->AddLine(temp + *(pDragon->unit->name) + " ignores the pleas of " + *(pAtt->unit->name) ); - else b->AddLine(temp + *(pDragon->unit->name) + " listens to the words of " + *(pAtt->unit->name) + " but is not swayed to leave this battle."); - return; - case 1: - if(pDragon->unit->GetSoldiers() == 1) temp = "a dragon from "; - b->AddLine(*(pAtt->unit->name) + " cannot convince " + temp + *(pDragon->unit->name) + " to leave this battle, but manages to bind him from spellcasting."); - pDragon->slevel = 0; - pDragon->special = NULL; - return; - case 3: - //if joining us: - //remove a dragon - pDragon->unit->items.SetNum(I_DRAGON, pDragon->unit->items.GetNum(I_DRAGON) - 1); - //add a dragon - pAtt->unit->items.SetNum(I_DRAGON, pAtt->unit->items.GetNum(I_DRAGON) + 1); - - if(pDragon->unit->GetSoldiers() == 1) b->AddLine( *(pDragon->unit->name) + " agrees to quit this battle and join " + *(pAtt->unit->name) ); - else b->AddLine(AString("A dragon from ") + *(pDragon->unit->name) + " agrees to quit this battle and join " + *(pAtt->unit->name) ); - //fall through... - case 2: - //if leaving this fight: - dragonnum = -1; - for(int i=0; iinform].GetNumMen(); i++) { - const Soldier *temp = formations[pDragon->inform].GetSoldier(i); - if (temp == pDragon) { - dragonnum = i; - break; - } - } - if(dragonnum == -1) { - #ifdef DEBUG - Awrite("Could not find bound dragon in its formation!"); - system("pause"); - #endif - return; - } - - pDragon2 = formations[pDragon->inform].RemoveSoldier(dragonnum); - #ifdef DEBUG - if(pDragon != pDragon2) { - Awrite(AString("Removed dragon is not the dragon it should be. It is of race ") + pDragon2->race); - system("pause"); - } - #endif - if(result == 2) { - if(pDragon->unit->GetSoldiers() == 1) b->AddLine( *(pAtt->unit->name) + " convinces " + *(pDragon->unit->name) + " to quit this battle." ); - else b->AddLine( *(pAtt->unit->name) + " convinces a dragon from " + *(pDragon->unit->name) + " to quit this battle." ); - } - count--; - delete pDragon2; - return; - default: - return; - } -} - -void Battle::UpdateRoundSpells(Army *armya, Army *armyb) -{ - - if(getrandom(2)) { - DoBinding(armya,armyb); - DoBinding(armyb,armya); - } else { - DoBinding(armyb,armya); - DoBinding(armya,armyb); - } - - int darkness = GetRoundSpellLevel(armya, armyb, 2, S_DARKNESS, S_LIGHT); - int foga = GetRoundSpellLevel(armya, armyb, 1, S_FOG, S_CLEAR_SKIES) + darkness; - int fogb = GetRoundSpellLevel(armyb, armya, 1, S_FOG, S_CLEAR_SKIES) + darkness; - int conceala = GetRoundSpellLevel(armya, armyb, 1, S_CONCEALMENT, S_DISPEL_ILLUSIONS); - int concealb = GetRoundSpellLevel(armyb, armya, 1, S_CONCEALMENT, S_DISPEL_ILLUSIONS); - -//Do taccontrol for army a, then army b. - float taca = 100; - while(fogb > 0) { - fogb--; - taca *= 0.7; - } - armya->taccontrol = (int) taca; - - float tacb = 100; - while(foga > 0) { - foga--; - tacb *= 0.7; - } - armyb->taccontrol = (int) tacb; - - armya->concealment = conceala; - armyb->concealment = concealb; - - //Do 'bonus' penalty for darkness. - for( int i=0; iformations[i].bonus -= darkness; - armyb->formations[i].bonus -= darkness; - } -} - -int Battle::GetRoundSpellLevel(Army *armya, Army *armyb, int type, int spell, int antispell) -//type can be 1 or 2 - 1 looks only at this army, 2 looks through both armies. -{ - Soldier *caster = 0; - int spelllevel = 0; - Soldier *anticaster = 0; - int antispelllevel = 0; - - int na = armya->NumAlive(); - //get max spell level in this army - for(int i=0; iGetSoldier(i); - if(pSold->special == NULL) continue; - if(pSold->special == SkillDefs[spell].special) { - pSold->DoSpellCheck(armya->round, this); //this checks if the mage should become exhausted - if(pSold->slevel > spelllevel) { - spelllevel = pSold->slevel; - caster = pSold; - } - } - if((type == 2) && pSold->special == SkillDefs[antispell].special) { - pSold->DoSpellCheck(armya->round, this); //this checks if the mage should become exhausted - if(pSold->slevel > antispelllevel) { - antispelllevel = pSold->slevel; - anticaster = pSold; - } - } - } - - na = armyb->NumAlive(); - for(int i=0; iGetSoldier(i); - if(pSold->special == NULL) continue; - - if((type == 2) && pSold->special == SkillDefs[spell].special) { - pSold->DoSpellCheck(armyb->round, this); //this checks if the mage should become exhausted - if(pSold->slevel > spelllevel) { - spelllevel = pSold->slevel; - caster = pSold; - } - } - if(pSold->special == SkillDefs[antispell].special) { - pSold->DoSpellCheck(armyb->round, this); //this checks if the mage should become exhausted - if(pSold->slevel > antispelllevel) { - antispelllevel = pSold->slevel; - anticaster = pSold; - } - } - } - - if(spelllevel == 0) return 0; - - if( caster->DoSpellCost(armya->round, this) == 0) return 0; //round should be same for both armies, so this works for darkness also. - - AString temp; - temp = *(caster->unit->name) + " casts "; - - SpecialType *spd = FindSpecial(SkillDefs[spell].special); - temp += spd->spelldesc; - - if(antispelllevel && anticaster->DoSpellCost(armyb->round, this)) { - //anticaster will get used twice - dispel illusions, light and clear skies all have another purpose. Well, tough - they get double experience also! - if(spelllevel > antispelllevel) { - temp += ", but it's effectiveness is reduced by "; - } else temp += ", but the spell is rendered ineffective by "; - temp += *(anticaster->unit->name); - } else temp += "."; - AddLine(temp); - - if(spell > antispell) return (spelllevel - antispelllevel); - else return 0; -} - -void Battle::DoSpecialAttack(int round, Soldier *a, Army *attackers, Army *def) -{ - SpecialType *spd; - int i, num, tot = -1; - AString results[4]; - int dam = 0; - - if(a->special == NULL) return; - spd = FindSpecial(a->special); -#ifdef DEBUG -cout << spd->key; -#endif - if(!(spd->effectflags & SpecialType::FX_DAMAGE)) return; - - int hitself = 0; - if(spd->targflags & SpecialType::HIT_OWN_ARMY) hitself = 1; - - if(spd->targflags && ( (!hitself && (def->IsSpecialTarget(a->special) < 1)) || - (hitself && (attackers->IsSpecialTarget(a->special) < 1)) ) ) { - if(a->unit->type == U_MAGE) { - AddLine(a->name + " cannot find a spell target, and saves his energy."); - } - return; //no targets to hit. - } - -#ifdef DEBUG2 -cout << "-"; -#endif - //energy cost for mages using their combat spell only (ie not for monsters, battle items etc) - int cancast = a->DoSpellCost(round, this); //this also includes fizzle chance. - if(!cancast) return; - if(cancast == 2) { - hitself = (hitself+1)%2; //swop army to hit. - } -#ifdef DEBUG2 -cout << "-"; -#endif - - for(i = 0; i < 4; i++) { -#ifdef DEBUG2 -cout << "!"; -#endif - if(spd->damage[i].type == -1) continue; - int times = spd->damage[i].value; - if(spd->effectflags & SpecialType::FX_USE_LEV) - times *= a->slevel; - int realtimes = spd->damage[i].minnum + getrandom(times) + - getrandom(times); - if(!hitself) num = def->DoAnAttack(a->special, realtimes, a->race, - spd->damage[i].type, a->slevel, - spd->damage[i].flags, spd->damage[i].dclass, - spd->damage[i].effect, 0, attackers, a->inform, this); - else num = attackers->DoAnAttack(a->special, realtimes, a->race, //hitting own army - spd->damage[i].type, a->slevel, - spd->damage[i].flags, spd->damage[i].dclass, - spd->damage[i].effect, 0, attackers, a->inform, this); //'attackers' are still attackers; this is used to trigger random target selection rather than formation-specific. - - if(spd->effectflags & SpecialType::FX_DONT_COMBINE && num != -1) { - if(spd->damage[i].effect == NULL) { - results[dam] = AString("killing ") + num; - dam++; - } else { - results[dam] = AString(spd->spelldesc2) + num; - } - } - if(num != -1) { - if(tot == -1) tot = num; - else tot += num; - } - } - if(tot == -1) { - AddLine(a->name + " " + spd->spelldesc + ", but it is deflected."); - } else { - if(spd->effectflags & SpecialType::FX_DONT_COMBINE) { - AString temp = a->name + " " + spd->spelldesc; - for(i = 0; i < dam; i++) { - if(i) temp += ", "; - if(i == dam-1) temp += " and "; - temp += results[dam]; - } - temp += AString(spd->spelltarget) + "."; - AddLine(temp); - } else { - AddLine(a->name + " " + spd->spelldesc + ", " + spd->spelldesc2 + - tot + spd->spelltarget + "."); - } - } -} - diff --git a/arcadia/spells.cpp b/arcadia/spells.cpp deleted file mode 100644 index 4bfdedf3b..000000000 --- a/arcadia/spells.cpp +++ /dev/null @@ -1,5344 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#include "game.h" -#include "gamedata.h" -#include "unit.h" - -#ifndef DEBUG -//#define DEBUG -#endif - -void Game::ProcessCastOrder(Unit * u,AString * o, OrdersCheck *pCheck, int isquiet) -{ - AString * token = o->gettoken(); - if (!token) { - ParseError( pCheck, u, 0, "CAST: No skill given."); - return; - } - - int sk = ParseSkill(token); - delete token; - if (sk==-1) { - ParseError( pCheck, u, 0, "CAST: Invalid skill."); - return; - } - - if( !( SkillDefs[sk].flags & SkillType::MAGIC )) { - ParseError( pCheck, u, 0, "CAST: That is not a magic skill."); - return; - } - if( !( SkillDefs[sk].flags & SkillType::CAST )) { - ParseError( pCheck, u, 0, "CAST: That skill cannot be CAST."); - return; - } - - RangeType *rt = NULL; - if( !pCheck ) { - // - // XXX -- should be error checking spells - // - switch(sk) { - case S_MIND_READING: - ProcessMindReading(u,o, pCheck, isquiet ); - break; - case S_CONSTRUCT_PORTAL: // Disabled in Earthsea - case S_ENCHANT_SWORDS: - case S_ENCHANT_ARMOR: - case S_CONSTRUCT_GATE: - case S_ENGRAVE_RUNES_OF_WARDING: - case S_SUMMON_BALROG: - case S_SUMMON_SKELETONS: - case S_SUMMON_LICH: - case S_DRAGON_LORE: // Disabled in Arcadia - case S_GRYFFIN_LORE: // Summons gryffins - case S_CREATE_RING_OF_INVISIBILITY: - case S_CREATE_CLOAK_OF_INVULNERABILITY: - case S_CREATE_STAFF_OF_FIRE: - case S_CREATE_STAFF_OF_LIGHTNING: - case S_CREATE_AMULET_OF_TRUE_SEEING: - case S_CREATE_AMULET_OF_PROTECTION: // in artifact_lore in Earthsea - case S_CREATE_RUNESWORD: - case S_CREATE_SHIELDSTONE: // in artifact_lore in Earthsea - case S_CREATE_MAGIC_CARPET: - case S_CREATE_FOOD: - //Earthsea spells - case S_PHANTASMAL_ENTERTAINMENT: // castable in earthsea mod. - case S_CONCEALMENT: // Adds to stealth of friendly units which do not attack/steal/assassinate - ProcessGenericSpell(u,sk, pCheck, isquiet ); - break; - case S_WOLF_LORE: - case S_SUMMON_IMPS: - case S_SUMMON_DEMON: - case S_RAISE_UNDEAD: - if(Globals->ARCADIA_MAGIC) ProcessSummonCreaturesSpell(u,o, sk, pCheck, isquiet ); - else ProcessGenericSpell(u,sk, pCheck, isquiet ); - break; - case S_FOG: // Blanks out region for others - ProcessFogSpell(u,o, pCheck, isquiet); - case S_CLEAR_SKIES: - case S_EARTH_LORE: - rt = FindRange(SkillDefs[sk].range); - if (rt == NULL && !Globals->ARCADIA_MAGIC) { - ProcessGenericSpell(u, sk, pCheck, isquiet); - } else - ProcessRegionSpell(u, o, sk, pCheck, isquiet); //large option - break; - case S_FARSIGHT: // small/large - case S_TELEPORTATION: - case S_WEATHER_LORE: - case S_DIVERSION: //modifies rivers - case S_BLIZZARD: //summons small/large blizzard around target region - case S_CREATE_PORTAL: //earthsea - creates a portal, may be linked to another. - case S_SEAWARD: // delays region sinking. - ProcessRegionSpell(u, o, sk, pCheck, isquiet); //"large" a possibility now for all region spells. Used for blizzard, clear skies - break; - case S_BIRD_LORE: - ProcessBirdLore(u,o, pCheck, isquiet ); - break; - case S_INVISIBILITY: - ProcessUnitsSpell(u,o, sk, pCheck, isquiet ); - break; - case S_GATE_LORE: - ProcessCastGateLore(u,o, pCheck, isquiet ); - break; - case S_PORTAL_LORE: - ProcessCastPortalLore(u,o, pCheck, isquiet ); - break; - case S_CREATE_PHANTASMAL_BEASTS: - ProcessPhanBeasts(u,o, pCheck, isquiet ); - break; - case S_CREATE_PHANTASMAL_UNDEAD: - ProcessPhanUndead(u,o, pCheck, isquiet ); - break; - case S_CREATE_PHANTASMAL_DEMONS: - ProcessPhanDemons(u,o, pCheck, isquiet ); - break; - //Earthsea spells: - case S_ILLUSORY_CREATURES: // summons illusory creatures of specified type - ProcessPhanCreatures(u,o, pCheck, isquiet ); - break; - case S_SUMMON_MEN: // summons men of particular race for $50 each - ProcessSummonMen(u,o,pCheck, isquiet); - break; - case S_SPIRIT_OF_DEAD: //cast: summons long dead mage - ProcessUnitsSpell(u,o, sk, pCheck, isquiet ); - break; - case S_TRANSMUTATION: //turns 2 pieces of one item type into one piece of another - ProcessChangeSpell(u,o, sk, pCheck, isquiet ); - break; - case S_MODIFICATION: //modifies region product - ProcessModificationSpell(u,o,pCheck, isquiet); - break; - case S_REJUVENATION: //modifies region terrain. High levels: includes ocean - ProcessRejuvenationSpell(u,o,pCheck, isquiet); - break; - case S_HYPNOSIS: //hypnotises target non-mage unit(s). Maximum men limit. Can give work/tax/produce/build orders. Higher level can give move/pillage/advance orders - ProcessHypnosisSpell(u,o,pCheck, isquiet); - break; - case S_ARTIFACT_LORE: //creates shieldstone or AMPR in EarthSea. - case S_BASE_ARTIFACTLORE: - ProcessArtifactSpell(u,o,sk,pCheck, isquiet); - break; - default: - u->Error("CAST: That spell does not seem to have process code. Please contact your GM."); - } - } -} - -void Unit::AddCastOrder(CastOrder *order) -{ - if(!Globals->ARCADIA_MAGIC) castlistorders.DeleteAll(); //no more than one spell allowed - else { - forlist(&castlistorders) { - CastOrder *ord = (CastOrder *) elem; - if(ord->spell == order->spell) { - castlistorders.Remove(ord); - delete ord; - } - } - } - castlistorders.Add(order); -} - -void Game::ProcessMindReading(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - UnitId *id = ParseUnit(o); - - if (!id) { - u->Error("CAST: No unit specified.", 0); - return; - } - - CastMindOrder *order = new CastMindOrder; - order->id = id; - order->spell = S_MIND_READING; - order->level = 1; - order->quiet = isquiet; - - u->AddCastOrder(order); -} - -void Game::ProcessBirdLore(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Missing arguments.", 0); - return; - } - - if (*token == "eagle") { - CastIntOrder *order = new CastIntOrder; - order->spell = S_BIRD_LORE; - order->quiet = isquiet; - order->level = 3; - order->target = -1; //Earthsea mod, does nothing in non-Earthsea. - delete token; - token = o->gettoken(); - if(token) { - order->target = token->value(); - delete token; - } - u->AddCastOrder(order); - return; - } - -/* if (*token == "large") { - //ARC-III only - delete token; - CastIntOrder *order = new CastIntOrder; - order->spell = S_BIRD_LORE; - order->quiet = isquiet; - order->level = 4; - order->target = 0; //just for safety. - u->AddCastOrder(order); - return; - }*/ - - if (*token == "direction") { - delete token; - token = o->gettoken(); - - if (!token) { - u->Error("CAST: Missing arguments.", 0); - return; - } - - int dir = ParseDir(token); - delete token; - if (dir == -1 || dir > NDIRS) { - u->Error("CAST: Invalid direction.", 0); - return; - } - - CastIntOrder *order = new CastIntOrder; - order->spell = S_BIRD_LORE; - order->quiet = isquiet; - order->level = 1; - order->target = dir; - u->AddCastOrder(order); - - return; - } - - u->Error("CAST: Invalid arguments.", 0); - delete token; -} - -void Game::ProcessFogSpell(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - - int large = 0; - int dir = -1; - if (token && *token == "large") { - large = 1; - delete token; - token = o->gettoken(); - if(token) { - dir = ParseDir(token); // return -1 if doesn't make sense - delete token; - if(dir<0 || dir>5) dir = -1; - } - } - - CastIntOrder *order = new CastIntOrder; - order->spell = S_FOG; - order->quiet = isquiet; - order->level = 1+3*large; - order->target = dir; - u->AddCastOrder(order); - return; -} - -void Game::ProcessUnitsSpell(Unit *u,AString *o, int spell, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - - if (!token || (!(*token == "units") && !(*token == "unit")) ) { - u->Error("CAST: Must specify units.", 0); - return; - } - delete token; - - CastUnitsOrder *order = 0; - //option of adding units over multiple lines - - - forlist(&u->castlistorders) { - CastOrder *ord = (CastOrder *) elem; - if(ord->spell == spell) { - order = (CastUnitsOrder *) ord; - if(order->quiet && !isquiet) order->quiet = isquiet; //if earlier line wasn't quiet, don't make it quiet now - } - } - - if(!order) { - order = new CastUnitsOrder; - order->spell = spell; - order->quiet = isquiet; - order->level = 1; - u->AddCastOrder(order); - } - - UnitId *id = ParseUnit(o); - while (id) { - order->units.Add(id); - id = ParseUnit(o); - } -} - -void Game::ProcessChangeSpell(Unit *u,AString *o, int spell, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Arguments missing.", 0); - return; - } - - int toitem = ParseEnabledItem(token); - delete token; - if(toitem<0) { - u->Error("CAST: Invalid item.", 0); - return; - } - - token = o->gettoken(); - int fromitem; - if (!token) { - fromitem = -1; - } else { - fromitem = ParseEnabledItem(token); - delete token; - if(fromitem<0) { - u->Error("CAST: Invalid item.", 0); - return; - } - } - if(toitem == fromitem) { - u->Error("CAST: to item is same as from item.", 0); - return; - } - - int unitlist = 0; - token = o->gettoken(); - if(token && ( *token == "units" || *token == "unit" ) ) { - delete token; - unitlist = 1; - } - - CastChangeOrder *order; - order = new CastChangeOrder; - order->spell = spell; - order->quiet = isquiet; - order->level = 1; - order->toitem = toitem; - order->fromitem = fromitem; - u->AddCastOrder(order); - - if(unitlist) { - UnitId *id = ParseUnit(o); - while (id) { - order->units.Add(id); - id = ParseUnit(o); - } - } -} - -void Game::ProcessModificationSpell(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - - int type; - - if (*token == "Increase") { - type = 1; - } else if (*token == "Decrease") { - type = 3; - } else { - u->Error("CAST: Invalid argument.", 0); - return; - } - delete token; - token = o->gettoken(); - if(!token) { - u->Error("CAST: Insufficient arguments", 0); - return; - } - int firstitem = ParseEnabledItem(token); - delete token; - if(firstitem<0) { - u->Error("CAST: Invalid item.", 0); - return; - } - - token = o->gettoken(); - if(!token) { - u->Error("CAST: Insufficient arguments", 0); - return; - } - int seconditem = ParseEnabledItem(token); - delete token; - if(seconditem<0) { - u->Error("CAST: Invalid item.", 0); - return; - } - - token = o->gettoken(); - int x = -1; - int y = -1; - int z = -1; - if(token && *token == "region") { - delete token; - token = o->gettoken(); - if(!token) { - u->Error("CAST: Region X coordinate not specified.", 0); - return; - } - x = token->value(); - delete token; - - token = o->gettoken(); - if(!token) { - u->Error("CAST: Region Y coordinate not specified.", 0); - return; - } - y = token->value(); - delete token; - - RangeType *range = FindRange(SkillDefs[S_MODIFICATION].range); - if(range && (range->flags & RangeType::RNG_CROSS_LEVELS)) { - token = o->gettoken(); - if(token) { - z = token->value(); - delete token; - if(z < 0 || (z >= Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + - Globals->ABYSS_LEVEL + 2)) { - u->Error("CAST: Invalid Z coordinate specified.", 0); - return; - } - } - } - } else { - if(token) delete token; - } - if(x == -1) x = u->object->region->xloc; - if(y == -1) y = u->object->region->yloc; - if(z == -1) z = u->object->region->zloc; - - CastModifyOrder *order; - order = new CastModifyOrder; - order->spell = S_MODIFICATION; - order->quiet = isquiet; - order->level = type; - order->xloc = x; - order->yloc = y; - order->zloc = z; - if(type == 3) { - order->toitem = seconditem; - order->fromitem = firstitem; - } else { - order->toitem = firstitem; - order->fromitem = seconditem; - } - u->AddCastOrder(order); - -} - -void Game::ProcessRejuvenationSpell(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - if(!token) { - u->Error("CAST: No arguments supplied", 0); - return; - } - - int type = ParseTerrain(token); - delete token; - - if(type >= R_CAVERN) { - u->Error("CAST: Cannot rejuvenate a region to non-surface terrain.", 0); - return; - } - - token = o->gettoken(); - int x = -1; - int y = -1; - int z = -1; - if(token && *token == "region") { - delete token; - token = o->gettoken(); - if(!token) { - u->Error("CAST: Region X coordinate not specified.", 0); - return; - } - x = token->value(); - delete token; - - token = o->gettoken(); - if(!token) { - u->Error("CAST: Region Y coordinate not specified.", 0); - return; - } - y = token->value(); - delete token; - - RangeType *range = FindRange(SkillDefs[S_MODIFICATION].range); - if(range && (range->flags & RangeType::RNG_CROSS_LEVELS)) { - token = o->gettoken(); - if(token) { - z = token->value(); - delete token; - if(z < 0 || (z >= Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + - Globals->ABYSS_LEVEL + 2)) { - u->Error("CAST: Invalid Z coordinate specified.", 0); - return; - } - } - } - } else { - if(token) delete token; - } - if(x == -1) x = u->object->region->xloc; - if(y == -1) y = u->object->region->yloc; - if(z == -1) z = u->object->region->zloc; - - CastModifyOrder *order; - order = new CastModifyOrder; - order->spell = S_REJUVENATION; - order->quiet = isquiet; - order->level = 1; - order->xloc = x; - order->yloc = y; - order->zloc = z; - order->toitem = type; - order->fromitem = -1; - - u->AddCastOrder(order); -} - -void Game::ProcessPhanDemons(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - CastIntOrder *order = new CastIntOrder; - order->spell = S_CREATE_PHANTASMAL_DEMONS; - order->quiet = isquiet; - order->level = 0; - order->target = 1; - - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Illusion to summon must be given.", 0); - delete order; - return; - } - - if (*token == "imp" || *token == "imps") { - order->level = 1; - } - - if (*token == "demon" || *token == "demons") { - order->level = 3; - } - - if (*token == "balrog" || *token == "balrogs") { - order->level = 5; - } - - delete token; - - if (!order->level) { - u->Error("CAST: Can't summon that illusion.", 0); - delete order; - return; - } - - token = o->gettoken(); - - if (!token) { - order->target = 1; - } else { - order->target = token->value(); - delete token; - } - - u->AddCastOrder(order); -} - -void Game::ProcessPhanUndead(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet) -{ - CastIntOrder *order = new CastIntOrder; - order->spell = S_CREATE_PHANTASMAL_UNDEAD; - order->quiet = isquiet; - order->level = 0; - order->target = 1; - - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Must specify which illusion to summon.", 0); - delete order; - return; - } - - if (*token == "skeleton" || *token == "skeletons") { - order->level = 1; - } - - if (*token == "undead") { - order->level = 3; - } - - if (*token == "lich" || *token == "liches") { - order->level = 5; - } - - delete token; - - if (!order->level) { - u->Error("CAST: Must specify which illusion to summon.", 0); - delete order; - return; - } - - token = o->gettoken(); - - if (token) { - order->target = token->value(); - delete token; - } else { - order->target = 1; - } - - u->AddCastOrder(order); -} - -void Game::ProcessPhanBeasts(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - CastIntOrder *order = new CastIntOrder; - order->spell = S_CREATE_PHANTASMAL_BEASTS; - order->quiet = isquiet; - order->level = 0; - order->target = 1; - - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Must specify which illusion to summon.", 0); - delete order; - return; - } - - if (*token == "wolf" || *token == "wolves") { - order->level = 1; - } - if (*token == "eagle" || *token == "eagles") { - order->level = 3; - } - if (*token == "dragon" || *token == "dragon") { - order->level = 5; - } - - delete token; - if (!order->level) { - delete order; - u->Error("CAST: Must specify which illusion to summon.", 0); - return; - } - - token = o->gettoken(); - if (token) { - order->target = token->value(); - delete token; - } - - u->AddCastOrder(order); -} - -void Game::ProcessPhanCreatures(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - CastMenOrder *order = new CastMenOrder; - order->spell = S_ILLUSORY_CREATURES; - order->quiet = isquiet; - order->level = 0; - order->men = 1; - - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Must specify which illusion to summon.", 0); - delete order; - return; - } - - if (*token == "wolf" || *token == "wolves") { - order->level = 1; - order->race = I_IWOLF; - } - if (*token == "eagle" || *token == "eagles" || *token == "eagl") { - order->level = 2; - order->race = I_IEAGLE; - } - if (*token == "gryffin" || *token == "gryffins" || *token == "gryf") { - order->level = 3; - order->race = I_IGRYFFIN; - } - if (*token == "dragon" || *token == "dragon" || *token == "drag") { - order->level = 4; - order->race = I_IDRAGON; - } - if (*token == "skeleton" || *token == "skeletons" || *token == "skel") { - order->level = 1; - order->race = I_ISKELETON; - } - if (*token == "undead" || *token == "unde") { - order->level = 2; - order->race = I_IUNDEAD; - } - if (*token == "lich" || *token == "liches") { - order->level = 3; - order->race = I_ILICH; - } - if (*token == "imp" || *token == "imps") { - order->level = 1; - order->race = I_IIMP; - } - if (*token == "demon" || *token == "demons" || *token == "demo") { - order->level = 2; - order->race = I_IDEMON; - } - if (*token == "balrog" || *token == "balrogs" || *token == "balr") { - order->level = 3; - order->race = I_IBALROG; - } - - delete token; - if (!order->level) { - delete order; - u->Error("CAST: Must specify which illusion to summon.", 0); - return; - } - - token = o->gettoken(); - if (token) { - order->men = token->value(); - delete token; - } - u->AddCastOrder(order); -} - -void Game::ProcessGenericSpell(Unit *u,int spell, OrdersCheck *pCheck, int isquiet ) -{ - CastOrder *order = new CastOrder; - order->spell = spell; - order->quiet = isquiet; - order->level = 1; - u->AddCastOrder(order); -} - -void Game::ProcessSummonCreaturesSpell(Unit *u, AString *o, int spell, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - int number = -1; - if(token) { - number = token->value(); - } - CastIntOrder *order = new CastIntOrder; - order->spell = spell; - order->quiet = isquiet; - order->level = 1; - order->target = number; - u->AddCastOrder(order); -} - -void Game::ProcessArtifactSpell(Unit *u, AString *o, int sk, OrdersCheck *pCheck, int isquiet ) -{ - if(!Globals->ARCADIA_MAGIC) return; - AString *token = o->gettoken(); - int type = -1; - if(token) { - if(*token == "protection" || *token == "ampr" || *token == "protections") { - type = 1; - } else if(*token == "shieldstone" || *token == "shst" || *token == "shieldstones") { - type = 3; - } - delete token; - } - if(type<0) { - u->Error("CAST: Invalid argument", 0); - return; - } - - CastOrder *order = new CastOrder; - order->spell = sk; - order->quiet = isquiet; - order->level = type; - u->AddCastOrder(order); -} - - - -void Game::ProcessRegionSpell(Unit *u, AString *o, int spell, - OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - int x = -1; - int y = -1; - int z = -1; - int size = 0; - RangeType *range = FindRange(SkillDefs[spell].range); - - // Edit to allow large region casting - Earthsea - if(token && *token == "large") { - size = 3; - delete token; - token = o->gettoken(); - } - - if(token) { - if(*token == "region") { - delete token; - token = o->gettoken(); - if(!token) { - u->Error("CAST: Region X coordinate not specified.", 0); - return; - } - x = token->value(); - delete token; - - token = o->gettoken(); - if(!token) { - u->Error("CAST: Region Y coordinate not specified.", 0); - return; - } - y = token->value(); - delete token; - - if(range && (range->flags & RangeType::RNG_CROSS_LEVELS)) { - token = o->gettoken(); - if(token) { - z = token->value(); - delete token; - if(z < 0 || (z >= Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + - Globals->ABYSS_LEVEL + 2)) { - u->Error("CAST: Invalid Z coordinate specified.", 0); - return; - } - } - } - } else { - delete token; - } - } - if(x == -1) x = u->object->region->xloc; - if(y == -1) y = u->object->region->yloc; - if(z == -1) z = u->object->region->zloc; - - CastRegionOrder *order; - if(spell == S_TELEPORTATION) - order = new TeleportOrder; - else - order = new CastRegionOrder; - order->spell = spell; - order->quiet = isquiet; - order->level = 1+size; //Earthsea mod. sets level to 4 if "large" - order->xloc = x; - order->yloc = y; - order->zloc = z; - - - /* Teleports happen late in the turn! */ - if(spell == S_TELEPORTATION) { - u->ClearTeleportOrders(); - u->teleportorders = (TeleportOrder *)order; - } else { - u->AddCastOrder(order); - } -} - -void Game::ProcessSummonMen(Unit *u, AString *o, OrdersCheck *pCheck, int isquiet) -{ - AString *token = o->gettoken(); - if (!token) { - u->Error("CAST: No arguments submitted.", 0); - return; - } - int number = token->value(); - delete token; - if(number<1) { - u->Error("CAST: Specify number of men to summon.", 0); - return; - } - token = o->gettoken(); - if (!token) { - u->Error("CAST: No race specified.", 0); - return; - } - int race = ParseEnabledItem(token); - delete token; - if(!(ItemDefs[race].type & IT_MAN)) { - u->Error("CAST: Invalid Race.", 0); - return; - } - token = o->gettoken(); - if (!token || (!(*token == "unit") && !(*token == "units")) ) { - u->Error("CAST: Unit not specified.", 0); - delete token; - return; - } - delete token; - - CastMenOrder *order; - order = new CastMenOrder; - order->spell = S_SUMMON_MEN; //spell; - order->quiet = isquiet; - order->level = 1; - order->men = number; - order->race = race; - - UnitId *id = ParseUnit(o); - //For summon men only the first unit will be used. - while(id) { - order->units.Add(id); - id = ParseUnit(o); - } - u->AddCastOrder(order); -} - -void Game::ProcessCastPortalLore(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - if (!token) { - u->Error("CAST: Requires a target mage.", 0); - return; - } - int gate = token->value(); - delete token; - token = o->gettoken(); - - if (!token) { - u->Error("CAST: No units to teleport.", 0); - return; - } - - if (!(*token == "units") && !(*token == "unit") ) { - u->Error("CAST: No units to teleport.", 0); - delete token; - return; - } - - TeleportOrder *order; - - if (u->teleportorders && u->teleportorders->spell == S_PORTAL_LORE) { - order = u->teleportorders; - } else { - order = new TeleportOrder; - u->ClearTeleportOrders(); - u->teleportorders = order; - } - - order->gate = gate; - order->spell = S_PORTAL_LORE; - order->quiet = isquiet; - order->level = 1; - - UnitId *id = ParseUnit(o); - while(id) { - order->units.Add(id); - id = ParseUnit(o); - } -} - -void Game::ProcessCastGateLore(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ - AString *token = o->gettoken(); - - if (!token) { - u->Error("CAST: Missing argument.", 0); - return; - } - - if ((*token) == "gate") { - delete token; - token = o->gettoken(); - - if (!token) { - u->Error("CAST: Requires a target gate.", 0); - return; - } - - TeleportOrder *order; - - if (u->teleportorders && u->teleportorders->spell == S_GATE_LORE && - u->teleportorders->gate == token->value()) { - order = u->teleportorders; - } else { - order = new TeleportOrder; - u->ClearTeleportOrders(); - u->teleportorders = order; - } - - order->gate = token->value(); - order->spell = S_GATE_LORE; - order->quiet = isquiet; - order->level = 3; - - delete token; - - token = o->gettoken(); - - if (!token) return; - if (!(*token == "units") && !(*token == "unit")) { - delete token; - return; - } - - UnitId *id = ParseUnit(o); - while(id) { - order->units.Add(id); - id = ParseUnit(o); - } - return; - } - - if ((*token) == "random") { - TeleportOrder *order; - - if (u->teleportorders && u->teleportorders->spell == S_GATE_LORE && - u->teleportorders->gate == -1 ) { - order = u->teleportorders; - } else { - order = new TeleportOrder; - u->ClearTeleportOrders(); - u->teleportorders = order; - } - - order->gate = -1; - order->spell = S_GATE_LORE; - order->quiet = isquiet; - order->level = 1; - - delete token; - - token = o->gettoken(); - - if (!token) return; - if (!(*token == "units") && !(*token == "unit")) { - delete token; - return; - } - - UnitId *id = ParseUnit(o); - while(id) { - order->units.Add(id); - id = ParseUnit(o); - } - return; - } - - if ((*token) == "detect") { - delete token; - CastOrder *to = new CastOrder; - to->spell = S_GATE_LORE; - to->level = 2; - to->quiet = isquiet; - token = o->gettoken(); - if(token) { - if(*token == "large") to->level = 5; - delete token; - } - u->AddCastOrder(to); - return; - } - - delete token; - u->Error("CAST: Invalid argument.", 0); -} - -void Game::ProcessHypnosisSpell(Unit *u,AString *o, OrdersCheck *pCheck, int isquiet ) -{ -/* Am going to have to move cast before tax! */ - AString *token = o->gettoken(); - int level = 1; - Order * monthorders = 0; - int tax = TAX_NONE; - - if (!token) { - u->Error("CAST: Missing argument.", 0); - return; - } - - if(*token == "work") { - delete token; - token = o->gettoken(); - - ProduceOrder *p = new ProduceOrder; - p->skill = -1; - p->item = I_SILVER; - monthorders = p; - } else if(*token == "produce") { - delete token; - token = o->gettoken(); - if (!token) { - ParseError(pCheck, u, 0, "CAST: No item given to produce."); - return; - } - int it = ParseEnabledItem(token); - delete token; - token = o->gettoken(); - - if (it == -1 || ItemDefs[it].flags & ItemType::DISABLED) { - ParseError(pCheck, u, 0, "CAST: Can't produce that."); - return; - } - - ProduceOrder *p = new ProduceOrder; - p->item = it; - AString skname = ItemDefs[it].pSkill; - p->skill = LookupSkill(&skname); - monthorders = p; - } else if(*token == "sail") { - delete token; -// token = o->gettoken(); - level = 5; - - SailOrder *m = new SailOrder; - - int done = 0; - int atleastone = 0; - while (!done) { - token = o->gettoken(); - if(!token) done = 1; - else if (*token == "units" || *token == "unit" ) done = 1; - else { - int d = ParseDir(token); - delete token; - if (d!=-1) { - MoveDir *x = new MoveDir; - x->dir = d; - m->dirs.Add(x); - atleastone = 1; - } else { - u->Error("CAST: Bad move direction.", 0); - return; - } - } - } - if(!atleastone) { - u->Error("CAST: No directions specified"); - return; - } - monthorders = m; - - } else if(*token == "tax") { - delete token; - token = o->gettoken(); - tax = TAX_TAX; - } else if(*token == "pillage") { - delete token; - token = o->gettoken(); - level = 5; - tax = TAX_PILLAGE; - } else if(*token == "move") { - delete token; - level = 3; - - MoveOrder *m = new MoveOrder; - m->advancing = 0; - - int done = 0; - int atleastone = 0; - while (!done) { - token = o->gettoken(); - if(!token) done = 1; - else if (*token == "units" || *token == "unit") done = 1; - else { - int d = ParseDir(token); - delete token; - if (d != -1) { - MoveDir *x = new MoveDir; - x->dir = d; - m->dirs.Add(x); - atleastone = 1; - } else { - u->Error("CAST: Bad move direction.", 0); - return; - } - } - } - if(!atleastone) { - u->Error("CAST: No directions specified"); - return; - } - monthorders = m; - - } else if(*token == "advance") { - delete token; - level = 4; - - MoveOrder *m = new MoveOrder; - m->advancing = 1; - m->type = O_ADVANCE; - - int done = 0; - int atleastone = 0; - while (!done) { - token = o->gettoken(); - if(!token) done = 1; - else if (*token == "units" || *token == "unit") done = 1; - else { - int d = ParseDir(token); - delete token; - if (d!=-1) { - MoveDir *x = new MoveDir; - x->dir = d; - m->dirs.Add(x); - atleastone = 1; - } else { - u->Error("CAST: Bad move direction.", 0); - return; - } - } - } - if(!atleastone) { - u->Error("CAST: No directions specified"); - return; - } - - monthorders = m; - - } else if(*token == "study") { - delete token; - level = 2; - token = o->gettoken(); - - if (!token) { - u->Error("CAST: No skill given.", 0); - return; - } - int sk = ParseSkill(token); - delete token; - token = o->gettoken(); - - if (sk==-1 || (SkillDefs[sk].flags & SkillType::DISABLED)) { - u->Error("CAST: Invalid skill.", 0); - return; - } - - if((SkillDefs[sk].flags & SkillType::APPRENTICE) || - (SkillDefs[sk].flags & SkillType::APPRENTICE)) { - u->Error("CAST: Cannot hypnotise with magic or apprentice skills.", 0); - return; - } - - StudyOrder *m = new StudyOrder; - m->skill = sk; - m->days = 0; - - monthorders = m; - - } else { - delete token; - u->Error("CAST: Invalid month order", 0); - return; - } - - if (!token) { - u->Error("CAST: No units specified to hypnotise.", 0); - return; - } - if(!(*token == "units") && !(*token == "unit")) { - delete token; - u->Error("CAST: Must specify units to hypnotise.", 0); - return; - } - delete token; - - CastHypnosisOrder *order; - order = new CastHypnosisOrder; - order->spell = S_HYPNOSIS; //spell; - order->quiet = isquiet; - order->level = level; // level required. - order->monthorder = monthorders; - order->taxing = tax; - - UnitId *id = ParseUnit(o); - while(id) { - order->units.Add(id); - id = ParseUnit(o); - } - - u->AddCastOrder(order); -} - -void Game::RunACastOrder(ARegion * r,Object *o,Unit * u, CastOrder *order) -{ - int val; - if (u->type != U_MAGE) { - u->Error("CAST: Unit is not a mage.", order->quiet); - return; - } - - if (order->level == 0) { - order->level = u->GetSkill(order->spell); - } - if (u->GetSkill(order->spell) < order->level || - order->level == 0) { - u->Error("CAST: Skill level isn't that high.", order->quiet); - return; - } - u->activecastorder = order; - int sk = order->spell; - switch (sk) { - case S_MIND_READING: - val = RunMindReading(r,u); - break; - case S_ENCHANT_ARMOR: - val = RunEnchantArmor(r,u); - break; - case S_ENCHANT_SWORDS: - val = RunEnchantSwords(r,u); - break; - case S_CONSTRUCT_GATE: - val = RunConstructGate(r,u,sk,order->quiet); - break; - case S_ENGRAVE_RUNES_OF_WARDING: - val = RunEngraveRunes(r,o,u,order->quiet); - break; - case S_CONSTRUCT_PORTAL: - val = RunCreateArtifact(r,u,sk,I_PORTAL); - break; - case S_CREATE_RING_OF_INVISIBILITY: - val = RunCreateArtifact(r,u,sk,I_RINGOFI); - break; - case S_CREATE_CLOAK_OF_INVULNERABILITY: - val = RunCreateArtifact(r,u,sk,I_CLOAKOFI); - break; - case S_CREATE_STAFF_OF_FIRE: - val = RunCreateArtifact(r,u,sk,I_STAFFOFF); - break; - case S_CREATE_STAFF_OF_LIGHTNING: - val = RunCreateArtifact(r,u,sk,I_STAFFOFL); - break; - case S_CREATE_AMULET_OF_TRUE_SEEING: - val = RunCreateArtifact(r,u,sk,I_AMULETOFTS); - break; - case S_CREATE_AMULET_OF_PROTECTION: - val = RunCreateArtifact(r,u,sk,I_AMULETOFP); - break; - case S_CREATE_RUNESWORD: - val = RunCreateArtifact(r,u,sk,I_RUNESWORD); - break; - case S_CREATE_SHIELDSTONE: - val = RunCreateArtifact(r,u,sk,I_SHIELDSTONE); - break; - case S_CREATE_MAGIC_CARPET: - val = RunCreateArtifact(r,u,sk,I_MCARPET); - break; - case S_CREATE_FLAMING_SWORD: - val = RunCreateArtifact(r,u,sk,I_FSWORD); - break; - case S_SUMMON_IMPS: - if(Globals->ARCADIA_MAGIC) val = RunSummonCreatures(r,u,sk,I_IMP,-1); - else val = RunSummonImps(r,u); - break; - case S_SUMMON_DEMON: - if(Globals->ARCADIA_MAGIC) val = RunSummonCreatures(r,u,sk,I_DEMON,-1); - else val = RunSummonDemon(r,u); - break; - case S_SUMMON_BALROG: - if(Globals->ARCADIA_MAGIC) val = RunSummonHigherCreature(r,u,sk,I_BALROG); - else val = RunSummonBalrog(r,u,order->quiet); - break; - case S_SUMMON_LICH: - if(Globals->ARCADIA_MAGIC) val = RunSummonHigherCreature(r,u,sk,I_LICH); - else val = RunSummonLich(r,u); - break; - case S_RAISE_UNDEAD: - if(Globals->ARCADIA_MAGIC) val = RunSummonCreatures(r,u,sk,I_UNDEAD,-1); - else val = RunRaiseUndead(r,u); - break; - case S_SUMMON_SKELETONS: - val = RunSummonSkeletons(r,u); - break; - case S_DRAGON_LORE: - val = RunDragonLore(r,u,order->quiet); - break; - case S_BIRD_LORE: - val = RunBirdLore(r,u); - break; - case S_WOLF_LORE: - if(Globals->ARCADIA_MAGIC && SkillDefs[sk].cast_cost > 0) val = RunSummonCreatures(r,u,sk,I_WOLF,8); - else val = RunWolfLore(r,u,order->quiet); - break; - case S_INVISIBILITY: - val = RunInvisibility(r,u); - break; - case S_CREATE_PHANTASMAL_DEMONS: - val = RunPhanDemons(r,u); - break; - case S_CREATE_PHANTASMAL_UNDEAD: - val = RunPhanUndead(r,u); - break; - case S_CREATE_PHANTASMAL_BEASTS: - val = RunPhanBeasts(r,u); - break; - case S_GATE_LORE: - val = RunDetectGates(r,o,u); - break; - case S_FARSIGHT: - val = RunFarsight(r,u); // "large" edit! - break; - case S_EARTH_LORE: - val = RunEarthLore(r,u); - break; - case S_WEATHER_LORE: - val = RunWeatherLore(r, u); - break; - case S_CLEAR_SKIES: - val = RunClearSkies(r,u); - break; - case S_CREATE_FOOD: - val = RunCreateFood(r, u); - break; -/* Earthsea Spells */ - case S_PHANTASMAL_ENTERTAINMENT: - val = RunPhanEntertainment(r,u); - break; - case S_ARTIFACT_LORE: - case S_BASE_ARTIFACTLORE: - if( (order->level > 1) && (u->GetSkill(sk) > 2) ) val = RunCreateArtifact(r,u,sk,I_SHIELDSTONE); - else val = RunCreateArtifact(r,u,sk,I_AMULETOFP); - break; - case S_BLIZZARD: - val = RunBlizzard(r,u); - break; - case S_FOG: // Difficult: need to get final mage region! - val = RunFog(r,u); - break; - case S_ILLUSORY_CREATURES: - val = RunPhanCreatures(r,u); - break; - case S_SUMMON_MEN: - val = RunSummonMen(r,u); - break; - case S_SPIRIT_OF_DEAD: - val = RunSpiritOfDead(r,u); - break; - case S_TRANSMUTATION: - val = RunTransmutation(r,u); - break; - case S_MODIFICATION: - val = RunModification(r,u); - break; - case S_REJUVENATION: - val = RunRejuvenation(r,u); - break; - case S_DIVERSION: - val = RunDiversion(r,u); - break; - case S_GRYFFIN_LORE: - val = RunSummonHigherCreature(r,u,sk,I_GRYFFIN); - break; - case S_SEAWARD: - val = RunSeaward(r,u); - break; - case S_HYPNOSIS: - val = RunHypnosis(r,u); - break; - case S_CREATE_PORTAL: - val = RunCreatePortal(r,u); - break; - } - if (val) { - u->Practice(sk); - r->NotifySpell(u, SkillDefs[sk].abbr, ®ions); - } - u->activecastorder = 0; - -} - -int Game::GetRegionInRange(ARegion *r, ARegion *tar, Unit *u, int spell, int quiet, int penalty) -{ - int level = u->GetSkill(spell); - if(!level) { - u->Error("CAST: You don't know that spell.", quiet); - return 0; - } - - RangeType *range = FindRange(SkillDefs[spell].range); - if (range == NULL) { - u->Error("CAST: Spell is not castable at range.", quiet); - return 0; - } - - if(penalty) level -= penalty; - - int rtype = regions.GetRegionArray(r->zloc)->levelType; - if((rtype == ARegionArray::LEVEL_NEXUS) && - !(range->flags & RangeType::RNG_NEXUS_SOURCE)) { - u->Error("CAST: Spell does not work from the Nexus.", quiet); - return 0; - } - - if(!tar) { - u->Error("CAST: No such region.", quiet); - return 0; - } - - rtype = regions.GetRegionArray(tar->zloc)->levelType; - if((rtype == ARegionArray::LEVEL_NEXUS) && - !(range->flags & RangeType::RNG_NEXUS_TARGET)) { - u->Error("CAST: Spell does not work to the Nexus.", quiet); - return 0; - } - - if((rtype != ARegionArray::LEVEL_SURFACE) && - (range->flags & RangeType::RNG_SURFACE_ONLY)) { - u->Error("CAST: Spell can only target regions on the surface.", quiet); - return 0; - } - if(!(range->flags&RangeType::RNG_CROSS_LEVELS) && (r->zloc != tar->zloc)) { - u->Error("CAST: Spell is not able to work across levels.", quiet); - return 0; - } - - int maxdist; - switch(range->rangeClass) { - default: - case RangeType::RNG_ABSOLUTE: - maxdist = 1; - break; - case RangeType::RNG_LEVEL: - maxdist = level; - break; - case RangeType::RNG_LEVEL2: - maxdist = level * level; - break; - case RangeType::RNG_LEVEL3: - maxdist = level * level * level; - break; - } - maxdist *= range->rangeMult; - - int dist; - if(range->flags & RangeType::RNG_CROSS_LEVELS) - dist = regions.GetPlanarDistance(tar, r, range->crossLevelPenalty); - else - dist = regions.GetDistance(tar, r); - if(dist > maxdist) { - u->Error("CAST: Target region out of range.", quiet); - return 0; - } - return 1; -} - -int Game::RunMindReading(ARegion *r,Unit *u) -{ - CastMindOrder *order = (CastMindOrder *) u->activecastorder; - int level = u->GetSkill(S_MIND_READING); - - Unit *tar = r->GetUnitId(order->id,u->faction->num); - if (!tar) { - u->Error("No such unit.", order->quiet); - return 0; - } - - //free spell to use. - - u->Experience(S_MIND_READING, 10); - - int falsefaction = 0; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - AString temp2; - switch(mevent) { - case 4: - u->Error("Attempts to read minds, but the spell is reflected.", order->quiet); - temp2 = AString("Gets a vision of: ") + *(u->name) + ", " + - *(u->faction->name) + "."; - temp2 += u->items.Report(2,5,0,u->type) + ". Skills: "; - temp2 += u->skills.Report(u->GetMen()) + "."; - tar->Event(temp2); - return 1; - case 3: - falsefaction = 1; - break; - case 2: - case 1: - u->Error("Attempts to read minds, but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - AString temp = AString("Casts Mind Reading: ") + *(tar->name) + ", "; - if(!falsefaction) temp += *(tar->faction->name); - else { - int num = 0; - Faction *falsefaction = 0; - forlist(&factions) { - Faction *f = (Faction *) elem; - if(f->IsNPC()) continue; - if(f == u->faction) continue; //don't want it appearing as the mage's faction. - if(num && f == tar->faction) continue; //don't want the real faction if there's an alternative - if( getrandom(++num) ) continue; //random faction selection - falsefaction = f; - } - if(falsefaction) temp += *(falsefaction->name); - } - - if (level < 3 || (!Globals->ARCADIA_MAGIC && level < 5)) { - u->Event(temp + "."); - return 1; - } - - temp += tar->items.Report(2,5,0,tar->type) + ". Skills: "; - temp += tar->skills.Report(tar->GetMen()) + "."; - - u->Event(temp); - return 1; -} - -int Game::RunEnchantArmor(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_ENCHANT_ARMOR); - int max = ItemDefs[I_MPLATE].mOut * level; -// int count = 0; - unsigned int c; -// int found; - - CastOrder *order = u->activecastorder; - - int cost = u->GetCastCost(S_ENCHANT_ARMOR,order->extracost,max); - while(u->energy < cost) { - cost = u->GetCastCost(S_ENCHANT_ARMOR,order->extracost,--max); - } - if(!max) { - u->Error("CAST: Not enough energy to cast that.", order->quiet); - return 0; - } - - - for(c = 0; c < sizeof(ItemDefs->mInput)/sizeof(Materials); c++) { - int i = ItemDefs[I_MPLATE].mInput[c].item; - if(i != -1) { - int amt = u->GetSharedNum(i); - if(amt/ItemDefs[I_MPLATE].mInput[c].amt < max) { - max = amt/ItemDefs[I_MPLATE].mInput[c].amt; - } - } - } - - if (max == 0) { - u->Error("CAST: Do not have the required item.", order->quiet); - return 0; - } - - // Deduct the items used - for(c = 0; c < sizeof(ItemDefs->mInput)/sizeof(Materials); c++) { - int i = ItemDefs[I_MPLATE].mInput[c].item; - int a = ItemDefs[I_MPLATE].mInput[c].amt; - if(i != -1) { - u->ConsumeShared(i, max*a); - } - } - -/* - - // Figure out how many components there are - for(c=0; citems.GetNum(i) >= a) found++; - } - } - // We do not, break. - if(found != count) break; - - // Decrement our inputs - for(c=0; citems.SetNum(i, u->items.GetNum(i) - a); - } - } - // We've made one. - num++; - max--; - } -*/ - - - u->energy -= u->GetCastCost(S_ENCHANT_ARMOR,order->extracost,max); - int experience = 4*max / level; - if(experience > 10) experience = 10; - u->Experience(S_ENCHANT_ARMOR,experience); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - u->Error("Attempts to enchant armour, but the spell goes wrong, producing chain armour.", order->quiet); - u->items.SetNum(I_CHAINARMOR,u->items.GetNum(I_CHAINARMOR) + max); - u->Event(AString("Enchants ") + num + " chain armour."); - return 1; - case 3: - u->Error("Attempts to enchant armour, but the spell goes wrong, producing pearl plate armour.", order->quiet); - u->items.SetNum(I_PPLATE,u->items.GetNum(I_PPLATE) + max); - u->Event(AString("Enchants ") + num + " pearl plate armour."); - return 1; - case 2: - case 1: - u->Error("Attempts to enchant armour, but the spell fizzles and they disappear.", order->quiet); - return 1; - default: - break; - } - #endif - - u->items.SetNum(I_MPLATE,u->items.GetNum(I_MPLATE) + max); - u->Event(AString("Enchants ") + max + " mithril armour."); - return 1; -} - -int Game::RunEnchantSwords(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_ENCHANT_SWORDS); - int max = ItemDefs[I_MSWORD].mOut * level; -// int count = 0; - unsigned int c; -// int found; - - CastOrder *order = u->activecastorder; - int cost = u->GetCastCost(S_ENCHANT_SWORDS,order->extracost,max); - while(u->energy < cost) { - cost = u->GetCastCost(S_ENCHANT_SWORDS,order->extracost,--max); - } - if(!max) { - u->Error("CAST: Not enough energy to cast that.", order->quiet); - return 0; - } - - for(c = 0; c < sizeof(ItemDefs->mInput)/sizeof(Materials); c++) { - int i = ItemDefs[I_MSWORD].mInput[c].item; - if(i != -1) { - int amt = u->GetSharedNum(i); - if(amt/ItemDefs[I_MSWORD].mInput[c].amt < max) { - max = amt/ItemDefs[I_MSWORD].mInput[c].amt; - } - } - } - - if (max == 0) { - u->Error("CAST: Do not have the required item.", order->quiet); - return 0; - } - - // Deduct the items used - for(c = 0; c < sizeof(ItemDefs->mInput)/sizeof(Materials); c++) { - int i = ItemDefs[I_MSWORD].mInput[c].item; - int a = ItemDefs[I_MSWORD].mInput[c].amt; - if(i != -1) { - u->ConsumeShared(i, max*a); - } - } - -/* - // Figure out how many components there are - for(c=0; citems.GetNum(i) >= a) found++; - } - } - // We do not, break. - if(found != count) break; - - // Decrement our inputs - for(c=0; citems.SetNum(i, u->items.GetNum(i) - a); - } - } - // We've made one. - num++; - max--; - } -*/ - u->energy -= u->GetCastCost(S_ENCHANT_SWORDS,order->extracost,max); - int experience = 4*max / level; - if(experience > 10) experience = 10; - u->Experience(S_ENCHANT_SWORDS,experience); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - case 3: - case 2: - case 1: - u->Error("Attempts to enchant swords, but the spell fizzles and they disappear.", order->quiet); - return 1; - default: - break; - } - #endif - - u->items.SetNum(I_MSWORD,u->items.GetNum(I_MSWORD) + max); - u->Event(AString("Enchants ") + max + " mithril swords."); - return 1; -} - -int Game::RunCreateFood(ARegion *r,Unit *u) -//Not adjusted for item sharing -{ - int level = u->GetSkill(S_CREATE_FOOD); - int max = ItemDefs[I_FOOD].mOut * level; - int num = 0; - int count = 0; - unsigned int c; - int found; - - // Figure out how many components there are - for(c=0; citems.GetNum(i) >= a) found++; - } - } - // We do not, break. - if(found != count) break; - - // Decrement our inputs - for(c=0; citems.SetNum(i, u->items.GetNum(i) - a); - } - } - // We've made one. - num++; - max--; - } - - u->items.SetNum(I_FOOD,u->items.GetNum(I_FOOD) + num); - u->Event(AString("Creates ") + num + " food."); - if (num == 0) return 0; - return 1; -} - -int Game::RunConstructGate(ARegion *r,Unit *u, int spell, int isquiet) -{ - if (TerrainDefs[r->type].similar_type == R_OCEAN) { - u->Error("Gates may not be constructed at sea.", isquiet); - return 0; - } - - if (r->gate) { - u->Error("There is already a gate in that region.", isquiet); - return 0; - } - - if(!Globals->ARCADIA_MAGIC) { - if (!u->GetSharedMoney(1000)) { - u->Error("Can't afford to construct a Gate.", isquiet); - return 0; - } - - u->ConsumeSharedMoney(1000); - - int level = u->GetSkill(spell); - int chance = level * 20; - if (getrandom(100) >= chance) { - u->Event("Attempts to construct a gate, but fails."); - return 0; - } - - u->Event(AString("Constructs a Gate in ")+r->ShortPrint( ®ions )+"."); - regions.numberofgates++; - r->gate = regions.numberofgates; - if(Globals->GATES_NOT_PERENNIAL) { - int dm = Globals->GATES_NOT_PERENNIAL / 2; - int gm = month + 1 - getrandom(dm) - getrandom(dm) - getrandom(Globals->GATES_NOT_PERENNIAL % 2); - while(gm < 0) gm += 12; - r->gatemonth = gm; - } - return 1; - } - -// int level = u->GetSkill(spell); //only contruct_gate ever seems to be called here ... ?! - CastOrder *order = u->activecastorder; - - int cost = u->GetCastCost(spell,order->extracost,1); - if(u->energy < cost) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - u->Experience(spell,20); // unusual spell to cast. - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - if(!u->teleportorders) { - TeleportOrder *torder; - torder = new TeleportOrder; - u->teleportorders = torder; - - torder->gate = -1; - torder->spell = S_GATE_LORE; - torder->level = 1; - u->Error("Attempts to construct a gate, but the spell backfires into a random gate jump instead.", order->quiet); - return 1; - } - case 3: - case 2: - case 1: - u->Error("Attempts to construct a gate, but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - u->Event(AString("Constructs a Gate in ") + r->ShortPrint( ®ions ) + "."); - regions.numberofgates++; - r->gate = regions.numberofgates; - if(Globals->GATES_NOT_PERENNIAL) { - int dm = Globals->GATES_NOT_PERENNIAL / 2; - int gm = month + 1 - getrandom(dm) - getrandom(dm) - getrandom(Globals->GATES_NOT_PERENNIAL % 2); - while(gm < 0) gm += 12; - r->gatemonth = gm; - } - return 1; -} - -int Game::RunEngraveRunes(ARegion *r,Object *o,Unit *u, int isquiet) -{ - if (!o->IsBuilding()) { - u->Error("Runes of Warding may only be engraved on a building.", isquiet); - return 0; - } - - if (o->incomplete > 0) { - u->Error( "Runes of Warding may only be engraved on a completed " - "building.", isquiet); - return 0; - } - - int level = u->GetSkill(S_ENGRAVE_RUNES_OF_WARDING); - - if(!Globals->ARCADIA_MAGIC) { - switch (level) { - case 5: - if (o->type == O_MFORTRESS) break; - case 4: - if (o->type == O_CITADEL) break; - case 3: - if (o->type == O_CASTLE) break; - case 2: - if (o->type == O_FORT) break; - if (o->type == O_MTOWER) break; - case 1: - if (o->type == O_TOWER) break; - default: - u->Error("Not high enough level to engrave Runes of Warding on " - "that building.", isquiet); - return 0; - } - - if (!u->GetSharedMoney(600)) { - u->Error("Can't afford to engrave Runes of Warding.", isquiet); - return 0; - } - - u->ConsumeSharedMoney(600); - if( o->type == O_MFORTRESS ) { - o->runes = 5; - } else if(o->type == O_MTOWER) { - o->runes = 4; - } else { - o->runes = 3; - } - u->Event(AString("Engraves Runes of Warding on ") + *(o->name) + "."); - return 1; - } - - int size = 1; - if(ObjectDefs[o->type].protect > 39) size++; - if(ObjectDefs[o->type].protect > 199) size++; - if(ObjectDefs[o->type].protect > 999) size++; - - if(size > level) { - u->Error("CAST: Insufficient level to engrave runes on that building.", isquiet); - return 0; - } - - - if(!(ObjectDefs[o->type].flags & ObjectType::CANMODIFY)) { - u->Error("CAST: Cannot engrave runes on that building type.", isquiet); - return 0; - } - - CastOrder * order = (CastOrder *) u->activecastorder; - - int cost = u->GetCastCost(S_ENGRAVE_RUNES_OF_WARDING,order->extracost,size); - if(u->energy < cost) { - u->Error("CAST: Not enough energy to cast that spell.", isquiet); - return 0; - } - u->energy -= cost; - - int experience = (30*size)/level; - if(experience > 16) experience = 16; - u->Experience(S_ENGRAVE_RUNES_OF_WARDING,experience); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - if(o->runes == 0 && level <= 4) { - u->Error("While engraving runes, the spell escapes the mage's control, engraving runes two levels higher than usual.", isquiet); - level += 2; - break; - } - case 3: - if(o->runes) { - u->Error("Attempts to engrave runes, but the spell backfires, leaving the building without engravings.", isquiet); - o->runes = 0; - return 1; - } - case 2: - case 1: - u->Error("Attempts to engrave runes, but the spell fizzles.", isquiet); - return 1; - default: - break; - } - #endif - - o->runes = level; - u->Event(AString("Engraves Runes of Warding on ") + *(o->name) + "."); - return 1; -} - -int Game::RunSummonBalrog(ARegion *r,Unit *u, int isquiet) -{ - int level = u->GetSkill(S_SUMMON_BALROG); - if(!Globals->ARCADIA_MAGIC) { - if (u->items.GetNum(I_BALROG) >= ItemDefs[I_BALROG].max_inventory) { - u->Error("Can't control any more balrogs.", isquiet); - return 0; - } - - int num = (level * 20 + getrandom(100)) / 100; - - u->items.SetNum(I_BALROG,u->items.GetNum(I_BALROG) + num); - u->Event(AString("Summons ") + ItemString(I_BALROG,num) + "."); - return 1; - } - if (u->items.GetNum(I_BALROG) >= level) { - u->Error("Can't control any more balrogs.", isquiet); - return 0; - } - return 0; -} - -int Game::RunSummonDemon(ARegion *r,Unit *u) -{ - u->items.SetNum(I_DEMON,u->items.GetNum(I_DEMON) + 1); - u->Event(AString("Summons ") + ItemString(I_DEMON,1) + "."); - return 1; -} - -int Game::RunSummonImps(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_SUMMON_IMPS); - - u->items.SetNum(I_IMP,u->items.GetNum(I_IMP) + level); - u->Event(AString("Summons ") + ItemString(I_IMP,level) + "."); - return 1; -} - -int Game::RunCreateArtifact(ARegion *r,Unit *u,int skill,int item) -{ - CastOrder *order = (CastOrder *) u->activecastorder; - - int level = u->GetSkill(skill); - unsigned int c; - - if(Globals->ARCADIA_MAGIC) { - int num; - if(SkillDefs[skill].flags & SkillType::COSTVARIES) num = 1; //always produce one - else num = (level * level * ItemDefs[item].mOut)/100; //produce level^2 * fixed value. This should give at least 2 for level=2, ie .mOut needs to be at least 50, typically 100. - int max = num; - - int cost = u->GetCastCost(skill,order->extracost,1); //cost to make one if num = 1, or level otherwise. - if(num > 1) cost = (cost + level - 1) / level; //cost to make one. Final cost is recalculated below to account for rounding. - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - - for(c = 0; c < sizeof(ItemDefs[item].mInput)/sizeof(Materials); c++) { - if(ItemDefs[item].mInput[c].item == -1) continue; - int amt = u->GetSharedNum(ItemDefs[item].mInput[c].item); - int itemcost = ItemDefs[item].mInput[c].amt; - if(amt < itemcost) { - u->Error(AString("CAST: Doesn't have sufficient ") + - ItemDefs[ItemDefs[item].mInput[c].item].name + - " to create that.", order->quiet); - return 0; - } - if(amt < itemcost*num) num = amt / itemcost; //reduce num if we don't have enough items. - } - - if(num > 1) { - cost = u->GetCastCost(skill,order->extracost,num); //cost to make num*level - cost = (cost + level - 1) / level; //cost to make num. - if( cost > u->energy) { - num = (num*u->energy)/cost; //reduce num if we don't have the energy. - cost = u->GetCastCost(skill, order->extracost, num); - cost = (cost + level - 1) / level; //cost to make num. - } - } - u->energy -= cost; - - int exper = (20*num + max - 1)/ max; - if(exper > 10) exper = 10; - - u->Experience(skill,exper); - // Deduct the costs - for(c = 0; c < sizeof(ItemDefs[item].mInput)/sizeof(Materials); c++) { - if(ItemDefs[item].mInput[c].item == -1) continue; - int cost = ItemDefs[item].mInput[c].amt; - u->ConsumeShared(ItemDefs[item].mInput[c].item, num*cost); - } - - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - case 3: - case 2: - case 1: - u->Error(AString("Attempts to create an ") + ItemDefs[item].name + ", but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - u->items.SetNum(item,u->items.GetNum(item) + num); - u->Event(AString("Creates ") + ItemString(item,num) + "."); - if (num == 0) return 0; - return 1; - } - // non-Earthsea: - - //This got corrupted, and needs to be replaced if ARCADIA_MAGIC is turned off - return 0; -} - -int Game::RunSummonLich(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_SUMMON_LICH); - - int num = ((2 * level * level) + getrandom(100))/100; - - u->items.SetNum(I_LICH,u->items.GetNum(I_LICH) + num); - u->Event(AString("Summons ") + ItemString(I_LICH,num) + "."); - if (num == 0) return 0; - return 1; -} - -int Game::RunRaiseUndead(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_RAISE_UNDEAD); - - int num = ((10 * level * level) + getrandom(100))/100; - - u->items.SetNum(I_UNDEAD,u->items.GetNum(I_UNDEAD) + num); - u->Event(AString("Raises ") + ItemString(I_UNDEAD,num) + "."); - if (num == 0) return 0; - return 1; -} - -int Game::RunSummonSkeletons(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_SUMMON_SKELETONS); - - int num = ((40 * level * level) + getrandom(100))/100; - - u->items.SetNum(I_SKELETON,u->items.GetNum(I_SKELETON) + num); - u->Event(AString("Summons ") + ItemString(I_SKELETON,num) + "."); - if (num == 0) return 0; - return 1; -} - -int Game::RunDragonLore(ARegion *r, Unit *u, int isquiet) -{ - int level = u->GetSkill(S_DRAGON_LORE); - - int num = u->items.GetNum(I_DRAGON); - if (num >= level) { - u->Error("Mage may not summon more dragons.", isquiet); - return 0; - } - - int chance = level * level * 4; - if (getrandom(100) < chance) { - u->items.SetNum(I_DRAGON,num + 1); - u->Event("Summons a dragon."); - num = 1; - } else { - u->Event("Attempts to summon a dragon, but fails."); - num = 0; - } - if (num == 0) return 0; - return 1; -} - -int Game::RunBirdLore(ARegion *r,Unit *u) -{ - CastIntOrder *order = (CastIntOrder *) u->activecastorder; - int type = regions.GetRegionArray(r->zloc)->levelType; - - if(type != ARegionArray::LEVEL_SURFACE) { - AString error = "CAST: Bird Lore may only be cast on the surface of "; - error += Globals->WORLD_NAME; - error += "."; - u->Error(error.Str(), order->quiet); - return 0; - } - - if (order->level < 3) { - int cost = u->GetCastCost(S_BIRD_LORE,order->extracost); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } else u->energy -= cost; - - int level = u->GetSkill(S_BIRD_LORE); - u->Experience(S_BIRD_LORE,5); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int newdir; - switch(mevent) { - case 4: - case 3: - u->Error("Summoned birds get confused, and visit the wrong region.", order->quiet); - do{ - newdir = getrandom(6); - } while (newdir == order->target); - order->target = newdir; - break; - case 2: - case 1: - u->Error("Attempts to send birds to a neighbouring region, but they fail to return.", order->quiet); - return 1; - default: - break; - } - #endif - - - int dir = order->target; - int count = 0; - ARegion *tempReg = r; - - while(level > 0) { - level--; - ARegion *tar = tempReg->neighbors[dir]; - if (!tar) { - if(!count) u->Error("CAST: No such region.", order->quiet); - return 0; - } - count++; - tempReg = tar; - - Farsight *f = new Farsight; - f->faction = u->faction; - f->level = u->GetSkill(S_BIRD_LORE); - tar->farsees.Add(f); - u->Event(AString("Sends birds to spy on ") + - tar->Print( ®ions ) + "."); - } - return 1; - }/* else if(order->level == 4) { - - int cost = u->GetCastCost(S_BIRD_LORE,order->extracost,4); //4 times normal cost - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell."); - return 0; - } else u->energy -= cost; - - u->Experience(S_BIRD_LORE,20); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - case 3: - case 2: - case 1: - u->Error("Attempts to send birds to neighbouring regions, but they fail to return."); - return 1; - default: - break; - } - #endif - - for(int i=0; i<6; i++) { - ARegion *tar = r->neighbors[i]; - if (!tar) continue; - Farsight *f = new Farsight; - f->faction = u->faction; - f->level = u->GetSkill(S_BIRD_LORE); - tar->farsees.Add(f); - } - u->Event("Sends birds to spy on all neighbouring regions."); - return 1; - }*/ - - int level = u->GetSkill(S_BIRD_LORE); - int currentnum = u->items.GetNum(I_EAGLE); - - - int cost = u->GetCastCost(S_BIRD_LORE,order->extracost,10); //cost of 10 creatures ! - int num = 1; //if free energy, only summon one at once - if(cost > 0) { - num = (10*u->energy) / cost; - if(num < 1) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - } - if( (num + currentnum) > (level-2)*(level-2) ) num = (level-2)*(level-2) - currentnum; - if(num < 1) { - u->Error("CAST: Already have the maximum number of eagles.", order->quiet); - return 0; - } - if(order->target > 0 && order->target < num) num = order->target; - - cost = u->GetCastCost(S_BIRD_LORE,order->extracost,num); - u->energy -= cost; - - int experience = num*4; - if(experience > 20) experience = 20; - u->Experience(S_BIRD_LORE,experience); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - if(currentnum>0) { - u->Error(AString("Attempts to summon ") + ItemDefs[I_EAGLE].names + ", but all of those creatures magically disappear.", order->quiet); - u->items.SetNum(I_EAGLE,0); - return 1; - } - //fall thru - case 3: - case 2: - case 1: - u->Error(AString("Attempts to cast ") + SkillDefs[S_BIRD_LORE].name + ", but talking parrots appear instead.", order->quiet); - return 1; - default: - break; - } - #endif - - u->items.SetNum(I_EAGLE,currentnum + num); - u->Event(AString("Summons ") + ItemString(I_EAGLE,num)); - return 1; -} - -int Game::RunWolfLore(ARegion *r,Unit *u, int isquiet) -{ //in Arcadia, SummonCreatures is called instead unless there is no energy cost. - if (TerrainDefs[r->type].similar_type != R_MOUNTAIN && - TerrainDefs[r->type].similar_type != R_FOREST) { - u->Error("CAST: Can only summon wolves in mountain and " - "forest regions.", isquiet); - return 0; - } - - int level = u->GetSkill(S_WOLF_LORE); - int max = level * level * 4; - - int num = u->items.GetNum(I_WOLF); - int summon = max - num; - if (summon > level) summon = level; - if (summon < 0) summon = 0; - - u->Experience(S_WOLF_LORE,summon); //typically 'level' experience. - - u->Event(AString("Casts Wolf Lore, summoning ") + - ItemString(I_WOLF,summon) + "."); - u->items.SetNum(I_WOLF,num + summon); - if (summon == 0) return 0; - return 1; -} - -int Game::RunInvisibility(ARegion *r,Unit *u) -{ - CastUnitsOrder *order = (CastUnitsOrder *) u->activecastorder; - int level = u->GetSkill(S_INVISIBILITY); - int max = level * level; - int energymax = (u->energy * level) / u->GetCastCost(S_INVISIBILITY,order->extracost,1); - - int num = 0; - forlist (&(order->units)) { - Unit *tar = r->GetUnitId((UnitId *) elem,u->faction->num); - if (!tar) continue; - if (tar->GetAttitude(r,u) < A_FRIENDLY) continue; - num += tar->GetRealSoldiers(); - } - - if (!num) { - u->Error("CAST: No valid targets to turn invisible.", order->quiet); - return 0; - } - - if (num > max) { - u->Error("CAST: Can't render that many men or creatures invisible.", order->quiet); - } - if (num > energymax) { - u->Error("CAST: Not enough energy to render that many men or creatures invisible.", order->quiet); - } - if(energymax < max) max = energymax; //max is now the smaller of the two limits. - - int backfire = 0; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - u->Error("Attempts to cast invisibility, but the spell backfires, decreasing the stealth of the mage and targets by 2.", order->quiet); - backfire = 2; - u->SetFlag(FLAG_VISIB,1); - break; - case 3: - u->Error("Attempts to cast invisibility, but the spell backfires, decreasing the stealth of the targets by 2.", order->quiet); - backfire = 2; - break; - case 2: - case 1: - u->Error("Attempts to cast invisibility, but the spell fizzles.", order->quiet); - backfire = 1; //continue, because we have to count targets to know how much energy to deduct. - break; - default: - break; - } - #endif - - int men = 0; - forlist_reuse(&(order->units)) { - Unit *tar = r->GetUnitId((UnitId *) elem,u->faction->num); - if (!tar) continue; - if (tar->GetAttitude(r,u) < A_FRIENDLY) continue; - if ( (men + tar->GetSoldiers()) > max ) continue; - men += tar->GetSoldiers(); - if(!backfire) { - tar->SetFlag(FLAG_INVIS,1); - tar->Event(AString("Is rendered invisible by ") + - *(u->name) + "."); - } else if(backfire == 2) { - tar->SetFlag(FLAG_VISIB,1); - tar->Event(AString("Is rendered visible by ") + - *(u->name) + "."); - } - } - - int cost = u->GetCastCost(S_INVISIBILITY,order->extracost,men); - cost = (cost + level - 1) / level; - u->energy -= cost; - int experience = (20 * men) / (level*level); - if(experience > 10) experience = 10; - u->Experience(S_INVISIBILITY, experience); - - u->Event("Casts invisibility."); - return 1; -} - -int Game::RunPhanDemons(ARegion *r,Unit *u) -{ - CastIntOrder *order = (CastIntOrder *) u->activecastorder; - int level = u->GetSkill(S_CREATE_PHANTASMAL_DEMONS); - int create,max; - - if (order->level < 3) { - create = I_IIMP; - max = level * level * 4; - } else { - if (order->level < 5) { - create = I_IDEMON; - max = (level - 2) * (level - 2); - } else { - create = I_IBALROG; - max = 1; - } - } - - if (order->target > max || order->target <= 0) { - u->Error("CAST: Can't create that many Phantasmal Demons.", order->quiet); - return 0; - } - - u->items.SetNum(create,order->target); - u->Event("Casts Create Phantasmal Demons."); - return 1; -} - -int Game::RunPhanUndead(ARegion *r,Unit *u) -{ - CastIntOrder *order = (CastIntOrder *) u->activecastorder; - int level = u->GetSkill(S_CREATE_PHANTASMAL_UNDEAD); - int create,max; - - if (order->level < 3) { - create = I_ISKELETON; - max = level * level * 4; - } else { - if (order->level < 5) { - create = I_IUNDEAD; - max = (level - 2) * (level - 2); - } else { - create = I_ILICH; - max = 1; - } - } - - if (order->target > max || order->target <= 0) { - u->Error("CAST: Can't create that many Phantasmal Undead.", order->quiet); - return 0; - } - - u->items.SetNum(create,order->target); - u->Event("Casts Create Phantasmal Undead."); - return 1; -} - -int Game::RunPhanBeasts(ARegion *r,Unit *u) -{ - CastIntOrder *order = (CastIntOrder *) u->activecastorder; - int level = u->GetSkill(S_CREATE_PHANTASMAL_BEASTS); - int create,max; - - if (order->level < 3) { - create = I_IWOLF; - max = level * level * 4; - } else { - if (order->level < 5) { - create = I_IEAGLE; - max = (level - 2) * (level - 2); - } else { - create = I_IDRAGON; - max = 1; - } - } - - if (order->target > max || order->target <= 0) { - u->Error("CAST: Can't create that many Phantasmal Beasts.", order->quiet); - return 0; - } - - u->items.SetNum(create,order->target); - u->Event("Casts Create Phantasmal Beasts."); - return 1; -} - -int Game::RunPhanCreatures(ARegion *r,Unit *u) -{ - CastMenOrder *order = (CastMenOrder *) u->activecastorder; - int level = u->GetSkill(S_ILLUSORY_CREATURES); - - if(order->level > level) { - u->Error("CAST: Insufficient level to create that illusion.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_ILLUSORY_CREATURES,order->extracost,10); // this is the cost to summon ten balrogs, - //or 4 demons, or 40 imps. - int change = order->men - u->items.GetNum(order->race); - if(!change) { - u->Error("CAST: The mage already has that many of that creature.", order->quiet); - return 1; - } - - cost *= change; - if(cost <= 0) cost = 0; - else { - switch(order->race) { - case I_IWOLF: - case I_ISKELETON: - case I_IIMP: - cost = (cost+399)/400; - break; - case I_IEAGLE: - case I_IDEMON: - case I_IUNDEAD: - cost = (cost+39)/40; - break; - case I_IGRYFFIN: - case I_IBALROG: - case I_ILICH: - cost = cost/10; - break; - case I_IDRAGON: - cost = cost/5; - break; - default: - u->Error("CAST: That does not seem to be an illusionary creature. This error should not occur, contact your GM.", 0); - return 1; - } - } - - if(cost > u->energy) { - u->Error("CAST: Not enough energy to create that many illusions.", order->quiet); - return 0; - } - u->energy -= cost; - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - u->Error("Attempts to create illusionary creatures, but the spell backfires, and all his illusory creatures are lost!", order->quiet); - for(int i=0; iitems.SetNum(i,0); - return 0; - case 3: - u->Error("Attempts to create illusionary creatures, but the spell backfires, and illusory cockroaches " - "swarm over him all month long, despite his efforts to get rid of them.", order->quiet); - u->energy -= 4; - if(u->energy < 0) u->energy = 0; - u->Experience(S_ILLUSORY_CREATURES,10); - return 1; - case 2: - case 1: - u->Error("Attempts to create illusionary creatures, but the spell fizzles, producing only illusory roast dinners.", order->quiet); - u->Experience(S_ILLUSORY_CREATURES,10); - return 1; - default: - break; - } - #endif - - int experience = 5 * cost; - if(experience > 30) experience = 30; - u->Experience(S_ILLUSORY_CREATURES, experience); - - u->items.SetNum(order->race,order->men); - u->Event("Casts Create Illusory Creatures."); - return 1; -} - -int Game::RunPhanEntertainment(ARegion *r,Unit *u) -//castable spell in Arc-III only. -{ - CastOrder *order = (CastOrder *) u->activecastorder; - int level = u->GetSkill(S_PHANTASMAL_ENTERTAINMENT); - - if(!r->town || r->town->TownType() != TOWN_CITY) { - u->Error("CAST: That spell can only be cast in cities.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_PHANTASMAL_ENTERTAINMENT,order->extracost); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell", order->quiet); - return 0; - } - u->energy -= cost; - - #ifdef FIZZLES - int mevent = u->MysticEvent(); -// int numunits = 0; -// Unit *tar = u; - - switch(mevent) { - case 4: - case 3: - u->Error("Attempts to entertain the nobility, and succeeds so well that jealous husbands leave him penniless, " - "while their wives leave him exhausted!", order->quiet); - u->energy = 0; - u->items.SetNum(I_SILVER,0); - u->Experience(S_PHANTASMAL_ENTERTAINMENT,10); - u->Experience(S_ENTERTAINMENT,90); - return 1; - case 2: - u->Error("Attempts to entertain the nobility, but they are a humourless bunch, and he is forced to weave " - "a web of illusions to escape unharmed.", order->quiet); - u->energy -= cost; - if(u->energy < 0) u->energy = 0; - u->Experience(S_PHANTASMAL_ENTERTAINMENT,20); - u->Experience(S_ILLUSION,40); - return 1; - case 1: - u->Error("Attempts to entertain the nobility, but his spells fizzle, and he gets covered in rotten tomato juice.", order->quiet); - u->Experience(S_PHANTASMAL_ENTERTAINMENT,10); - //unfortunately there is not yet any fruit-dodging skill to practise. - return 1; - default: - break; - } - #endif - - u->items.SetNum(I_SILVER,u->items.GetNum(I_SILVER) + 100 * level); - u->Experience(S_PHANTASMAL_ENTERTAINMENT,10); - u->Event(AString("Casts Phantasmal Entertainment, raising ") + (100*level) + " silver from the nobility."); - return 1; -} - -int Game::RunEarthLore(ARegion *r,Unit *u) -{ - int level = u->GetSkill(S_EARTH_LORE); - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - int size = order->level - 1; // 3 if large, 0 otherwise - int penalty = 0; - if(size>2) penalty = 2; //2 is max penalty - AString temp = "Casts Earth Lore"; - ARegion *tar = r; - int val; - - RangeType *range = FindRange(SkillDefs[S_EARTH_LORE].range); - if(range != NULL) { - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_EARTH_LORE,order->quiet,penalty); - if(!val) return 0; - temp += " on "; - temp += tar->ShortPrint(®ions); - } - - if(TerrainDefs[tar->type].similar_type == R_OCEAN) { - u->Error("CAST: Cannot cast Earth Lore at sea.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_EARTH_LORE,order->extracost, 1); - int largecost = u->GetCastCost(S_EARTH_LORE,order->extracost, 4); - - if(cost > u->energy) { //if large and not enough energy for large casting, we default to small, so don't exit - u->Error("CAST: Not enough energy to cast that spell", order->quiet); - return 0; - } - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - case 3: - case 2: - case 1: - u->Error("Attempts to cast earth lore, but the spell fizzles.", order->quiet); - u->Experience(S_EARTH_LORE,10); - if(!size) u->energy -= cost; - else u->energy -= largecost; - return 1; - default: - break; - } - #endif - - if (level > tar->earthlore) r->earthlore = level; - int amt = tar->Wages() * level * 4; - - int count = 0; - if (size && Globals->ARCADIA_MAGIC) { - if(level < 4) { - u->Error("CAST: Not high enough level for large casting.", order->quiet); - } else if(largecost <= u->energy) { - for (int i = 0; i<6; i++) { - if(tar->neighbors[i] && TerrainDefs[tar->neighbors[i]->type].similar_type != R_OCEAN) { - count++; - if (level > tar->neighbors[i]->earthlore) tar->neighbors[i]->earthlore = level; - amt += tar->neighbors[i]->Wages() * level * 4; - } - } - if(range == NULL) temp += AString(" on ") + tar->ShortPrint(®ions); - temp += AString(" and ") + count + " neighbouring regions"; - } else { - u->Error("CAST: Not enough energy for large casting.", order->quiet); - } - } - temp += AString(", raising ") + amt + " silver."; - - if(count) { - u->energy -= largecost; - u->Experience(S_EARTH_LORE,20); - } else { - u->energy -= cost; - u->Experience(S_EARTH_LORE,10); - } - - u->items.SetNum(I_SILVER,u->items.GetNum(I_SILVER) + amt); - u->Event(temp); - - return 1; -} - -int Game::RunClearSkies(ARegion *r, Unit *u) -{ - ARegion *tar = r; - AString temp = "Casts Clear Skies"; - int val; - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - int size = order->level - 1; - int penalty = 0; - if(size) penalty = 2; - - RangeType *range = FindRange(SkillDefs[S_CLEAR_SKIES].range); - if(range != NULL) { - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_CLEAR_SKIES, order->quiet, penalty); - if(!val) return 0; - temp += " on "; - temp += tar->ShortPrint(®ions); - } - - int level = u->GetSkill(S_CLEAR_SKIES); - - if(Globals->ARCADIA_MAGIC) { - if(size && level < 4) { - u->Error("CAST: Not high enough level for large casting.", order->quiet); - return 0; - } - if(penalty < 1) penalty = 1; - int cost = u->GetCastCost(S_CLEAR_SKIES,order->extracost,penalty*penalty); //*4 if large - if(u->energy < cost) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - u->Experience(S_CLEAR_SKIES,10*penalty); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - switch(mevent) { - case 4: - u->Error("Attempts to cast clearskies, but a terrible blizzard appears instead.", order->quiet); - tar->weather = W_BLIZZARD; - return 1; - case 3: - case 2: - xx = getrandom(regions.GetRegionArray(1)->x); - do { - yy = getrandom(regions.GetRegionArray(1)->y); - } while ( (xx+yy)%2 ); - tar = regions.GetRegion(xx,yy,1); - if(!tar) { - u->Error("Attempts to cast clearskies, but the spell fizzles.", order->quiet); - return 1; - } - u->Error(AString("Attempts to cast clearskies, but the spell is misaimed, hitting ") + tar->ShortPrint(®ions), order->quiet); - break; - case 1: - u->Error("Attempts to cast clearskies, but the spell fizzles, and the mage gets rained on.", order->quiet); - return 1; - default: - break; - } - #endif - } - - if (level > tar->clearskies) tar->clearskies = level; - - if (size && Globals->ARCADIA_MAGIC) { - int count = 0; - for (int i = 0; i<6; i++) { - if(tar->neighbors[i]) { - count++; - if (level > tar->neighbors[i]->clearskies) tar->neighbors[i]->clearskies = level; - } - } - temp += AString(" and ") + count + " neighbouring regions"; - } - - temp += "."; - u->Event(temp); - return 1; -} - -int Game::RunWeatherLore(ARegion *r, Unit *u) -{ - ARegion *tar; - int val, i; - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_WEATHER_LORE, order->quiet, 0); - if(!val) return 0; - - int level = u->GetSkill(S_WEATHER_LORE); - int months = 3; - if(level >= 5) months = 12; - else if (level >= 3) months = 6; - - AString temp = "Casts Weather Lore on "; - temp += tar->ShortPrint(®ions); - temp += ". It will be "; - int weather, futuremonth; - for(i = 0; i <= months; i++) { - futuremonth = (month + i)%12; - weather=regions.GetWeather(tar, futuremonth); - temp += SeasonNames[weather]; - temp += " in "; - temp += MonthNames[futuremonth]; - if(i < (months-1)) - temp += ", "; - else if(i == (months-1)) - temp += " and "; - else - temp += "."; - } - u->Event(temp); - return 1; -} - -int Game::RunFarsight(ARegion *r,Unit *u) -{ - ARegion *tar; - int val; - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - - int size = order->level - 1; - int penalty = 0; - if(size) penalty = 2; - - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_FARSIGHT, order->quiet, penalty); - if(!val) return 0; - - int level = u->GetSkill(S_FARSIGHT); - - if(Globals->ARCADIA_MAGIC) { - if(size && level < 4) { - u->Error("CAST: Not high enough level for large casting.", order->quiet); - return 0; - } - - if(penalty<1) penalty=1; - int cost = u->GetCastCost(S_FARSIGHT, order->extracost, penalty*penalty); //*4 if large - if(u->energy < cost) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - u->Experience(S_FARSIGHT,10*penalty); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - switch(mevent) { - case 4: - u->Error("Attempts to cast farsight, but it is reflected, displaying the mage's region for all in the " - "target region to see.", order->quiet); - //not programmed - return 1; - case 3: - case 2: - xx = getrandom(regions.GetRegionArray(1)->x); - do { - yy = getrandom(regions.GetRegionArray(1)->y); - } while ( (xx+yy)%2 ); - tar = regions.GetRegion(xx,yy,1); - if(!tar) { - u->Error("Attempts to cast farsight, but the spell fizzles.", order->quiet); - return 1; - } - u->Error(AString("Attempts to cast farsight, but the spell is misaimed, hitting ") + tar->ShortPrint(®ions), order->quiet); - break; - case 1: - u->Error("Attempts to cast farsight, but the spell fizzles, and the mage gets two black eyes.", order->quiet); - return 1; - default: - break; - } - #endif - } - - Farsight *f = new Farsight; - f->faction = u->faction; - f->level = u->GetSkill(S_FARSIGHT); - f->unit = u; - tar->farsees.Add(f); - AString temp = "Casts Farsight on "; - temp += tar->ShortPrint(®ions); - - if (size && Globals->ARCADIA_MAGIC) { - int count = 0; - for (int i = 0; i<6; i++) { - if(tar->neighbors[i]) { - Farsight *f = new Farsight; - f->faction = u->faction; - f->level = u->GetSkill(S_FARSIGHT); - f->unit = u; - tar->neighbors[i]->farsees.Add(f); - count++; - } - } - temp += AString(" and ") + count + " neighbouring regions"; - } - - temp += "."; - u->Event(temp); - return 1; -} - -int Game::RunDetectGates(ARegion *r,Object *o,Unit *u) -{ - CastOrder *order = (CastOrder *)u->activecastorder; - int distance = 1; - if(order->level == 5) distance = 2; - - int level = u->GetSkill(S_GATE_LORE); - - if (level == 1) { - u->Error("CAST: Insufficient level to DETECT gates.",order->quiet); - return 0; - } - - if(Globals->ARCADIA_MAGIC) { - - int cost = u->GetCastCost(S_GATE_LORE, order->extracost, distance*distance); - if(u->energy < cost) { - u->Error("CAST: Not enough energy to cast that spell.",order->quiet); - return 0; - } - u->energy -= cost; - u->Experience(S_GATE_LORE,6*distance); //low experience, most experience comes from gating around. - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - case 3: - case 2: - case 1: - u->Error("Attempts to cast detect gates, but the spell fizzles, leaving the mage with a headache."); - return 1; - default: - break; - } - #endif - } - - - u->Event("Casts Gate Lore, detecting nearby Gates:"); - int found = 0; - if ((r->gate) && (!r->gateopen)) { - u->Event(AString("Identified local gate number ") + (r->gate) + - " in " + r->ShortPrint(®ions) + "."); - } - for (int i=0; ineighbors[i]; - if (tar) { - if (tar->gate) { - if(Globals->DETECT_GATE_NUMBERS) { - u->Event(tar->Print(®ions) + - " contains Gate " + tar->gate + - "."); - } else { - u->Event(tar->Print(®ions) + - " contains a Gate."); - } - found = 1; - } - } - } - if(distance == 2) { - //check regions distance two away - //first, clear markers on those regions. - for(int i=0; ineighbors[i]; - if(adj) { - for(int j=0; jneighbors[j]; - if(tar) tar->marker = 0; - } - } - } - //second, mark adjacent regions. - for(int i=0; ineighbors[i]; - if(adj) adj->marker = 1; - } - //third, cycle through dist 2 regions with marker = 0. - for(int i=0; ineighbors[i]; - if(adj) { - for(int j=0; jneighbors[j]; - if(tar->marker == 0) { - tar->marker = 1; - if (tar->gate) { - if(Globals->DETECT_GATE_NUMBERS) { - u->Event(tar->Print(®ions) + - " contains Gate " + tar->gate + - "."); - } else { - u->Event(tar->Print(®ions) + - " contains a Gate."); - } - found = 1; - } - } - } - } - } - } - - if (!found) - u->Event("There are no nearby Gates."); - return 1; -} - -int Game::RunTeleport(ARegion *r,Object *o,Unit *u) -{ - ARegion *tar; - int val; - - CastRegionOrder *order = (CastRegionOrder *)u->teleportorders; - - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_TELEPORTATION, order->quiet, 0); - if(!val) return 0; - - int level = u->GetSkill(S_TELEPORTATION); - int maxweight = level * 50; - if(Globals->ARCADIA_MAGIC) maxweight *= level; - - if (u->Weight() > maxweight) { - u->Error("CAST: Can't carry that much when teleporting.", order->quiet); - return 0; - } - - // Presume they had to open the portal to see if target is ocean - if (TerrainDefs[tar->type].similar_type == R_OCEAN) { - u->Error(AString("CAST: ") + tar->Print(®ions) + - " is an ocean.",order->quiet); - return 1; - } - - if(Globals->ARCADIA_MAGIC) { - - int cost = u->GetCastCost(S_TELEPORTATION,order->extracost,(u->Weight()/level)); //This is 50 times the cost. - cost /= 50; - if(u->energy < cost) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - int experience = (40 * u->Weight()) / (50*level*level); - if(experience > 15) experience = 15; - - u->Experience(S_TELEPORTATION,experience); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - switch(mevent) { - case 4: - case 3: - do { - tar = 0; - xx = getrandom(regions.GetRegionArray(1)->x); - yy = getrandom(regions.GetRegionArray(1)->y); - if(!(xx+yy)%2) tar = regions.GetRegion(xx,yy,1); - } while ( tar == 0 || TerrainDefs[tar->type].similar_type == R_OCEAN ); - - if(!tar) { - u->Error("Attempts to cast teleport, but the spell fizzles.", order->quiet); - return 1; - } - u->Error(AString("Attempts to teleport, but the spell is misaimed, teleporting the mage to ") + tar->ShortPrint(®ions), order->quiet); - break; - case 2: - case 1: - u->Error("Attempts to cast teleport, but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - } - - u->Event(AString("Teleports to ") + tar->Print(®ions) + "."); - u->MoveUnit(tar->GetDummy()); - return 1; -} - -int Game::RunGateJump(ARegion *r,Object *o,Unit *u) -{ - int level = u->GetSkill(S_GATE_LORE); - int nexgate = 0; - - TeleportOrder *order = u->teleportorders; - - if( !level ) { - u->Error( "CAST: Unit doesn't have that skill.", order->quiet ); - return 0; - } - - if (order->gate != -1 && level < 3) { - u->Error("CAST: Unit Doesn't know Gate Lore at that level.", order->quiet); - return 0; - } - - nexgate = Globals->NEXUS_GATE_OUT && - (TerrainDefs[r->type].similar_type == R_NEXUS); - if (!r->gate && !nexgate) { - u->Error("CAST: There is no gate in that region.", order->quiet); - return 0; - } - - if (!r->gateopen) { - u->Error("CAST: Gate not open at this time of year.", order->quiet); - return 0; - } - - int maxweight = 10; - if (order->gate != -1) level -= 2; //subtract two levels if targetting a particular gate - if(Globals->ARCADIA_MAGIC) { - maxweight = (18*u->GetEnergy())/(u->GetCastCost(S_GATE_LORE,order->extracost,1)); - maxweight *= level*level; //can carry 3*level^2 weight per energy. - } else { - switch (level) { - case 1: - maxweight = 15; - break; - case 2: - maxweight = 100; - break; - case 3: - case 4: - case 5: - maxweight = 1000; - break; - } - } - int weight = u->Weight(); - - forlist (&(order->units)) { - Unit *taru = r->GetUnitId((UnitId *) elem,u->faction->num); - if (taru && taru != u) weight += taru->Weight(); - } - - if (weight > maxweight) { - u->Error( "CAST: That mage cannot carry that much weight " - "through a Gate.", order->quiet); - return 0; - } - - if(Globals->ARCADIA_MAGIC) { - int cost = u->GetCastCost(S_GATE_LORE,order->extracost,weight); - cost = (cost + 18*level*level - 1) / (18*level*level); - u->energy -= cost; - int experience = weight / (level*level*level); - if(experience > 10) experience = 10; - u->Experience(S_GATE_LORE, experience); //max experience takes 10*level*level*level weight. - - #ifdef FIZZLES - int mevent = u->MysticEvent(); -// int xx; -// int yy; - switch(mevent) { - case 4: -/* u->Error("Attempts to cast gate jump, but the mage emerges at a random location."); - ARegion *tar = 0; - do { - tar = 0; - xx = getrandom(regions.GetRegionArray(r->zloc)->x); - yy = getrandom(regions.GetRegionArray(1)->y); - if(!(xx+yy)%2) tar = regions.GetRegion(xx,yy,1); - } while ( tar == 0 || TerrainDefs[tar->type].similar_type == R_OCEAN ); -*/ - case 3: - case 2: - if(order->gate != -1) { - order->gate = -1; - u->Error("Attempts to jump to a particular gate, but the spell backfires, sending the mage to a random gate.", order->quiet); - break; - } - case 1: - u->Error("Attempts to cast gate jump, but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - } - - ARegion *tar; - if (order->gate == -1) { - int good = 0; - int gatenum = getrandom(regions.numberofgates); - tar = regions.FindGate(gatenum+1); - - if(tar && tar->zloc == r->zloc) good = 1; - if(tar && nexgate && tar->zloc == ARegionArray::LEVEL_SURFACE) - good = 1; - - while( !good ) { - gatenum = getrandom(regions.numberofgates); - tar = regions.FindGate(gatenum+1); - if(tar && tar->zloc == r->zloc) good = 1; - if(tar && nexgate && tar->zloc == ARegionArray::LEVEL_SURFACE) - good = 1; - } - - u->Event("Casts Random Gate Jump."); - } else { - if (order->gate < 1 || order->gate > regions.numberofgates) { - u->Error("CAST: No such target gate.", order->quiet); - return 0; - } - - tar = regions.FindGate(order->gate); - if (!tar) { - u->Error("CAST: No such target gate.", order->quiet); - return 0; - } - if(!tar->gateopen) { - u->Error("CAST: Target gate not open at this time of year.", order->quiet); - return 0; - } - - u->Event("Casts Gate Jump."); - } - - int comma = 0; - AString unitlist; { - forlist(&(order->units)) { - Location *loc = r->GetLocation((UnitId *) elem,u->faction->num); - if (loc) { - /* Don't do the casting unit yet */ - if (loc->unit == u) { - delete loc; - continue; - } - - if (loc->unit->GetAttitude(r,u) < A_ALLY) { - u->Error("CAST: Unit is not allied.", order->quiet); - } else { - if (comma) { - unitlist += AString(", ") + AString(loc->unit->num); - } else { - unitlist += AString(loc->unit->num); - comma = 1; - } - - loc->unit->Event(AString("Is teleported through a ") + - "Gate to " + tar->Print(®ions) + " by " + - *u->name + "."); - loc->unit->MoveUnit( tar->GetDummy() ); - if (loc->unit != u) loc->unit->ClearCastOrder(); - } - delete loc; - } else { - u->Error("CAST: No such unit.", order->quiet); - } - } - } - - u->Event(AString("Jumps through a Gate to ") + - tar->Print( ®ions ) + "."); - if (comma) { - u->Event(unitlist + " follow through the Gate."); - } - u->MoveUnit( tar->GetDummy() ); - return 1; -} - -int Game::RunPortalLore(ARegion *r,Object *o,Unit *u) -{ - int level = u->GetSkill(S_PORTAL_LORE); - TeleportOrder *order = u->teleportorders; - - if (!level) { - u->Error("CAST: Doesn't know Portal Lore.", order->quiet); - return 0; - } - - if (!u->items.GetNum(I_PORTAL)) { - u->Error("CAST: Unit doesn't have a Portal.", order->quiet); - return 0; - } - - int maxweight = 50 * level; - int weight = 0; - forlist (&(order->units)) { - Unit *taru = r->GetUnitId((UnitId *) elem,u->faction->num); - if (taru) weight += taru->Weight(); - } - - if (weight > maxweight) { - u->Error("CAST: That mage cannot teleport that much weight through a " - "Portal.", order->quiet); - return 0; - } - - Location *tar = regions.FindUnit(order->gate); - if (!tar) { - u->Error("CAST: No such target mage.", order->quiet); - return 0; - } - - if (tar->unit->faction->GetAttitude(u->faction->num) < A_FRIENDLY) { - u->Error("CAST: Target mage is not friendly.", order->quiet); - return 0; - } - - if (tar->unit->type != U_MAGE) { - u->Error("CAST: Target is not a mage.", order->quiet); - return 0; - } - - if (!tar->unit->items.GetNum(I_PORTAL)) { - u->Error("CAST: Target does not have a Portal.", order->quiet); - return 0; - } - - if (!GetRegionInRange(r, tar->region, u, S_PORTAL_LORE, order->quiet, 0)) return 0; - - u->Event("Casts Portal Jump."); - - { - forlist(&(order->units)) { - Location *loc = r->GetLocation((UnitId *) elem,u->faction->num); - if (loc) { - if (loc->unit->GetAttitude(r,u) < A_ALLY) { - u->Error("CAST: Unit is not allied.", order->quiet); - } else { - loc->unit->Event(AString("Is teleported to ") + - tar->region->Print( ®ions ) + - " by " + *u->name + "."); - loc->unit->MoveUnit( tar->obj ); - if (loc->unit != u) loc->unit->ClearCastOrder(); - } - delete loc; - } else { - u->Error("CAST: No such unit.", order->quiet); - } - } - } - - delete tar; - return 1; -} - -void Game::RunTeleportOrders() -{ - int val = 1; - forlist(®ions) { - ARegion * r = (ARegion *) elem; - forlist(&r->objects) { - Object * o = (Object *) elem; - int foundone = 1; - while (foundone) { - foundone = 0; - forlist(&o->units) { - Unit * u = (Unit *) elem; - if (u->teleportorders) { - foundone = 1; - switch (u->teleportorders->spell) { - case S_GATE_LORE: - val = RunGateJump(r,o,u); - break; - case S_TELEPORTATION: - val = RunTeleport(r,o,u); - break; - case S_PORTAL_LORE: - val = RunPortalLore(r,o,u); - break; - } - if (val) - u->Practice(u->teleportorders->spell); - delete u->teleportorders; - u->teleportorders = 0; - break; - } - } - } - } - } -} - -int Game::RunBlizzard(ARegion *r, Unit *u) -// Earthsea spell -{ - ARegion *tar; - int val; - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - - int size = order->level - 1; - int penalty = 0; - if(size) penalty = 2; - int level = u->GetSkill(S_BLIZZARD); - - if(size && level < 4) { - u->Error("CAST: Not high enough level for large casting.", order->quiet); - return 0; - } - - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_BLIZZARD, order->quiet, penalty); - if(!val) return 0; - - if(penalty<1) penalty = 1; - int cost = u->GetCastCost(S_BLIZZARD,order->extracost, penalty*penalty); // 4 times cost for large casting. - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - switch(mevent) { - case 4: - case 3: - u->Error("Attempts to cast a blizzard, but the spell is reflected back on the caster!", order->quiet); - tar = r; - //get experience normally! - break; - case 2: - xx = getrandom(regions.GetRegionArray(1)->x); - do { - yy = getrandom(regions.GetRegionArray(1)->y); - } while ( (xx+yy)%2 ); - tar = regions.GetRegion(xx,yy,1); - if(!tar) { - u->Error("Attempts to cast a blizzard, but the spell fizzles.", order->quiet); - u->Experience(S_BLIZZARD,10); - return 1; - } - u->Error(AString("Attempts to cast a blizzard, but the spell is misaimed, hitting ") + tar->ShortPrint(®ions), order->quiet); - //get experience normally! - break; - case 1: - u->Error("Attempts to cast a blizzard, but the spell fizzles, and the mage is seen shivering all month long.", order->quiet); - u->Experience(S_BLIZZARD,10); - return 1; - default: - break; - } - #endif - - - AString temp = "Casts Blizzard on "; - temp += tar->ShortPrint(®ions); - if (size) { - int count = 0; - for (int i = 0; i<6; i++) { - if(tar->neighbors[i]) { - tar->neighbors[i]->weather = W_BLIZZARD; - count++; - } - } - temp += AString(" and ") + count + " neighbouring regions"; - } - temp += "."; - tar->weather = W_BLIZZARD; - u->Event(temp); - if(size) u->Experience(S_BLIZZARD,20); - else u->Experience(S_BLIZZARD,10); - return 1; -} - -int Game::RunSeaward(ARegion *r, Unit *u) -// Arcadia spell -{ - ARegion *tar; - int val; - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - - int size = order->level - 1; - int penalty = 0; - if(size) penalty = 2; - int level = u->GetSkill(S_SEAWARD); - int time = level/2 + level%2; - - if(size && level < 4) { - u->Error("CAST: Not high enough level for large casting.", order->quiet); - return 0; - } - - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_SEAWARD, order->quiet, penalty); - - // should have something here for reducing range of large spells. - if(!val) return 0; - - int cost = u->GetCastCost(S_SEAWARD,order->extracost); // cost of normal size - if(size) cost = u->GetCastCost(S_SEAWARD,order->extracost,3); //note, only 3, not usual 4, because it is highly unlikely all six neighbouring regions can be affected. - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - //subtraction of energy done at the end. - - if(!size && (tar->willsink == 0 || tar->willsink >= time)) { - u->Error("CAST: That region is not sinking.", order->quiet); //check so it doesn't have a chance to fizzle in single cast. - return 0; - } - -// int destroyed = 0; - int permanent = 0; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - switch(mevent) { - case 4: - u->Error("Attempts to ward off the sea, but the spell backfires, attracting the ocean to " - "the target's neighbouring regions as well.", order->quiet); - for (int i = 0; i<6; i++) { - if(tar->neighbors[i]) { - if(TerrainDefs[tar->neighbors[i]->type].similar_type == R_OCEAN) continue; //do not try to sink ocean regions! - if(tar->neighbors[i]->willsink != 1) { - tar->neighbors[i]->willsink = 2; - } - } - } - u->Experience(S_SEAWARD,20); - return 1; - case 3: - if(tar->willsink < 1) break; - u->Error("Mystic energies cause a sea ward to have incredible effectiveness.", order->quiet); - permanent = 1; - break; - case 2: - //this case could cause problems if casting large on regions with nothing sinking. - forlist(&r->objects) { - Object *obj = (Object *) elem; - if(obj->type != O_DUMMY && obj->inner == -1) { - //Move units out - Object *dest = r->GetDummy(); - forlist(&obj->units) { - Unit *u = (Unit *) elem; - u->MoveUnit(dest); - } - //destroy object - r->objects.Remove(obj); - delete obj; - destroyed++; - } - } - if(destroyed) u->Error(AString("While warding off the sea, high winds destroy ") + destroyed + " structures in the region.", order->quiet); - break; - case 1: - u->Error("Attempts to ward off the sea, but the spell fizzles, and a freak storm of fish land on the mage.", order->quiet); - u->Experience(S_SEAWARD,10); - u->energy -= cost; - if(!(ItemDefs[I_FISH].flags & ItemType::DISABLED)) u->items.SetNum(I_FISH,u->items.GetNum(I_FISH) + 20); - - if(u->energy < 0) u->energy = 0; - return 1; - default: - break; - } - #endif - - - int done = 0; - AString temp = "Wards the sea away from "; - temp += tar->ShortPrint(®ions); - if (size && Globals->ARCADIA_MAGIC) { - for (int i = 0; i<6; i++) { - if(tar->neighbors[i]) { - if(tar->neighbors[i]->willsink > 0 && tar->neighbors[i]->willsink <= time) { - tar->neighbors[i]->willsink = time + 1; - done = 1; - } - } - } - temp += " and all neighbouring regions"; - } - temp += AString(", holding the sea at bay for ") + time + " month"; - if(time>1) temp += "s"; - temp += "."; - - if(tar->willsink > 0 && tar->willsink <= time) { - tar->willsink = time+1; - done = 1; - } - if(tar->willsink && permanent) { - tar->willsink = 0; //never sinks - done = 1; - } - - if(!done) { - u->Error("CAST: That region is not sinking.", order->quiet); - return 0; - } - - u->energy -= cost; - if(size) u->Experience(S_SEAWARD,30); //highish experience because unusual spell to cast. - else u->Experience(S_SEAWARD,15); - - if(!permanent) u->Event(temp); - return 1; -} - -int Game::RunDiversion(ARegion *r, Unit *u) -// Arcadia spell -// Complicated 3 case code. I cannot see a simpler solution however. -{ -// If rivers disabled, return! (else will crash below) - if((HexsideDefs[H_RIVER].flags & HexsideType::DISABLED) || !Globals->HEXSIDE_TERRAIN) return 0; - - ARegion *tar; - int val; - - CastRegionOrder *order = (CastRegionOrder *)u->activecastorder; - - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_DIVERSION, order->quiet, 0); - if(!val) return 0; - - int cost = u->GetCastCost(S_DIVERSION,order->extracost); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - u->Experience(S_DIVERSION, 15); - - int rivers = 0; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - int tries = 0; - switch(mevent) { - case 4: - case 3: - xx = getrandom(regions.GetRegionArray(1)->x); - do { - tar = 0; - yy = getrandom(regions.GetRegionArray(1)->y); - if(!(xx+yy)%2) tar = regions.GetRegion(xx,yy,1); - if(tar) { - for(int i=0; i<6; i++) { - Hexside *h = tar->hexside[i]; - if(h && h->type == H_RIVER) rivers++; - } - } - } while ( (tar == 0 || rivers == 0 ) && tries++ < 1000); - if(!tar) { - u->Error("Attempts to cast diversion, but the spell fizzles.", order->quiet); - return 1; - } - u->Error(AString("Attempts to cast diversion, but the spell is misaimed, hitting ") + tar->ShortPrint(®ions), order->quiet); - break; - case 2: - case 1: - u->Error("Attempts to cast diversion, but the spell fizzles, dragging the mage into a nearby well.", order->quiet); - return 1; - default: - break; - } - #endif - -// If no river in region, return (do not create a river "ring") - rivers = 0; - for(int i=0; i<6; i++) { - if(tar->hexside[i]->type == H_RIVER) rivers++; - } - if(!rivers) { - u->Error("CAST: No rivers in that region.", order->quiet); - return 0; - } - if(rivers == 6) { - u->Error("CAST: Nowhere to divert river to.", order->quiet); - return 0; - } - -// Currently this code can leave hanging rivers if cast on a -// river junction. Must deal with this somehow. -Fixed? - - int inflows[6]; - for (int i=0; i<6; i++) inflows[i] = 0; - - for (int k=0; k<6; k++) { - if(!tar->neighbors[k]) continue; - if(tar->neighbors[k]->hexside[(k+2)%6]->type == H_RIVER) { - inflows[k] += 1; - } - if(tar->neighbors[k]->hexside[(k+4)%6]->type == H_RIVER) { - inflows[(k+5)%6] += 1; - } - } - int total = 0; - for (int j=0; j<6; j++) { - if(inflows[j]) total++; - } - - //only continue if inflows < 3. Otherwise, divide river piecemeal. - if(total < 3) { - - for (int i=0; i<6; i++) { - if(tar->hexside[i]->type == H_RIVER) { - tar->hexside[i]->type = H_DUMMY; -// tar->hexside[i]->bridge = 0; - continue; - } - - if(tar->neighbors[i] && TerrainDefs[tar->neighbors[i]->type].similar_type == R_OCEAN) continue; - //no river, non coastal. Create river. - tar->hexside[i]->type = H_RIVER; - } - } else { - // 3+ inflows - int nonseg = 0; //counting number of strips of non-beach/river (could be up to 3) - for(int k=0; k<6; k++) { - if (tar->hexside[k]->type == H_RIVER) continue; - if (tar->neighbors[k] && (TerrainDefs[tar->neighbors[k]->type].similar_type == R_OCEAN) ) continue; - //not a beach or river. - - if (tar->hexside[(k+5)%6]->type == H_RIVER) { - nonseg++; - continue; - } - if (tar->neighbors[(k+5)%6] && (TerrainDefs[tar->neighbors[(k+5)%6]->type].similar_type == R_OCEAN) ) { - if (tar->hexside[(k+4)%6]->type == H_RIVER) nonseg++; - else break; //three continuous non-rivers -> break - } - } - - if((nonseg > 1) && (total == 4)) { - //two non-river segments, 4+ inflows: - for(int k=0; k<6; k++) { - if(tar->hexside[k]->type == H_RIVER) { - tar->hexside[k]->type = H_DUMMY; -// tar->hexside[k]->bridge = 0; - continue; - } - if(tar->neighbors[k] && (TerrainDefs[tar->neighbors[k]->type].similar_type == R_OCEAN)) continue; - //non river, non coastal. Create river. - tar->hexside[k]->type = H_RIVER; - } - } else { - //one non-river segment, 3+ inflows, or two non-river segments and 5+ inflows: - - int foundnon = 0; //found non-river segment - int foundriv = 0; //found river segment - int first = 1; - for(int i=0; i<12; i++) { - int j=i%6; - int river = 0; - if(tar->hexside[j]->type == H_RIVER) river = 1; - - //we have to find a river segment first - if(!foundriv) { - if(!river) continue; - else foundriv = 1; - } - //then we have to find the non-river segment - if(!foundnon) { - if(river) continue; - else foundnon = 1; - } - - //then we treat the non-river segment(s) - if(!river && first) { - //if coastal, cycle - if(tar->neighbors[j]) { - if(TerrainDefs[tar->neighbors[j]->type].similar_type == R_OCEAN) continue; - } - //otherwise form river - tar->hexside[j]->type = H_RIVER; - //then we treat the river segment(s) - } else { - //we are now on the first or later edge of the first river segment - if(first) { - first = 0; - tar->hexside[j]->type = H_DUMMY; -// tar->hexside[j]->bridge = 0; - } else { - //if not first, break if there is an inflow - but make sure on a river. - if(inflows[(i-1)%6]) { - tar->hexside[(i%6)]->type = H_RIVER; - break; - } - else { - tar->hexside[j]->type = H_DUMMY; -// tar->hexside[j]->bridge = 0; - } - } - } - } - - } - - - } - - AString temp = "Casts Diversion on "; - temp += tar->ShortPrint(®ions); - u->Event(temp); - SpecialError(tar, AString("Rivers in ") + tar->ShortPrint(®ions) + " change their course.", u->faction); - tar->Event("Local rivers were diverted from their courses last month."); - return 1; -} - -int Game::RunSummonCreatures(ARegion *r, Unit *u, int skill, int item, int max) -//if no max, set max to -1. -{ - CastIntOrder *order = (CastIntOrder *) u->activecastorder; - - int level = u->GetSkill(skill); //wolf, imp, demon, undead (eagles handled in bird lore) - int currentnum = u->items.GetNum(item); - - if(item == I_WOLF && TerrainDefs[r->type].similar_type != R_MOUNTAIN && - TerrainDefs[r->type].similar_type != R_FOREST) { - u->Error("CAST: Can only summon wolves in mountain and " - "forest regions.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(skill,order->extracost); //cost of 10 creatures ! - int num = (10*u->energy) / cost; - if(num < 1) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - if(max > 0 && (num + currentnum) > max*level*level ) num = max*level*level - currentnum; - if(num < 1) { - u->Error("CAST: Already have the maximum number of that creature.", order->quiet); - return 0; - } - if(order->target > 0 && order->target < num) num = order->target; - - cost = u->GetCastCost(skill,order->extracost,num); //this gives 10*cost - cost = (cost+9)/10; - u->energy -= cost; - - int experience = num/2+cost; - if(experience > 20) experience = 20; - u->Experience(skill,experience); - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int newitem; - switch(mevent) { - case 4: - if(currentnum>0) { - u->Error(AString("Attempts to summon ") + ItemDefs[item].names + ", but all of those creatures magically disappear.", order->quiet); - u->items.SetNum(item,0); - return 1; - } - //fall thru - case 3: - if(item == I_DEMON) newitem = I_IMP; - else if(item == I_UNDEAD) newitem = I_SKELETON; - else break; - u->Error(AString("Attempts to summon ") + ItemDefs[item].names + ", but something goes wrong and " + ItemDefs[newitem].names + " appear instead.", order->quiet); - item = newitem; - currentnum = u->items.GetNum(item); - break; - case 2: - case 1: - u->Error(AString("Attempts to cast ") + SkillDefs[skill].name + ", but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - u->items.SetNum(item,currentnum + num); - u->Event(AString("Summons ") + num + " " + ItemDefs[item].names); - - return 1; -} - -int Game::RunSummonHigherCreature(ARegion *r, Unit *u, int skill, int item) -//Arcadia code for summoning balrogs, gryffins, liches -{ - CastOrder *order = (CastOrder *) u->activecastorder; - - int level = u->GetSkill(skill); //balrog, lich, S_GRYFFIN_LORE - int maxnum = (level+1)/2; - - int num = u->items.GetNum(item); - if(item == I_LICH) num = 0; //special case, no limit for liches - if (num >= maxnum) { - u->Error(AString("Mage may not control more ") + ItemDefs[item].names + ".", order->quiet); - return 0; - } - - int cost = u->GetCastCost(skill,order->extracost, 1, 2*num); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - - if(!cost) { - //free spell to cast; eg gryffin lore in Arc IV. Let's make a 10% summon chance per level, since it's free. - u->Experience(skill,5); - if(getrandom(100) >= 10*(level - 2*num)) { - u->Event("Attempts to summon a gryffin, but fails."); - return 1; - } - } else { - u->energy -= cost; - u->Experience(skill,24); //this skill would usually only be cast 3 times, and is energy intensive. - } - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int newitem; - - switch(mevent) { - case 4: - if(num>0) { - u->Error(AString("Attempts to summon a ") + ItemDefs[item].name + ", but all of those creatures magically disappear.", order->quiet); - u->items.SetNum(item,0); - return 1; - } - //fall thru - case 3: - if(item == I_BALROG) newitem = I_DEMON; - else if(item == I_GRYFFIN) newitem = I_EAGLE; - else if(item == I_LICH) newitem = I_UNDEAD; - u->Error(AString("Attempts to summon a ") + ItemDefs[item].name + ", but something goes wrong and a " + ItemDefs[newitem].name + " appears instead.", order->quiet); - item = newitem; - num = u->items.GetNum(item); - break; - case 2: - case 1: - u->Error(AString("Attempts to cast ") + SkillDefs[skill].name + ", but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - u->items.SetNum(item,u->items.GetNum(item) + 1); //can't use (num+1) because of lich special case. - u->Event(AString("Summons a ") + ItemDefs[item].name); - - return 1; -} - - -int Game::RunFog(ARegion *r, Unit *u) -// Arcadia spell -{ - CastIntOrder *order = (CastIntOrder *)u->activecastorder; - -/* Fog must follow the mage around, so must be a property of the mage, -not of the region - at least until after the sail and move phases. */ - int large = 0; - if(order->level > 1) large = 1; - int dir = order->target; - - int skill = u->GetSkill(S_FOG); - if(large && skill < 4) { - u->Error("CAST: Not high enough skill level to cast large fog", order->quiet); - return 0; - } - - int marker = 1; //marks unit as foggy - if(dir < -1) dir = -1; - if(large) marker += 2 + dir; //if marker > 1, then large. If marker == 2, then centred on mage, else on direction 'marker-3' - - int cost = u->GetCastCost(S_FOG,order->extracost); // cost of normal sized fog - if(large) cost = u->GetCastCost(S_FOG,order->extracost,4); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - if(large) u->Experience(S_FOG,16); - else u->Experience(S_FOG,10); - - Unit *tar = u; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int numunits = 0; - - switch(mevent) { - case 4: - u->Error("Attempts to cast fog, but the spell backfires, " - "clearing the region of all bad weather and making the mage a local hero.", order->quiet); - if(r->clearskies == 0) r->clearskies = 1; - return 1; - case 3: - forlist(&r->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *unit = (Unit *) elem; - if(unit != u) { - if(getrandom(++numunits)) tar = unit; - } - } - } - if(tar == u) break; - u->Error(AString("Attempts to cast fog, but the spell follows ") - + *(tar->name) + " instead.", order->quiet); - break; - case 2: - case 1: - u->Error("Attempts to cast fog, but the spell fizzles.", order->quiet); - return 1; - default: - break; - } - #endif - - - tar->foggy = marker; - - return 1; -} - -int Game::RunSummonMen(ARegion *r, Unit *u) -// Arcadia spell -{ - int level = u->GetSkill(S_SUMMON_MEN); - CastMenOrder *order = (CastMenOrder *)u->activecastorder; - -//checks: race must be a man and not a leader: - if(!(ItemDefs[order->race].type & IT_MAN) || (ItemDefs[order->race].flags & ItemType::DISABLED)) { - u->Error(AString("CAST: Incorrect race"), order->quiet); - return 0; - } - if(ItemDefs[order->race].type & IT_LEADER) { - u->Error(AString("CAST: Cannot summon leaders"), order->quiet); - return 0; - } - -// work out cost of men - int cost = ItemDefs[order->race].baseprice; //This is usually $50. - int amt = u->GetSharedNum(I_SILVER); - - if(amt < cost) { - u->Error(AString("CAST: Doesn't have sufficient silver to summon that."), order->quiet); - return 0; - } - - int num = amt/cost; - if (num > order->men) num = order->men; - if (num > 10*level*level) num = 10*level*level; - - int energycost = u->GetCastCost(S_SUMMON_MEN,order->extracost); //cost per 10 men. - if( (num * energycost) / 10 > u->energy) num = (u->energy * 10) / energycost; - - if(!num) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - - Unit *tar = r->GetUnitId((UnitId *) order->units.First(),u->faction->num); - if (!tar) { - u->Error("CAST: Invalid unit number.", order->quiet); - return 0; - } - if (tar->faction != u->faction) { - u->Error("CAST: Target unit is not from your faction.", order->quiet); - return 0; - } - if(tar->type != U_NORMAL) { - u->Error("CAST: Can only summon men into normal units.", order->quiet); - return 0; - } - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - //cases 4&3: - //case 2: change to a different race - int i = 0; - int numraces = 0; - int race = -1; - - switch(mevent) { - case 4: - u->Error("Attempts to cast summon men, but he summons women instead. The lure of temptation is too great, and the mage ends the month exhausted.", order->quiet); - u->energy = 0; - u->Experience(S_SUMMON_MEN,10); - return 1; - case 3: - case 2: - for(i=0; irace) continue; - if(!getrandom(++numraces)) race = i; - } - if(race == -1) break; - u->Error("Attempts to cast summon men, but the spell backfires, summoning the wrong race.", order->quiet); - order->race = race; - break; - case 1: - u->Error("Attempts to cast summon men, but the spell fizzles, producing only a frog.", order->quiet); - u->Experience(S_SUMMON_MEN,10); - u->energy -= cost; - if(u->energy < 0) u->energy = 0; - return 1; - default: - break; - } - #endif - - - u->ConsumeShared(I_SILVER, num*cost); - tar->items.SetNum(order->race,tar->items.GetNum(order->race) + num); - - u->Event(AString("Summons ") + num + " " + ItemDefs[order->race].names - + " into " + *tar->name + "."); - - u->energy -= (num * energycost) / 10; - if((num * energycost)%10) u->energy -= 1; - - int experience = (2 * num) / level; - if(experience > 10) experience = 10; - - u->Experience(S_SUMMON_MEN,experience); - - return 1; -} - -int Game::RunTransmutation(ARegion *r, Unit *u) -// Arcadia spell -{ - int level = u->GetSkill(S_TRANSMUTATION); - CastChangeOrder *order = (CastChangeOrder *) u->activecastorder; - int fromitem = order->fromitem; - int toitem = order->toitem; - if(level<5 && fromitem<0) { - u->Error("CAST: Must specify item to transmute.", order->quiet); - return 0; - } - if(!IsPrimary(toitem)) { - if(level<2) { - u->Error("CAST: To item is not a primary item.", order->quiet); - return 0; - } - if(IsPrimary(fromitem)) { - u->Error("CAST: Cannot transmute a primary item into a manufactured item.", order->quiet); - return 0; - } - } - - if( (fromitem >= 0) && ItemDefs[toitem].baseprice >= 2*ItemDefs[fromitem].baseprice) { - u->Error("CAST: To item is too valuable to be transmuted from that.", order->quiet); - return 0; - } - - int ratio = 1; - if(!(ItemDefs[toitem].type & IT_NORMAL) ) { - if(level<5) { - u->Error("CAST: Can only create normal items.", order->quiet); - return 0; - } - if(toitem == I_MITHRIL && !(ItemDefs[I_IRON].flags & ItemType::DISABLED)) - fromitem = I_IRON; - else if(toitem == I_IRONWOOD && !(ItemDefs[I_WOOD].flags & ItemType::DISABLED)) - fromitem = I_WOOD; - else if(toitem == I_YEW && !(ItemDefs[I_WOOD].flags & ItemType::DISABLED)) - fromitem = I_WOOD; - else if(toitem == I_PEARL && !(ItemDefs[I_FISH].flags & ItemType::DISABLED)) - fromitem = I_FISH; - else if(toitem == I_ROOTSTONE && !(ItemDefs[I_STONE].flags & ItemType::DISABLED)) - fromitem = I_STONE; - else if(toitem == I_MUSHROOM && !(ItemDefs[I_HERBS].flags & ItemType::DISABLED)) - fromitem = I_HERBS; - else if(toitem == I_FLOATER && !(ItemDefs[I_FUR].flags & ItemType::DISABLED)) - fromitem = I_FUR; - else if(toitem == I_WHORSE && !(ItemDefs[I_HORSE].flags & ItemType::DISABLED)) - fromitem = I_HORSE; - else { - u->Error("CAST: Cannot create that item.", order->quiet); - return 0; - } - ratio = 2; - } - - if(fromitem<0) { - u->Error("CAST: Must specify item to transmute.", order->quiet); - return 0; - } - -/* if(!(SkillDefs[S_TRANSFIGURE].flags & SkillType::DISABLED)) { //only have this limit if transfigure is also in play - if(toitem == I_LIVESTOCK || toitem == I_HORSE || toitem == I_CAMEL || - fromitem == I_LIVESTOCK || fromitem == I_HORSE || - fromitem == I_CAMEL || fromitem == I_WHORSE) { - u->Error("CAST: Cannot transmute living items."); - return 0; - }*/ - - - if(ItemDefs[toitem].type & IT_MAN || ItemDefs[fromitem].type & IT_MAN ) { - u->Error("CAST: Cannot transmute men.", order->quiet); - return 0; - } - - if(ItemDefs[toitem].type & IT_MONSTER || ItemDefs[fromitem].type & IT_MONSTER ) { - u->Error("CAST: Cannot transmute creatures.", order->quiet); - return 0; - } - - if(toitem == I_PLATEARMOR) { - //should generalise this to anything needing more than 1 input to make. - u->Error("CAST: Cannot transmute into items which require more than one input to manufacture.", order->quiet); - return 0; - } - - int num = u->GetSharedNum(fromitem); - if(!num) { - u->Error("CAST: Not enough of that item to transmute.", order->quiet); - return 0; - } - if(num > 4*level*level) num = 4*level*level; // max items to transmute - num /= ratio; // advanced items produce half as many. - - int cost = u->GetCastCost(S_TRANSMUTATION,order->extracost, ratio*ratio); // cost of 8 items transmuted - // ratio: advanced resources cost 4 times more energy! - // but only 3 times more resources! - if(ratio == 2) ratio = 3; - - if(u->energy < 0) u->energy = 0; //status check to prevent silly negatives. - if(num > (8 * u->energy) / cost) num = (8 * u->energy) / cost; - if(!num) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - -// int i = 0; -// int numitems = 0; -// int item = -1; - int nooutput = 0; - int noinput = 0; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - //cases 4&3: - //case 2: change to a different resource - - switch(mevent) { - case 4: - noinput = 1; - u->Error("Transmutation spell produces resources from nothing!", order->quiet); - break; - case 3: - nooutput = 1; - u->Error("Attempts to cast transmutation, but it fizzles, and the resources vanish. ", order->quiet); - break; - case 2: - for(i=0; iError("Attempts to cast transmutation, but the spell backfires, producing the wrong output.", order->quiet); - toitem = item; - break; - case 1: - u->Error("Attempts to cast transmutation, but the spell fizzles, and the mage's hat disappears.", order->quiet); - if(u->describe) *u->describe = AString("Hatless. ") + *u->describe; // crossing my fingers this will not overwrite data. - else u->describe = new AString("Hatless"); - u->Experience(S_TRANSMUTATION,8); - u->energy -= cost; - if(u->energy < 0) u->energy = 0; - return 1; - default: - break; - } - #endif - - u->energy -= (num * cost) / 8; - if((num*cost)%8) u->energy -= 1; //cost gets rounded up. - if(u->energy < 0) u->energy = 0; - - if(!noinput) u->ConsumeShared(fromitem, num*ratio); - if(!nooutput) u->items.SetNum(toitem,u->items.GetNum(toitem) + num); - - if(!noinput && !nooutput) u->Event(AString("Transmutes ") + num*ratio + " " + ItemDefs[fromitem].names - + " to " + num + " " + ItemDefs[toitem].names); //should rewrite this using the itemstring function. - - int experience = (ratio * num * 20) / (4*level*level); - if(experience>10) experience = 10; - u->Experience(S_TRANSMUTATION, experience); - - return 1; -} - -int Game::RunModification(ARegion *r, Unit *u) -{ - int level = u->GetSkill(S_MODIFICATION); - CastModifyOrder *order = (CastModifyOrder *) u->activecastorder; - int fromitem = order->fromitem; - int toitem = order->toitem; - - ARegion *tar; - int val; - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_MODIFICATION, order->quiet, 0); - if(!val) return 0; - - int increase = 1; - if(order->level == 3) increase = 0; - // increase = 1 to go up, 0 to decrease - - if(!increase && level<3) { - u->Error("CAST: Not high enough level to decrease resources.", order->quiet); - return 0; - } - - // check the level is high enough to do what is needed - int advanced = 0; - if(!(ItemDefs[toitem].type & IT_NORMAL)) { - if(increase) { - if(level<4) { - u->Error("CAST: Not high enough level to increase advanced resources.", order->quiet); - return 0; - } - } else { //ie if decreasing - if(level<5) { - u->Error("CAST: Not high enough level to decrease advanced resources.", order->quiet); - return 0; - } - } - advanced = 1; - } - - if(!(ItemDefs[fromitem].type & IT_NORMAL)) { - if(level<5) { - u->Error("CAST: Not high enough level to modify advanced resources.", order->quiet); - return 0; - } - advanced = 1; - } - - if(advanced) level -= 2; - - if(toitem == I_SILVER || fromitem == I_SILVER) { - u->Error("CAST: Cannot modify wages.", order->quiet); - return 0; - } - - if(toitem == fromitem) { - u->Error("CAST: Item increasing and item decreasing are the same.", order->quiet); - return 0; - } - - //check the region has the resources! - Production *toprod = 0; - Production *fromprod = 0; - - forlist(&tar->products) { - Production *p = (Production *) elem; - if(p->itemtype == toitem) toprod = p; - if(p->itemtype == fromitem) fromprod = p; - } - - if(!toprod || !fromprod) { - u->Error("CAST: Product not present in region.", order->quiet); - return 0; - } - - int toamount = 0; - int fromamount = 0; - for(unsigned int i=0; i<(sizeof(TerrainDefs[tar->type].prods)/sizeof(Product)); i++) { - if(TerrainDefs[tar->type].prods[i].product == toitem) toamount = TerrainDefs[tar->type].prods[i].amount; - if(TerrainDefs[tar->type].prods[i].product == fromitem) fromamount = TerrainDefs[tar->type].prods[i].amount; - } - //food items (livestock, grain, fish) may be present in the region but not listed in the terrain table. Set them from - //the economy table. - if(!toamount && (ItemDefs[toitem].type & IT_FOOD) ) toamount = TerrainDefs[tar->type].economy; - if(!fromamount && (ItemDefs[fromitem].type & IT_FOOD) ) fromamount = TerrainDefs[tar->type].economy; - - if(!toamount || !fromamount) { - //This should never occur. - u->Error("CAST: Product does not naturally occur in target region type.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_MODIFICATION,order->extracost); //cost per resource changed up/down. - if(advanced) cost = u->GetCastCost(S_MODIFICATION,order->extracost,4); //4 times cost. - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - //cases 4&3: add or remove one of the mentioned resource - //case 2: change a different resource - switch(mevent) { - case 4: - case 3: - case 2: - case 1: - u->Error("Attempts to cast modification, but the spell fizzles.", order->quiet); - u->Experience(S_MODIFICATION,10); - u->energy -= 4*cost; - if(u->energy < 0) u->energy = 0; - return 1; - default: - break; - } - #endif - - int change; - int decrease; - - if(increase) { - change = toamount + toamount * level / 2 - toprod->baseamount; - if(change > level * 6) change = level*6; - if(change <= 0) { - u->Error("CAST: Mage is not skilled enough to increase the quantity of that resource", order->quiet); - return 0; - } - if(change*cost > u->energy) change = u->energy / cost; - - decrease = (change * 5 + level + 1 ) / (level + 4); //ie change*5/(l+4) rounded up - if(decrease >= fromprod->baseamount) { - decrease = fromprod->baseamount - 1; - change = decrease*(level+2) / 3; - } - u->energy -= change * cost; - toprod->amount += change; - toprod->baseamount += change; - fromprod->amount -= decrease; - fromprod->baseamount -= decrease; - - u->Event(AString("Casts modification on ") + tar->ShortPrint(®ions) + " increasing the amount of " + ItemDefs[toitem].name + " by " + change); - SpecialError(tar, AString("Resources present in ") + tar->ShortPrint(®ions) + " are magically altered.", u->faction); - } - else { - decrease = toprod->baseamount - 1; - if(decrease > level * 6) decrease = level*6; - if(decrease*cost > u->energy) decrease = u->energy / cost; - - change = (decrease * 3) / level; //ie decrease*3/(l) rounded up - if(change + fromprod->baseamount > fromamount + fromamount * level / 2) { - change = fromamount + fromamount * level / 2 - fromprod->baseamount; - decrease = change * level / 3; - } - u->energy -= decrease * cost; - toprod->amount -= decrease; - toprod->baseamount -= decrease; - fromprod->amount += change; - fromprod->baseamount += change; - - u->Event(AString("Casts modification on ") + tar->ShortPrint(®ions) + " decreasing the amount of " + ItemDefs[toitem].name + " by " + decrease); - SpecialError(tar, AString("Resources present in ") + tar->ShortPrint(®ions) + " are magically altered.", u->faction); - } - - //max 10 experience, but you have to change at least 50% of max capable of to get it. - int experience = 60; - if(increase) experience *= change; - else experience *= decrease; - experience /= level * 6; - if(experience > 30) experience = 30; - if(!advanced) experience /= 3; - u->Experience(S_MODIFICATION,experience); - - return 1; -} - -int Game::RunRejuvenation(ARegion *r, Unit *u) -{ -//this had better be a surface only spell, or wierd things will happen! - - int level = u->GetSkill(S_REJUVENATION); - CastModifyOrder *order = (CastModifyOrder *) u->activecastorder; - int regtype = order->toitem; - - ARegion *tar; - int val; - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_REJUVENATION, order->quiet, 0); - if(!val) return 0; - - if(TerrainDefs[regtype].similar_type == TerrainDefs[tar->type].similar_type) { - u->Error("CAST: Region is already of that type.", order->quiet); - return 0; - } - - if(TerrainDefs[tar->type].similar_type == R_OCEAN && level < 3) { - u->Error("CAST: Not high enough level to rejuvenate oceans or lakes.", order->quiet); - return 0; - } - - if(TerrainDefs[regtype].similar_type == R_OCEAN && level < 5) { - u->Error("CAST: Not high enough level to create oceans or lakes.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_REJUVENATION,order->extracost); - if(TerrainDefs[regtype].similar_type == R_OCEAN) cost = u->GetCastCost(S_REJUVENATION,order->extracost, 3, 4); - else if(TerrainDefs[tar->type].similar_type == R_OCEAN) cost = u->GetCastCost(S_REJUVENATION,order->extracost, 2, 2); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - int large = 0; - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - int tries = 0; - //case 4: reflects to random type, large - //case 3: hits random location - //case 2: reflects to random type - //case 1: fizzles - switch(mevent) { - case 4: - u->Error("Attempts to cast rejuvenation, but the spell backfires, rejuvenating nearby regions.", order->quiet); - large = 1; - tar = r; - do { - regtype = getrandom(R_CAVERN); - } while((TerrainDefs[regtype].similar_type == TerrainDefs[tar->type].similar_type) && tries++ < 20); - //get experience normally, plus some additional compensation! - u->Experience(S_REJUVENATION,20); - break; - case 3: - xx = getrandom(regions.GetRegionArray(1)->x); - do { - yy = getrandom(regions.GetRegionArray(1)->y); - } while ( (xx+yy)%2 ); - tar = regions.GetRegion(xx,yy,1); - if(!tar) { - u->Error("Attempts to cast rejuvenation, but the spell fizzles.", order->quiet); - u->Experience(S_REJUVENATION,10); - return 1; - } - u->Error(AString("Attempts to cast rejuvenation, but the spell is misaimed, rejuvenating ") + tar->ShortPrint(®ions), order->quiet); - //get experience normally! - break; - case 2: - u->Error("Attempts to cast rejuvenation, but the spell backfires, rejuvenating the local region.", order->quiet); - tar = r; - do { - regtype = getrandom(R_CAVERN); - } while((TerrainDefs[regtype].similar_type == TerrainDefs[tar->type].similar_type) && tries++ < 20); - //get experience normally! - break; - case 1: - u->Error("Attempts to cast rejuvenation, but the spell fizzles.", order->quiet); - u->Experience(S_REJUVENATION,10); - return 1; - default: - break; - } - #endif - - -// if creating oceans or lakes, set tosink and quit - if(TerrainDefs[regtype].similar_type == R_OCEAN) { - u->Experience(S_REJUVENATION, 30); - if(tar->willsink != 1) { - tar->willsink = 2; - u->Event(AString("Casts rejuvenation. ") + tar->ShortPrint(®ions) + " will sink below the waves next month."); - } else { - u->Event(AString("Casts rejuvenation. ") + tar->ShortPrint(®ions) + " has will sink below the waves."); - } - - if(large) - for(int i=0; i<6; i++) { - ARegion *tar2 = tar->neighbors[i]; - if(!tar2) continue; - if(tar2->willsink != 1) tar2->willsink = 2; //poor sod who cast this and gets his seven region sunk! Maybe check if mage is on ship in ocean ... and do something equally horrible - } - - return 1; - } - - int redopop = 0; - -// if converting from ocean to land, adjust beaches and ships - if(TerrainDefs[tar->type].similar_type == R_OCEAN) { - tar->OceanToLand(); - u->Experience(S_REJUVENATION, 20); - redopop = 1; - } else u->Experience(S_REJUVENATION, 10); - - SpecialError(tar, tar->ShortPrint(®ions) + " is magically changed to " + TerrainDefs[regtype].name + ".", u->faction); - tar->Event(AString("Is magically changed from ") + TerrainDefs[tar->type].name); - tar->type = regtype; - u->Event(AString("Casts rejuvenation on ") + tar->ShortPrint(®ions)); - - if(!redopop) { - forlist((&tar->products)) { - Production * p = ((Production *) elem); - if(p->itemtype != I_SILVER) { - tar->products.Remove(p); - delete p; - } - } - tar->SetupProds(); - - //this assumes NOT using the new economy system. - int oldwages = tar->maxwages; - int mw = TerrainDefs[regtype].wages; - if(Globals->RANDOM_ECONOMY) mw += getrandom(3); - tar->maxwages = mw; - tar->wages += mw - oldwages; - tar->UpdateEditRegion(); - } else { - //redo the economy - if(tar->town) delete tar->town; - tar->town = NULL; - - tar->products.DeleteAll(); - tar->SetupProds(); - - tar->markets.DeleteAll(); - - tar->SetupEditRegion(0); - tar->UpdateEditRegion(); - } - // region event! - if(!large) return 1; - - for(int i=0; i<6; i++) { - ARegion *tar2 = tar->neighbors[i]; - if(!tar2) continue; - - if(TerrainDefs[tar2->type].similar_type == R_OCEAN) { - //redo the economy - tar2->OceanToLand(); - SpecialError(tar2, tar2->ShortPrint(®ions) + " is magically changed to " + TerrainDefs[regtype].name + "."); - tar2->Event(AString("Is magically changed from ") + TerrainDefs[tar->type].name); - tar2->type = regtype; - if(tar2->town) delete tar->town; - tar2->town = NULL; - - tar2->products.DeleteAll(); - tar2->SetupProds(); - - tar2->markets.DeleteAll(); - - tar2->SetupEditRegion(0); - tar2->UpdateEditRegion(); - - - } else { - tar2->type = regtype; - forlist((&tar2->products)) { - Production * p = ((Production *) elem); - if(p->itemtype != I_SILVER) { - tar2->products.Remove(p); - delete p; - } - } - tar2->SetupProds(); - - //this assumes NOT using the new economy system. - int oldwages = tar2->maxwages; - int mw = TerrainDefs[regtype].wages; - if(Globals->RANDOM_ECONOMY) mw += getrandom(3); - tar2->maxwages = mw; - tar2->wages += mw - oldwages; - tar2->UpdateEditRegion(); - } - } - return 1; -} - -int Game::RunSpiritOfDead(ARegion *r, Unit *u) -{ - int level = u->GetSkill(S_SPIRIT_OF_DEAD); - CastUnitsOrder *order = (CastUnitsOrder *) u->activecastorder; - - Unit *tar; - if(order->units.First()) { - tar = r->GetUnitId((UnitId *) order->units.First(),u->faction->num); - if (!tar) { - u->Error("CAST: Cannot find that unit.", order->quiet); - return 0; - } - } else { - // list shades in the region. - int cost = (u->GetCastCost(S_SPIRIT_OF_DEAD,order->extracost)+4)/5; - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - - #ifdef FIZZLES - if(u->MysticEvent()) { - u->Error("Attempts to search for shades, but the spell fizzles.", order->quiet); - u->Experience(S_SPIRIT_OF_DEAD,2); - return 0; - } - #endif - u->Event("The following shades are present in this region:"); - int shades = 0; - forlist(&r->objects) { - Object *obj = (Object *) elem; - forlist(&obj->units) { - Unit *un = (Unit *) elem; - if(un->dead) { - shades++; - u->Event(*un->name); - } - } - } - if(!shades) u->Event("none."); - u->Experience(S_SPIRIT_OF_DEAD,10); - return 1; - } - // we have a target. Make sure it satisfies all conditions - if(!tar->dead) { - u->Error("CAST: That unit is not dead.", order->quiet); - return 0; - } - - if(!tar->faction->num == ghostfaction) { - u->Error("CAST: That unit appears to be dead, but not a ghost. Please contact your GM.", 0); - return 1; - } - - if(!tar->type == U_MAGE) { - u->Error("CAST: That unit appears to be dead, but not a mage. Please contact your GM.", 0); - return 1; - } - - if((tar->dead != 1) && (tar->dead != u->faction->num)) { - //This mage is loyal to another faction. - u->Error("CAST: That mage is still loyal to another.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_SPIRIT_OF_DEAD,order->extracost); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - u->energy -= cost; - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - Faction *gf = 0; - - switch(mevent) { - case 4: - u->Error("Attempts to summon a spirit of the dead, but the spell backfires, sucking the mage " - "into the spirit world.", order->quiet); - u->MoveUnit(r->GetDummy()); - u->dead = u->faction->num; - gf = GetFaction(&factions, ghostfaction); - if(!gf) { - u->MoveUnit(0); - r->hell.Add(u); - return 0; - } - u->faction = gf; - u->Experience(S_SPIRIT_OF_DEAD,180); - return 0; - case 3: //could give spirit mage to another faction - have to find another faction & check for too many mages. - case 2: - u->Error("Attempts to summon a spirit of the dead, but the spell backfires, sucking the mage's " - "energy into the spirit world.", order->quiet); - u->energy = 0; - u->Experience(S_SPIRIT_OF_DEAD,10); - return 1; - case 1: - u->Error("Attempts to summon a spirit of the dead, but the spell fizzles. The mage spends the month hearing tortured whispers in his head.", order->quiet); - u->Experience(S_SPIRIT_OF_DEAD,10); - return 1; - default: - break; - } - #endif - - if(getrandom(6) >= level) { - u->Event(AString("Summons the spirit of ") + *tar->name + " who refuses to join your faction."); - u->Experience(S_SPIRIT_OF_DEAD,20); - return 1; - } - - if(Globals->FACTION_LIMIT_TYPE != GameDefs::FACLIM_UNLIMITED) { - if (CountMages(u->faction) >= AllowedMages(u->faction)) { - u->Error("CAST: Faction has too many mages.", order->quiet); - u->Event(AString("Summons the spirit of ") + *tar->name + " who is unable to join your faction due to lack of magic faction points."); - u->Experience(S_SPIRIT_OF_DEAD,20); - return 1; - } - } - - tar->resurrects++; - tar->faction = u->faction; - tar->energy = tar->MaxEnergy()/5; - tar->dead = 0; - - u->Event(AString("Summons the spirit of ") + *tar->name + " who joins your faction."); - u->Experience(S_SPIRIT_OF_DEAD,40); - return 1; -} - -int Game::RunHypnosis(ARegion *r, Unit *u) -{ - int level = u->GetSkill(S_HYPNOSIS); - CastHypnosisOrder *order = (CastHypnosisOrder *) u->activecastorder; - - if(level < order->level) { - u->Error("CAST: Insufficient level for that month order.", order->quiet); - return 0; - } - - if(!u->energy) { - u->Error("CAST: Insufficient energy to cast that spell.", order->quiet); - return 0; - } - - int cost = u->GetCastCost(S_HYPNOSIS,order->extracost); //this is the cost to hypnotise 10*level men. - int max = u->energy * 10 * level / cost; - - int max2 = level * level * 10; - if (max2 < max) max = max2; - - //mystic events: - //1: fizzle 40% - //2: work 30% - //3: hypnotise self 20% - //4: they attack you 10% ?? - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - ProduceOrder *p = 0; - - switch(mevent) { - case 4: - case 3: - u->Error("Attempts to hypnotise, but the spell is reflected onto himself.", order->quiet); - delete u->monthorders; - u->monthorders = order->monthorder; - u->taxing = order->taxing; - order->monthorder = 0; - u->energy -= 1; - u->Experience(S_HYPNOSIS, 20); - return 1; - case 2: - u->Error("Attempts to hypnotise, but cannot convince them to do more than work.", order->quiet); - delete order->monthorder; - p = new ProduceOrder; - p->skill = -1; - p->item = I_SILVER; - order->monthorder = p; - break; - case 1: - u->Error("Attempts to hypnotise, but the spell fizzles.", order->quiet); - u->energy -= cost; - if(u->energy < 0) u->energy = 0; - u->Experience(S_HYPNOSIS,10); - return 1; - default: - break; - } - #endif - - int num = 0; - int mageerror = 0; - int numberserror = 0; - int emptyerror = 0; - forlist (&(order->units)) { -//cout << "Move is: " << O_MOVE << "Hypno is: " << order->monthorder->type << endl; - - Unit *tar = r->GetUnitId((UnitId *) elem,u->faction->num); - if (!tar) continue; - if (tar->faction != u->faction) { - if (!tar->IsMage()) { - if (tar->GetMen()) { - if( (num + tar->GetMen()) <= max) { - num += tar->GetMen(); - delete tar->monthorders; - tar->monthorders = 0; - - tar->taxing = order->taxing; - - if(order->monthorder) { - //not using a switch as have to initialise orders in here - else becomes a nightmare :(. - if(order->monthorder->type == O_PRODUCE) { - //this includes "WORK" orders - ProduceOrder *p = new ProduceOrder; - p->item = ((ProduceOrder *) order->monthorder)->item; - p->skill = ((ProduceOrder *) order->monthorder)->skill; - tar->monthorders = p; - } else if(order->monthorder->type == O_SAIL) { - SailOrder *m = new SailOrder; - forlist(&((SailOrder *) order->monthorder)->dirs) { - MoveDir *old = (MoveDir *) elem; - MoveDir *toadd = new MoveDir; - toadd->dir = old->dir; - m->dirs.Add(toadd); - } - tar->monthorders = m; - } else if(order->monthorder->type == O_MOVE || order->monthorder->type == O_ADVANCE) { - MoveOrder *m = new MoveOrder; - m->advancing = ((MoveOrder *) order->monthorder)->advancing; - m->type = ((MoveOrder *) order->monthorder)->type; - //cout << "Directions "; - forlist(&((MoveOrder *) order->monthorder)->dirs) { - //cout << "in list "; - MoveDir *old = (MoveDir *) elem; - MoveDir *toadd = new MoveDir; - //cout << old->dir << " "; - toadd->dir = old->dir; - m->dirs.Add(toadd); - } - //cout << endl; - tar->monthorders = m; - } else if(order->monthorder->type == O_STUDY) { - StudyOrder *m = new StudyOrder; - m->skill = ((StudyOrder *) order->monthorder)->skill; - m->days = 0; - m->level = 0; - tar->monthorders = m; - } else { - u->Error("Something went wrong with the HYPNOSIS order. Please contact your GM."); - if(tar->taxing == TAX_NONE) { - ProduceOrder *p = new ProduceOrder; - p->item = I_SILVER; - p->skill = -1; - tar->monthorders = p; - u->Error("PS: Hypnosis defaulted to 'WORK'."); - } - } - } - - // tar->monthorders = order->monthorder; //this isn't going to work for unit #2! Need to clone it. - - tar->Event(AString("Is hypnotised by ") + *(u->name) + "."); - u->Event(AString("Hypnotises ") + *(tar->name) + "."); - } else numberserror = 1; - } else { - emptyerror = 1; - forlist(&tar->gavemento) { - UnitId *id = new UnitId; - id->unitnum = ((UnitId *) elem)->unitnum; - id->alias = 0; - id->faction = ((UnitId *) elem)->faction; - order->units.Add(id); - } - } - } else mageerror = 1; - } - } - - delete order->monthorder; - order->monthorder = 0; - - if(mageerror) { - u->Error("CAST: Can't hypnotise heroes.", order->quiet); - } - - if(numberserror) { - if(num) u->Error("CAST: Can't hypnotise that many men. Hypnotising as many as able.", order->quiet); - else { - if(!mageerror) u->Error("CAST: Can't hypnotise that many men.", order->quiet); - return 0; - } - } - if(emptyerror) { - u->Error("CAST: Trying to hypnotise an empty unit", order->quiet); - } - - - cost = cost * num / (10 * level); - if((cost*num)%(10*level)) cost++; //round up - u->energy -= cost; - - //max 20 experience because it's a rare spell to use, but have to hypnotise at least 67% of your max to get it. - int experience = 30 * num / max2; - if(experience > 20) experience = 20; - u->Experience(S_HYPNOSIS, experience); - - u->Event(AString("Hypnotises ") + num + " men."); - return 1; -} - -int Game::RunCreatePortal(ARegion *r, Unit *u) -{ - -// int level = u->GetSkill(S_CREATE_PORTAL); - CastRegionOrder *order = (CastRegionOrder *) u->activecastorder; - - if(TerrainDefs[r->type].similar_type == R_OCEAN) { - u->Error("CAST: Cannot create a portal in the ocean.", order->quiet); - return 0; - } - - RangeType *range = FindRange(SkillDefs[S_CREATE_PORTAL].range); - ARegion *tar; - int val; - - if(range != NULL) { - tar = regions.GetRegion(order->xloc, order->yloc, order->zloc); - val = GetRegionInRange(r, tar, u, S_CREATE_PORTAL, order->quiet, 0); - if(!val) return 0; - } else { - u->Error("CAST: Create Portal Range class does not exist. Contact your GM.", 0); - return 0; - } - - int cost = u->GetCastCost(S_CREATE_PORTAL,order->extracost); - if(cost > u->energy) { - u->Error("CAST: Not enough energy to cast that spell.", order->quiet); - return 0; - } - //energy subtracted at end. - - #ifdef FIZZLES - int mevent = u->MysticEvent(); - int xx; - int yy; - switch(mevent) { - case 4: - u->Error("Attempts to create a portal, but the spell backfires, sucking away the mage's energy.", order->quiet); - u->energy = 0; - u->Experience(S_CREATE_PORTAL,15); - return 1; - case 3: - if(tar != r) { - u->Error(AString("Attempts to create a linked portal, but the spell backfires, teleporting the mage to ") + tar->ShortPrint(®ions), order->quiet); - u->energy -= cost; - u->MoveUnit(tar->GetDummy()); - u->Experience(S_TELEPORTATION,10); - return 0; - } else { - u->energy -= cost; - xx = getrandom(regions.GetRegionArray(1)->x); - do { - yy = getrandom(regions.GetRegionArray(1)->y); - } while ( (xx+yy)%2 ); - tar = regions.GetRegion(xx,yy,1); - if(!tar) break; - u->Error(AString("Attempts to create a linked portal, but the spell backfires, teleporting the mage to ") + tar->ShortPrint(®ions), order->quiet); - u->MoveUnit(tar->GetDummy()); - u->Experience(S_TELEPORTATION,10); - return 0; - } - case 2: - case 1: - u->Error("Attempts to create a portal, but the spell fizzles.", order->quiet); - u->energy -= cost; - u->Experience(S_CREATE_PORTAL,10); - return 1; - default: - break; - } - #endif - - //create portal - Object *o = new Object(r); - o->num = r->buildingseq++; - o->type = O_ESEAPORTAL; - o->name = new AString(AString(ObjectDefs[o->type].name) + " [" + o->num + "]"); - o->incomplete = 0; - o->inner = -1; - o->mageowner = u->num; - r->objects.Add(o); - - AString temp; - temp = "Creates an unlinked portal."; - - if(tar != r) { - //link portal - int done = 0; - forlist(&tar->objects) { - Object *obj = (Object *) elem; - if(obj->type == O_ESEAPORTAL && obj->inner < 0 && obj->mageowner == u->num) { - done = 1; - //link - obj->inner = r->num; - o->inner = tar->num; - temp = AString("Links portals between ") + r->ShortPrint(®ions) + " and " + tar->ShortPrint(®ions); - } - } - if(!done) { - u->Error("CAST: No unlinked portal belongs to this mage in the target region.", order->quiet); - r->objects.Remove(o); - delete o; - r->buildingseq--; - return 0; - } - } - u->Experience(S_CREATE_PORTAL, 15); - u->energy -= cost; - u->Event(temp); - return 1; -} - -void Game::DoMerchantBuy(Unit *u, BuyOrder *o) -{ - int level = u->GetSkill(S_MERCHANTRY); - if(level < 4) { - u->Error("BUY: Insufficient Merchantry level to BUY", o->quiet); - return; - } - if((ItemDefs[o->item].type & IT_ADVANCED) && level < 6) { - u->Error("BUY: Insufficient Merchantry level to buy advanced items", o->quiet); - return; - } - - if(ItemDefs[o->item].type & IT_MAN || ItemDefs[o->item].type & IT_MONSTER || ItemDefs[o->item].type & IT_MAGIC || ItemDefs[o->item].type & IT_SPECIAL || ItemDefs[o->item].type & IT_TRADE || ItemDefs[o->item].type & IT_ILLUSION) { - u->Error(AString("BUY: Cannot merchant buy ") + ItemDefs[o->item].names, o->quiet); - return; - } - - if(!(ItemDefs[o->item].type & IT_NORMAL) && !(ItemDefs[o->item].type & IT_ADVANCED)) { - u->Error(AString("BUY: Item problem. Please alert your GM. Cannot merchant buy ") + ItemDefs[o->item].names, 0); - Awrite("Merchant BUY problem!"); - return; - } - - int cost = ItemDefs[o->item].baseprice * (17-level); - if(!(ItemDefs[o->item].type & IT_ADVANCED)) cost = (cost+3)/4; //rounded up! 3.25, 3, 2.75 times baseprice, or 130,120,110% of withdraw cost. - else cost = ItemDefs[o->item].baseprice * 4; - int silver = u->GetSharedMoney(); - if(o->num < 0 || o->num > silver/cost) o->num = silver/cost; - if(u->ConsumeSharedMoney(o->num*cost)) { - u->items.SetNum(o->item, u->items.GetNum(o->item) + o->num); - u->Event(AString("Buys ") + ItemString(o->item, o->num) - + " at $" + cost + " each."); - } - u->nummerchanted += o->num*cost; -} - -void Game::DoMerchantSell(Unit *u, SellOrder *o) -{ - int level = u->GetSkill(S_MERCHANTRY); - - if(ItemDefs[o->item].type & IT_MAN || ItemDefs[o->item].type & IT_MONSTER || ItemDefs[o->item].type & IT_SPECIAL || ItemDefs[o->item].type & IT_ILLUSION) { - u->Error(AString("SELL: Cannot merchant sell ") + ItemDefs[o->item].names, o->quiet); - } - - if(!(ItemDefs[o->item].type & IT_NORMAL) && !(ItemDefs[o->item].type & IT_ADVANCED) && !(ItemDefs[o->item].type & IT_MAGIC) && !(ItemDefs[o->item].type & IT_TRADE)) { - u->Error(AString("SELL: Item problem. Please alert your GM. Cannot merchant sell ") + ItemDefs[o->item].names, o->quiet); - Awrite("Merchant SELL problem!"); - return; - } - - int price = ItemDefs[o->item].baseprice * (6+level); - price /= 8; //rounded down! This is 7/8, 1, 9/8, 5/4, 11/8, 3/2 of bp, or 35, 40, 45, 50, 55, 60% of withdraw cost - if(o->num < 0) o->num = u->items.GetNum(o->item); - else if(!u->GetSharedNum(o->item,o->num)) o->num = u->GetSharedNum(o->item); - - if(u->ConsumeShared(o->item,o->num)) { - u->SetMoney(u->GetMoney() + o->num*price); - u->Event(AString("Sells ") + ItemString(o->item, o->num) - + " at $" + price + " each."); - } - u->nummerchanted += o->num*price*2; //double effect due to poor sell prices -} - - -/* -Todo: - -non urgent: -Hexside updates - walls? generalise to int array rather than bridge, road etc. -Square defence and fort combat? -renaming when terrain changes. -*/ diff --git a/arcadia/spells.h b/arcadia/spells.h deleted file mode 100644 index c071c541a..000000000 --- a/arcadia/spells.h +++ /dev/null @@ -1,117 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -#ifdef GAME_SPELLS -// -// If GAME_SPELLS is defined, this is being included from inside the Game -// class in game.h -// - -// -// Spell parsing - generic -// -void ProcessGenericSpell(Unit *, int, OrdersCheck *pCheck, int isquiet); -void ProcessRegionSpell(Unit *, AString *, int, OrdersCheck *pCheck, int isquiet); - -// -// Spell parsing - specific -// -void ProcessCastGateLore(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -void ProcessCastPortalLore(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -void ProcessPhanBeasts(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -void ProcessPhanUndead(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -void ProcessPhanDemons(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -void ProcessBirdLore(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -void ProcessMindReading(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); -//Arcadia -void ProcessSummonCreaturesSpell(Unit *, AString *, int spell, OrdersCheck *pCheck, int isquiet); //wolf, imp, demon, undead -void ProcessSummonMen(Unit *, AString *, OrdersCheck *pCheck, int isquiet); //SummonMen -void ProcessUnitsSpell(Unit *,AString *, int spell, OrdersCheck *pCheck, int isquiet ); //Invis, SummonSpirit -void ProcessChangeSpell(Unit *,AString *, int spell, OrdersCheck *pCheck, int isquiet ); //Transmutation -void ProcessModificationSpell(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); //Modification -void ProcessRejuvenationSpell(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); //Rejuvenation -void ProcessArtifactSpell(Unit *,AString *, int sk, OrdersCheck *pCheck, int isquiet ); //Artifact_Lore -void ProcessHypnosisSpell(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); // -void ProcessFogSpell(Unit *, AString *, OrdersCheck *pCheck, int isquiet ); //Fog -void ProcessPhanCreatures(Unit *,AString *, OrdersCheck *pCheck, int isquiet ); //Illusory Creatures - -// -// Spell helpers -// -int GetRegionInRange(ARegion *r, ARegion *tar, Unit *u, int spell, int quiet, int penalty = 0); - -// -// Spell running -// -int RunDetectGates(ARegion *,Object *,Unit *); //done skillshows, cost, experience, and 1/1 mevents. -int RunFarsight(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunGateJump(ARegion *,Object *,Unit *); //done skillshows, cost, experience, and 2/2 mevents. -int RunTeleport(ARegion *,Object *,Unit *); //done skillshows, cost, experience, and 2/2 mevents. -int RunPortalLore(ARegion *,Object *,Unit *); //disabled in ES -int RunEarthLore(ARegion *,Unit *); //done skillshows, cost, experience, and 1/1 mevents. -int RunWeatherLore(ARegion *, Unit *); //disabled in ES -int RunClearSkies(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunPhanBeasts(ARegion *,Unit *); //disabled in ES -int RunPhanUndead(ARegion *,Unit *); //disabled in ES -int RunPhanDemons(ARegion *,Unit *); //disabled in ES -int RunInvisibility(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunWolfLore(ARegion *,Unit *, int quiet); //disabled in ES (summoncreatures used instead) -int RunBirdLore(ARegion *,Unit *); //done skillshows, cost, experience, and 2/2,1/1,2/2 mevents. -int RunDragonLore(ARegion *,Unit *, int quiet); //disabled in ES -int RunSummonSkeletons(ARegion *,Unit *);//disabled in ES -int RunRaiseUndead(ARegion *,Unit *); //disabled in ES (summoncreatures used instead) -int RunSummonLich(ARegion *,Unit *); //disabled in ES (summoncreatures used instead) -int RunSummonImps(ARegion *,Unit *); //disabled in ES (summoncreatures used instead) -int RunSummonDemon(ARegion *,Unit *); //disabled in ES (summoncreatures used instead) -int RunSummonBalrog(ARegion *,Unit *, int quiet); //disabled in ES (summoncreatures used instead) -int RunCreateArtifact(ARegion *,Unit *,int,int); //done skillshows, cost, experience, and 1/1 mevents. -int RunEngraveRunes(ARegion *,Object *,Unit *, int quiet); //done skillshows, cost, experience, and 3/3 mevents. -int RunConstructGate(ARegion *,Unit *,int, int quiet); //done skillshows, cost, experience, and 2/2 mevents. -int RunEnchantSwords(ARegion *,Unit *); //done skillshows, cost, experience -int RunEnchantArmor(ARegion *,Unit *); //done skillshows, cost, experience -int RunMindReading(ARegion *,Unit *); -int RunCreateFood(ARegion *,Unit *); //disabled in ES -//Arcadia -int RunPhanCreatures(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunPhanEntertainment(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunBlizzard(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunSeaward(ARegion *,Unit *); //done skillshows, cost, experience, and 4/4 mevents. -int RunDiversion(ARegion *,Unit *); //done skillshows, cost, experience, and 1/1 mevents. Complicated 3-case code, but I don't think there's a simpler solution. -int RunSummonCreatures(ARegion *, Unit *, int spell, int item, int max); //wolves, imps, undead and demons. done skillshows, cost, experience, and 3/3 mevents. -int RunSummonHigherCreature(ARegion *, Unit *, int spell, int item); //balrogs, liches and gryffins. done skillshows, cost, experience, and 3/3 mevents. -int RunFog(ARegion *,Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunSummonMen(ARegion *,Unit *); //done skillshows, cost, experience, and 2/2 mevents. -int RunTransmutation(ARegion *,Unit *); //done skillshows, cost, experience, and 4/4 mevents. -int RunModification(ARegion *,Unit *); //done skillshows, cost, experience, and 1/3 mevents*. -int RunRejuvenation(ARegion *, Unit *); //done skillshows, cost, experience, and 4/4 mevents. -int RunSpiritOfDead(ARegion *, Unit *); //done skillshows, cost, experience, and 3/3 mevents. -int RunHypnosis(ARegion *, Unit *); //done skillshows, cost, experience, and 3/4 mevents*. -int RunCreatePortal(ARegion *, Unit *); //done skillshows, cost, experience, and 3/3 mevents. -void DoMerchantBuy(Unit *u, BuyOrder *o); -void DoMerchantSell(Unit *u, SellOrder *o); - - -//portal - -#endif diff --git a/arcadia/template.cpp b/arcadia/template.cpp deleted file mode 100644 index 3a639db69..000000000 --- a/arcadia/template.cpp +++ /dev/null @@ -1,593 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "game.h" -#include "gamedata.h" -#include -#ifdef WIN32 -#include -#endif -#include - -#define LINE_WIDTH 70 -#define MAP_WIDTH 23 -#define TMPL_MAP_WIDTH 20 -#define TMPL_MAP_OFS 1 -#define FILL_SIZE 6 -#define TEMPLATE_MAX_LINES 13 - -static void TrimWrite(Areport *f, char *buffer); - -static char *TemplateMap[] = { - //12345678901234567890 - " ____ ", // 1 - "nw / \\ ne", // 2 - " ____/ \\____ ", // 3 - " / \\ / \\ ", // 4 - "/ \\____/ \\", // 5 - "\\ / \\ /", // 6 - " \\____/ \\____/ ", // 7 - " / \\ / \\ ", // 8 - "/ \\____/ \\", // 9 - "\\ / \\ /", // 10 - " \\____/ \\____/ ", // 11 - " \\ / ", // 12 - "sw \\____/ se" // 13 -}; - -static int dircrd[] = { - // X Y - 8-1, 7-1, // center - 8-1, 3-1, // N - 14-1, 5-1, // NE - 14-1, 9-1, // SE - 8-1, 11-1, // S - 2-1, 9-1, // SW - 2-1, 5-1 // NW -}; - -//this crashes if more terrain types are added! -static char *ter_fill[] = { - // block - " #### ", - " #### ", - - // ocean - " ~ ~ ", - " ~ ~ ", - - // plain - " ", - " ", - - // forest - " ^ ^ ", - " ^ ^ ", - - // mountain - " /\\/\\ ", - "/ \\ \\", - - // swamp - " v v ", - " v v ", - - // jungle - " @ @ ", - " @ @ ", - - // desert - " . . ", - " . . ", - - // tundra - " ' ' ", - " ' ' ", - - // cavern - " . . ", - " . . ", - - // underforest - " ^ ^ ", - " ^ ^ ", - - // tunnels - " ", - " ", - - // grotto - " . . ", - " . . ", - - // deepforest - " ^ ^ ", - " ^ ^ ", - - // chasm - " ", - " ", - - // nexus - " !!!! ", - " !!!! ", - - // paradise - " + + ", - " + + ", - - // For conquest - // Island Plain - " ", - " ", - - // Island swamp - " v v ", - " v v ", - - // Island mountain - " /\\/\\ ", - "/ \\ \\", - - // For Ceran terrains - - // plain1 - " ", - " ", - // plain2 - " ", - " ", - // plain3 - " ", - " ", - - // forest1 - " ^ ^ ", - " ^ ^ ", - // forest2 - " ^ ^ ", - " ^ ^ ", - // forest3 - " ^ ^ ", - " ^ ^ ", - - // mystforest - " ` ` ", - " ` ` ", - // mystforest1 - " ` ` ", - " ` ` ", - // mystforest2 - " ` ` ", - " ` ` ", - - // mountain1 - " /\\/\\ ", - "/ \\ \\", - // mountain2 - " /\\/\\ ", - "/ \\ \\", - // mountain3 - " /\\/\\ ", - "/ \\ \\", - - // hill - " * * ", - " * * ", - // hill1 - " * * ", - " * * ", - // hill2 - " * * ", - " * * ", - - // swamp1 - " v v ", - " v v ", - // swamp2 - " v v ", - " v v ", - // swamp3 - " v v ", - " v v ", - - // jungle1 - " @ @ ", - " @ @ ", - // jungle2 - " @ @ ", - " @ @ ", - // jungle3 - " @ @ ", - " @ @ ", - - // desert1 - " . . ", - " . . ", - // desert2 - " . . ", - " . . ", - // desert3 - " . . ", - " . . ", - - // wasteland - " ; ; ", - " ; ; ", - // wasteland1 - " ; ; ", - " ; ; ", - - // lake - " ~ ~ ", - " ~ ~ ", - - // tundra1 - " ' ' ", - " ' ' ", - // tundra2 - " ' ' ", - " ' ' ", - // tundra2 - " ' ' ", - " ' ' ", - - // cavern1 - " . . ", - " . . ", - // cavern2 - " . . ", - " . . ", - // cavern3 - " . . ", - " . . ", - - // underforest1 - " ^ ^ ", - " ^ ^ ", - // underforest2 - " ^ ^ ", - " ^ ^ ", - // underforest3 - " ^ ^ ", - " ^ ^ ", - - // tunnels1 - " ", - " ", - // tunnels2 - " ", - " ", - - // grotto1 - " . . ", - " . . ", - // deepforest1 - " ^ ^ ", - " ^ ^ ", - // chasm1 - " ", - " ", - - // volcano - " /\\/\\ ", - "/ \\ \\", - - // lake - " ~ ~ ", - " ~ ~ ", - -}; - -// NEW FUNCTION DK 2000.03.07, -// converted WriteReport -// -void ARegion::WriteTemplateHeader(Areport *f, Faction *fac, - ARegionList *pRegs, int month) -{ - - f->PutStr(""); - - f->PutStr("-------------------------------------------------" - "----------", 1); - - // plain (X,Y) in Blah, contains Blah - f->PutStr(Print(pRegs), 1); - - char buffer[LINE_WIDTH+1]; - char *data = buffer + MAP_WIDTH; - int line = 0; - - Production *prod; - int any; - - // ---------------------------------------------------------------- - GetMapLine(buffer, line, pRegs); - TrimWrite(f, buffer); - line++; - - // ---------------------------------------------------------------- - - if(Globals->WEATHER_EXISTS) { - GetMapLine(buffer, line, pRegs); - - char* nextWeather = ""; - int nxtweather = pRegs->GetWeather(this, (month + 1) % 12); - if (nxtweather == W_WINTER) - nextWeather = "winter"; - if (nxtweather == W_MONSOON) - nextWeather = "monsoon"; - if (nxtweather == W_NORMAL) - nextWeather = "clear"; - sprintf(data, "Next %s", nextWeather); - - TrimWrite(f, buffer); - line++; - } - - // ---------------------------------------------------------------- - GetMapLine(buffer, line, pRegs); - sprintf(data, "Tax %5i", money); - TrimWrite(f, buffer); - line++; - - // ---------------------------------------------------------------- - prod = products.GetProd(I_SILVER, S_ENTERTAINMENT); - if (prod) { - GetMapLine(buffer, line, pRegs); - sprintf(data, "Ente %5i", prod->amount); - TrimWrite(f, buffer); - line++; - } - - // ---------------------------------------------------------------- - prod = products.GetProd(I_SILVER, -1); - if (prod) { - GetMapLine(buffer, line, pRegs); - sprintf(data, "Wage %5i (max %i)", prod->productivity, prod->amount); - TrimWrite(f, buffer); - line++; - } - - // ---------------------------------------------------------------- - any = 0; - { - forlist(&markets) { - Market *m = (Market *) elem; - if (!m->amount) continue; - if (m->type == M_SELL) { - - if (ItemDefs[m->item].type & IT_ADVANCED) { - if (!HasItem(fac, m->item)) { - continue; - } - } - - if (!any) { - GetMapLine(buffer, line, pRegs); - TrimWrite(f, buffer); - line++; - } - GetMapLine(buffer, line, pRegs); - if (m->amount == -1) { - sprintf(data, "%s unlim %4s @ %3i", - (any ? " " : "Want"), - ItemDefs[m->item].abr, - m->price); - } else { - sprintf(data, "%s %5i %4s @ %3i", - (any ? " " : "Want"), - m->amount, - ItemDefs[m->item].abr, - m->price); - } - TrimWrite(f, buffer); - line++; - - any = 1; - } - } - } - - // ---------------------------------------------------------------- - any = 0; - { - forlist(&markets) { - Market *m = (Market *) elem; - if (!m->amount) continue; - if (m->type == M_BUY) { - - if (!any) { - GetMapLine(buffer, line, pRegs); - TrimWrite(f, buffer); - line++; - } - - GetMapLine(buffer, line, pRegs); - - if (m->amount == -1) { - sprintf(data, "%s unlim %4s @ %3i", - (any ? " " : "Sell"), - ItemDefs[m->item].abr, - m->price); - } else { - sprintf(data, "%s %5i %4s @ %3i", - (any ? " " : "Sell"), - m->amount, - ItemDefs[m->item].abr, - m->price); - } - - TrimWrite(f, buffer); - line++; - any = 1; - } - } - } - - // ---------------------------------------------------------------- - any = 0; - { - forlist((&products)) { - Production *p = ((Production *) elem); - if (ItemDefs[p->itemtype].type & IT_ADVANCED) { - if (!CanMakeAdv(fac, p->itemtype)) { - continue; - } - } else { - if (p->itemtype == I_SILVER) { - continue; - } - } - - if (!any) { - GetMapLine(buffer, line, pRegs); - TrimWrite(f, buffer); - line++; - } - - GetMapLine(buffer, line, pRegs); - - if (p->amount == -1) { - sprintf(data, "%s unlim %4s", - (any ? " " : "Prod"), - ItemDefs[p->itemtype].abr); - } else { - sprintf(data, "%s %5i %4s", - (any ? " " : "Prod"), - p->amount, - ItemDefs[p->itemtype].abr); - } - - TrimWrite(f, buffer); - line++; - any = 1; - - } - } - - // ---------------------------------------------------------------- - - if(Globals->GATES_EXIST && gate) { - int sawgate = 0; - forlist(&objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if (!sawgate && u->faction == fac && - u->GetSkill(S_GATE_LORE)) { - GetMapLine(buffer, line, pRegs); - TrimWrite(f, buffer); - line++; - - GetMapLine(buffer, line, pRegs); - sprintf(data, "Gate %4i", gate); - TrimWrite(f, buffer); - line++; - - sawgate = 1; - } - } - } - } - - // ---------------------------------------------------------------- - while (line < TEMPLATE_MAX_LINES) { - GetMapLine(buffer, line, pRegs); - TrimWrite(f, buffer); - line++; - } -} - - -// NEW FUNCTION DK 2000.03.07, -// converted WriteExits -// -void ARegion::GetMapLine(char *buffer, int line, ARegionList *pRegs) -{ - for (int m=0; m= TEMPLATE_MAX_LINES) - return; - - char *dest = buffer+TMPL_MAP_OFS; - memcpy(dest, TemplateMap[line], TMPL_MAP_WIDTH); - ARegion *r = this; - int x, y, t, i = 0; - char *name; - - t = (r->type + 1) * 2; - name = (r->town ? r->town->name->Str() : NULL); - for (;;) { - - x = dircrd[i*2]; - y = dircrd[i*2+1]; - - if (y == line || y+1 == line) { - if (y == line) { - if (name) { - int len = strlen(name); - if (len > FILL_SIZE) len = FILL_SIZE; - memcpy(dest + x, name, len); - } else { - memcpy(dest + x, ter_fill[t], FILL_SIZE); - } - } else { - t++; - memcpy(dest + x, ter_fill[t], FILL_SIZE); - } - } - if (i >= NDIRS) break; - - ARegion *r = neighbors[i]; - if (r) { - t = (r->type + 1) * 2; - name = (r->town ? r->town->name->Str() : NULL); - } else { - t = 0; - name = NULL; - } - - i++; - } -} - -static void TrimWrite(Areport *f, char *buffer) { - - char *p = buffer + strlen(buffer) - 1; - while (p > buffer) { - if (*p == ' ') { - p--; - } else { - break; - } - } - p[1] = 0; - - f->PutStr(buffer, 1); -} diff --git a/arcadia/times.cpp b/arcadia/times.cpp deleted file mode 100644 index ef3ef7ade..000000000 --- a/arcadia/times.cpp +++ /dev/null @@ -1,328 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "game.h" -#include "gamedata.h" -#include "unit.h" - -WorldEvent::WorldEvent() -{ - type = -1; - place = 0; - reportdelay = 0; - age = 0; - fact1 = -1; - fact2 = -1; -} - -WorldEvent::~WorldEvent() -{ -} - -AString *WorldEvent::Text() -{ - AString *text = 0; - return text; -} - -void Game::CreateBattleEvents() -{ - Battle * b1 = 0; - Battle * b2 = 0; - Battle * b3 = 0; - - forlist(&battles) { - Battle *b = (Battle *) elem; - if(!b1 || b->casualties > b1->casualties) { - b2 = b1; - b3 = b2; - b1 = b; - } else if(!b2 || b->casualties > b2->casualties) { - b3 = b2; - b2 = b; - } else if(!b3 || b->casualties > b3->casualties) { - b3 = b; - } - } - //we've picked out the three biggest battles in the world for the turn. - - if(b1) { - WorldEvent * event = new WorldEvent; - event->type = WorldEvent::BATTLE; - event->place = new Location; - event->place->region = b1->region; - event->place->obj = 0; - event->place->unit = 0; - event->fact1 = b1->casualties; - event->reportdelay = 0; - worldevents.Add(event); - b1 = 0; - } - if(b2) { - WorldEvent * event = new WorldEvent; - event->type = WorldEvent::BATTLE; - event->place = new Location; - event->place->region = b2->region; - event->place->obj = 0; - event->place->unit = 0; - event->fact1 = b2->casualties; - event->reportdelay = 0; - worldevents.Add(event); - b2 = 0; - } - if(b3) { - WorldEvent * event = new WorldEvent; - event->type = WorldEvent::BATTLE; - event->place = new Location; - event->place->region = b3->region; - event->place->obj = 0; - event->place->unit = 0; - event->fact1 = b3->casualties; - event->reportdelay = 0; - worldevents.Add(event); - b3 = 0; - } -} - -void Game::WriteRumour(int &rumournum, AString rumour) -{ - int tries = 0; - int i; - Aoutfile f; - Ainfile g; - AString str; - - do { - str = AString("rumour.") + rumournum; - rumournum++; - i = g.OpenByName( str ); - if(i == 0) g.Close(); - } while (i == 0 && tries < 100); - - i = f.OpenByName( str ); - if(i == -1) { - Awrite("Could not write rumour"); - return; - } - f.PutStr(rumour); - - f.Close(); -} - -void Game::WriteTimes(int timesnum, AString times) -{ - Aoutfile f; - AString str; - - str = AString("times.") + timesnum; - int i = f.OpenByName( str, 1 ); - if(i == -1) { - Awrite("Could not write times"); - return; - } - f.PutStr(times); - - f.Close(); -} - -void Game::CreateTimesReports() -{ - CreateBattleEvents(); - - int rumournum = 1; - int timesnum = 1; - AString rumour; - AString times; - Faction *pFac; - - int elfwritten = 0; - int humanwritten = 0; - int dwarfwritten = 0; - int independentwritten = 0; - - forlist(&factions) { - Faction *f = (Faction *) elem; - //This section writes an opening intro for each faction - - if(f->pStartLoc) { - //ie on turn faction is created. - //get hero name - AString hero; - AString race; - forlist(&f->pStartLoc->objects) { - Object *o = (Object *) elem; - forlist(&o->units) { - Unit *u = (Unit *) elem; - if(u->faction == f && u->type == U_MAGE) { - hero = *u->name; - race = EthnicityString(u->GetEthnicity()); - } - } - } - AString *fname = new AString(*f->name); - AString *token = fname->gettoken(); - int the = 0; - if(*token == "the") the = 1; - delete fname; - fname = 0; - delete token; - token = 0; - - times = hero + ", a " + race + " hero from the "; - if(f->pStartLoc->town) { - times += TownString(f->pStartLoc->town->TownType()) + " "; - times += *f->pStartLoc->town->name; - } else { - ///// - } - times += ", has emerged from obscurity. As leader of "; - if(!the) times += "the "; - times += *f->name; - times += AString(", ") + hero + " may yet achieve dominance over Xanaxor."; - WriteTimes(f->num, times); - } - } - - forlist_reuse(®ions) { - ARegion *r = (ARegion *) elem; - - //This section writes a message every time a city guard/mage unit is killed - if(r->timesmarker == 1) { - times = "The guards of "; - if(r->town) times += (*r->town->name); - else times += *r->name; - times += " have been callously slain!"; - - switch(r->GetEthnicity()) { - case RA_HUMAN: - timesnum = guardfaction; - humanwritten = 1; - break; - case RA_ELF: - timesnum = elfguardfaction; - elfwritten = 1; - break; - case RA_DWARF: - timesnum = dwarfguardfaction; - dwarfwritten = 1; - break; - case RA_OTHER: - timesnum = independentguardfaction; - independentwritten = 1; - break; - default: - timesnum = 0; - break; - } - - if(timesnum) WriteTimes(timesnum, times); - } - } - - forlist_reuse(&worldevents) { - WorldEvent *event = (WorldEvent *) elem; - switch(event->type) { - //This writes a rumour for ALL? battles around the world - case WorldEvent::BATTLE: - rumour = AString("A battle was fought in ") + *event->place->region->name + - ", "; - if(event->fact1 < 8) rumour += "with less than 10 deaths"; - else if(event->fact1 < 80) { - rumour += "with about "; - rumour += ((event->fact1+3+getrandom(5))/10)*10; - rumour += " deaths."; - } else { - rumour += "with about "; - rumour += ((event->fact1+30+getrandom(41))/100)*100; - rumour += " deaths."; - } - WriteRumour(rumournum, rumour); - break; - case WorldEvent::CONVERSION: - pFac = GetFaction(&factions, event->fact1); - if(!pFac) break; - if(pFac->ethnicity != event->fact2) break; - times = AString(*pFac->name) + " has converted to the "; - switch(pFac->ethnicity) { - case RA_HUMAN: - times += "human cause!"; - timesnum = guardfaction; - humanwritten = 1; - break; - case RA_ELF: - times += "elven cause!"; - timesnum = elfguardfaction; - elfwritten = 1; - break; - case RA_DWARF: - times += "dwarven cause!"; - timesnum = dwarfguardfaction; - dwarfwritten = 1; - break; - case RA_OTHER: - times += "independent cause!"; - timesnum = independentguardfaction; - independentwritten = 1; - break; - case RA_NA: - times = AString("The leadership of ") + *pFac->name + " is in chaos."; - timesnum = peasantfaction; - break; - default: - times += "!@#$ please alert your GM !@#$"; - timesnum = guardfaction; - humanwritten = 1; - break; - } - WriteTimes(timesnum, times); - break; - default: - break; - } - } - - //use this if your script doesn't add on the faction name when compiling times. - if(humanwritten) { - Faction *fac = GetFaction(&factions, guardfaction); - WriteTimes(guardfaction, AString(" ")); - WriteTimes(guardfaction, AString(*fac->name)); - } - if(elfwritten) { - Faction *fac = GetFaction(&factions, elfguardfaction); - WriteTimes(elfguardfaction, AString(" ")); - WriteTimes(elfguardfaction, AString(*fac->name)); - } - if(dwarfwritten) { - Faction *fac = GetFaction(&factions, dwarfguardfaction); - WriteTimes(dwarfguardfaction, AString(" ")); - WriteTimes(dwarfguardfaction, AString(*fac->name)); - } - if(independentwritten) { - Faction *fac = GetFaction(&factions, independentguardfaction); - WriteTimes(independentguardfaction, AString(" ")); - WriteTimes(independentguardfaction, AString(*fac->name)); - } - -} diff --git a/arcadia/unit.cpp b/arcadia/unit.cpp deleted file mode 100644 index 4f26d68da..000000000 --- a/arcadia/unit.cpp +++ /dev/null @@ -1,3082 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER - -#include "unit.h" -#include "gamedata.h" - -UnitId::UnitId() -{ -} - -UnitId::~UnitId() -{ -} - -AString UnitId::Print() -{ - if (unitnum) { - return AString(unitnum); - } else { - if (faction) { - return AString("faction ") + AString(faction) + " new " + - AString(alias); - } else { - return AString("new ") + AString(alias); - } - } -} - -UnitPtr *GetUnitList(AList *list, Unit *u) -{ - forlist (list) { - UnitPtr *p = (UnitPtr *) elem; - if (p->ptr == u) return p; - } - return 0; -} - -Unit::Unit() -{ - name = 0; - describe = 0; - label = 0; - num = 0; - type = U_NORMAL; - dead = 0; - energy = 0; - resurrects = 0; - mastery = 0; - transferred = 0; - foggy = 0; - faction = 0; - formfaction = 0; - alias = 0; - guard = GUARD_NONE; - reveal = REVEAL_NONE; - tactics = TACTICS_NONE; - if(Globals->FLIGHT_OVER_WATER == GameDefs::WFLIGHT_NONE) flags = 0; - else flags = FLAG_NOCROSS_WATER; - combat = -1; - for(int i = 0; i < MAX_READY; i++) { - readyWeapon[i] = -1; - readyArmor[i] = -1; - } - readyItem = -1; - object = 0; - attackorders = NULL; - evictorders = NULL; - stealorders = NULL; - monthorders = NULL; - herostudyorders = NULL; - activecastorder = NULL; - teleportorders = NULL; - inTurnBlock = 0; - presentTaxing = 0; - presentMonthOrders = NULL; - former = NULL; - free = 0; - practiced = 0; - numtraded = 0; - nummerchanted = 0; - numquartermastered = 0; - movementmalus = 0; - ClearOrders(); -} - -Unit::Unit(int seq, Faction *f, int a) -{ - num = seq; - type = U_NORMAL; - name = new AString; - describe = 0; - label = 0; - *name = AString("Unit (") + num + ")"; - - dead = 0; - energy = 0; - resurrects = 0; - mastery = 0; - transferred = 0; - foggy = 0; - - faction = f; - formfaction = f; - alias = a; - guard = 0; - reveal = REVEAL_NONE; - tactics = TACTICS_NONE; - if(Globals->FLIGHT_OVER_WATER == GameDefs::WFLIGHT_NONE) flags = 0; - else flags = FLAG_NOCROSS_WATER; - combat = -1; - for(int i = 0; i < MAX_READY; i++) { - readyWeapon[i] = -1; - readyArmor[i] = -1; - } - readyItem = -1; - object = 0; - attackorders = NULL; - evictorders = NULL; - stealorders = NULL; - monthorders = NULL; - herostudyorders = NULL; - activecastorder = NULL; - teleportorders = NULL; - inTurnBlock = 0; - presentTaxing = 0; - presentMonthOrders = NULL; - former = NULL; - free = 0; - practiced = 0; - numtraded = 0; - nummerchanted = 0; - numquartermastered = 0; - movementmalus = 0; - ClearOrders(); -} - -Unit::~Unit() -{ - if (monthorders) delete monthorders; - if (herostudyorders) delete herostudyorders; - if (presentMonthOrders) delete presentMonthOrders; - if (attackorders) delete attackorders; - if (stealorders) delete stealorders; - if (name) delete name; - if (describe) delete describe; - if (label) delete label; -#ifdef DEBUG -Awrite("Deleting Unit"); -#endif -} - -void Unit::SetMonFlags() -{ - guard = GUARD_AVOID; - SetFlag(FLAG_HOLDING, 1); -// reveal = REVEAL_FACTION; // BS Edit - monsters should be obviously monsters. But this would make them always visible regardless of stealth :(. - tactics = TACTICS_AGGRESSIVE; -} - -void Unit::MakeWMon(char *monname, int mon, int num) -{ - AString *temp = new AString(monname); - SetName(temp); - - type = U_WMON; - items.SetNum(mon, num); - SetMonFlags(); -} - -void Unit::Writeout(Aoutfile *s) -{ - s->PutStr(*name); - if (describe) { - s->PutStr(*describe); - } else { - s->PutStr("none"); - } - if (label) { - s->PutStr(*label); - } else { - s->PutStr("none"); - } - s->PutInt(num); - s->PutInt(type); - if (type == U_MAGE && Globals->ARCADIA_MAGIC) { - s->PutInt(energy); - s->PutInt(mastery); - s->PutInt(resurrects); - s->PutInt(dead); - } - s->PutInt(faction->num); - s->PutInt(guard); - s->PutInt(reveal); - s->PutInt(free); - if (readyItem != -1) s->PutStr(ItemDefs[readyItem].abr); - else s->PutStr("NO_ITEM"); - for(int i = 0; i < MAX_READY; ++i) { - if (readyWeapon[i] != -1) - s->PutStr(ItemDefs[readyWeapon[i]].abr); - else s->PutStr("NO_ITEM"); - if (readyArmor[i] != -1) - s->PutStr(ItemDefs[readyArmor[i]].abr); - else s->PutStr("NO_ITEM"); - } - s->PutInt(flags); - items.Writeout(s); - skills.Writeout(s); - if (combat != -1) s->PutStr(SkillDefs[combat].abbr); - else s->PutStr("NO_SKILL"); -} - -void Unit::Readin(Ainfile *s, AList *facs, ATL_VER v) -{ - name = s->GetStr(); - describe = s->GetStr(); - if (*describe == "none") { - delete describe; - describe = 0; - } - label = s->GetStr(); - if (*label == "none") { - delete label; - label = 0; - } - num = s->GetInt(); - type = s->GetInt(); - if(type == U_MAGE && Globals->ARCADIA_MAGIC) { - energy = s->GetInt(); - mastery = s->GetInt(); - resurrects = s->GetInt(); - dead = s->GetInt(); - } - int i = s->GetInt(); - faction = GetFaction(facs, i); - guard = s->GetInt(); - if(guard == GUARD_ADVANCE) guard = GUARD_NONE; - if(guard == GUARD_SET) guard = GUARD_GUARD; - reveal = s->GetInt(); - - /* Handle the new 'ready item', ready weapons/armor, and free */ - free = 0; - readyItem = -1; - for(i = 0; i < MAX_READY; i++) { - readyWeapon[i] = -1; - readyArmor[i] = -1; - } - - free = s->GetInt(); - AString *temp; - temp = s->GetStr(); - readyItem = LookupItem(temp); - delete temp; - for(i = 0; i < MAX_READY; i++) { - temp = s->GetStr(); - readyWeapon[i] = LookupItem(temp); - delete temp; - temp = s->GetStr(); - readyArmor[i] = LookupItem(temp); - delete temp; - } - flags = s->GetInt(); - - items.Readin(s); - skills.Readin(s); - temp = s->GetStr(); - combat = LookupSkill(temp); - delete temp; -} - -AString Unit::MageReport() -{ - AString temp = AString(""); - - if (combat != -1) { - temp += AString(". Combat spell: ") + SkillStrs(combat); - } else temp += ". Combat spell: none"; - - if (Globals->ARCADIA_MAGIC) { //not relevant for guardmages. - temp += AString(". Energy: ") + energy + "/" + MaxEnergy(); - temp += AString(". Recharge: ") + EnergyRecharge(); - } - - return temp; -} - -AString Unit::ReadyItem() -{ - AString temp, weaponstr, armorstr, battlestr; - int weapon, armor, item, i, ready; - - item = 0; - for(i = 0; i < MAX_READY; ++i) { - ready = readyWeapon[i]; - if(ready != -1) { - if(item) weaponstr += ", "; - weaponstr += ItemString(ready, 1); - ++item; - } - } - if(item > 0) - weaponstr = AString("Ready weapon") + (item == 1?"":"s") + ": " + - weaponstr; - weapon = item; - - item = 0; - for(i = 0; i < MAX_READY; ++i) { - ready = readyArmor[i]; - if(ready != -1) { - if(item) armorstr += ", "; - armorstr += ItemString(ready, 1); - ++item; - } - } - if(item > 0) - armorstr = AString("Ready armor: ") + armorstr; - armor = item; - - if(readyItem != -1) { - battlestr = AString("Ready item: ") + ItemString(readyItem, 1); - item = 1; - } else - item = 0; - - if(weapon || armor || item) { - temp += AString(". "); - if(weapon) temp += weaponstr; - if(armor) { - if(weapon) temp += ". "; - temp += armorstr; - } - if(item) { - if(armor || weapon) temp += ". "; - temp += battlestr; - } - } - return temp; -} - -AString Unit::StudyableSkills() -{ - AString temp; - int j=0; - - for (int i=0; i stealth) { - ret += ", "; - ret += *faction->name; - } - return ret; -} - -int Unit::CanGetSpoil(Item *i) -{ - //if can carry unlimited items, we return (i->num+1) as this always exceeds what is available ... - if(!i) return 0; - int itemweight = ItemDefs[i->type].weight; - if(!itemweight) return (i->num+1); // any unit can carry 0 weight spoils - - int num; - - if(flags & FLAG_NOSPOILS) return 0; //no spoils! - if(flags & FLAG_FLYSPOILS) { - itemweight -= ItemDefs[i->type].fly; - if(itemweight < 1) return (i->num+1); - num = (FlyingCapacity() - Weight())/itemweight; //we know itemweight is not zero - if(num < 1) return 0; - else return num; - } - if(flags & FLAG_RIDESPOILS) { - itemweight -= ItemDefs[i->type].ride; - if(itemweight < 1) return (i->num+1); - num = (RidingCapacity() - Weight())/itemweight; //we know itemweight is not zero - if(num < 1) return 0; - else return num; - } - if(flags & FLAG_WALKSPOILS) { - itemweight -= ItemDefs[i->type].walk; - if(itemweight < 1) return (i->num+1); - num = (WalkingCapacity() - Weight())/itemweight; //we know itemweight is not zero - if(num < 1) return 0; - else return num; - } - if(flags & FLAG_SWIMSPOILS) { - itemweight -= ItemDefs[i->type].swim; - if(itemweight < 1) return (i->num+1); - num = (SwimmingCapacity() - Weight())/itemweight; //we know itemweight is not zero - if(num < 1) return 0; - else return num; - } - if(flags & FLAG_SAILSPOILS) { - if(itemweight < 1) return (i->num+1); //this should not be needed, but hey, why not! - if(!object->IsBoat()) return (i->num+1); //if we're not on a boat, consider this to be spoils all - //we need num to be (spare sailing capacity) divided by itemweight - num = (ObjectDefs[object->type].capacity - object->Weight())/itemweight; //we know itemweight is not zero - if(num < 1) return 0; - else return num; - } - return (i->num+1); // all spoils -} - -AString Unit::SpoilsReport() { - AString temp; - if(GetFlag(FLAG_NOSPOILS)) temp = ", weightless battle spoils"; - else if(GetFlag(FLAG_FLYSPOILS)) temp = ", flying battle spoils"; - else if(GetFlag(FLAG_WALKSPOILS)) temp = ", walking battle spoils"; - else if(GetFlag(FLAG_RIDESPOILS)) temp = ", riding battle spoils"; - else if(GetFlag(FLAG_SWIMSPOILS)) temp = ", swimming battle spoils"; - else if(GetFlag(FLAG_SAILSPOILS)) temp = ", sailing battle spoils"; - return temp; -} - -void Unit::WriteReport(Areport *f, int obs, int truesight, int detfac, - int autosee, int attitude) -{ - - if(dead) return; // Do not see dead units - - int stealth = GetAttribute("stealth"); - if (obs==-1) { - /* The unit belongs to the Faction writing the report */ - obs = 2; - } else { - if (obs < stealth) { - /* The unit cannot be seen */ - if (reveal == REVEAL_FACTION) { - obs = 1; - } else { - if (guard == GUARD_GUARD || reveal == REVEAL_UNIT || autosee) { - obs = 0; - } else { - return; - } - } - } else { - if (obs == stealth) { - /* Can see unit, but not Faction */ - if (reveal == REVEAL_FACTION) { - obs = 1; - } else { - obs = 0; - } - } else { - /* Can see unit and Faction */ - obs = 1; - } - } - } - - /* Setup True Sight */ - if (obs == 2) { - truesight = 1; - } else { - if (!Globals->ARCADIA_MAGIC && (GetSkill(S_ILLUSION) > truesight) ) { - truesight = 0; - } else if (Globals->ARCADIA_MAGIC && (GetSkill(S_BASE_ILLUSION) > truesight)) { - truesight = 0; - } else if (truesight != 0) { //BS mod: if no illusion skill, eg monsters, still need TRUE 1 to see they are illusions! - truesight = 1; - } - } - - if (detfac && obs != 2) obs = 1; - - /* Write the report */ - AString temp; - if (obs == 2) { - temp += AString("* ") + *name; - } else { - if (faction->showunitattitudes) { - switch (attitude) { - case A_ALLY: - temp += AString("= ") +*name; - break; - case A_FRIENDLY: - temp += AString(": ") +*name; - break; - case A_NEUTRAL: - temp += AString("- ") +*name; - break; - case A_UNFRIENDLY: - temp += AString("% ") +*name; - break; - case A_HOSTILE: - temp += AString("! ") +*name; - break; - } - } else { - temp += AString("- ") + *name; - } - } - - if (guard == GUARD_GUARD) temp += ", on guard"; - if (obs > 0) temp += AString(", ") + *faction->name + " [" + EthnicityString(faction->ethnicity) + "]"; - if(obs == 2 && label) temp += AString(", ") + *label; - if (obs > 0) { - if (guard == GUARD_AVOID) temp += ", avoiding"; - if (GetFlag(FLAG_BEHIND)) temp += ", behind"; - } - - if (obs == 2) { - if (GetFlag(FLAG_COMMANDER)) temp += ", commanding faction"; - if (reveal == REVEAL_UNIT) temp += ", revealing unit"; - if (reveal == REVEAL_FACTION) temp += ", revealing faction"; - if (GetFlag(FLAG_HOLDING)) temp += ", holding"; - if (GetFlag(FLAG_AUTOTAX)) temp += ", taxing"; - if (GetFlag(FLAG_NOAID)) temp += ", receiving no aid"; - if (GetFlag(FLAG_SHARING)) temp += ", sharing"; - if (GetFlag(FLAG_CONSUMING_UNIT)) temp += ", consuming unit's food"; - if (GetFlag(FLAG_CONSUMING_FACTION)) - temp += ", consuming faction's food"; - if (GetFlag(FLAG_NOCROSS_WATER)) temp += ", won't cross water"; - if (GetFlag(FLAG_FIGHTASFOOT)) temp += ", fighting as foot"; - if (GetFlag(FLAG_FIGHTASRIDE)) temp += ", fighting as cavalry"; - if (tactics == TACTICS_AGGRESSIVE) temp += ", fighting aggressively"; - if (tactics == TACTICS_DEFENSIVE) temp += ", fighting defensively"; - temp += SpoilsReport(); - } - - temp += items.Report(obs, truesight, 0, type); - - if (obs == 2) { - temp += ". Weight: "; - temp += AString(items.Weight()); - temp += ". Capacity: "; - temp += AString(FlyingCapacity()); - temp += "/"; - temp += AString(RidingCapacity()); - temp += "/"; - temp += AString(WalkingCapacity()); - temp += "/"; - temp += AString(SwimmingCapacity()); - temp += ". Skills: "; - temp += skills.Report(GetMen()); - } - - if (obs == 2 && (type == U_MAGE || type == U_GUARDMAGE)) { - temp += MageReport(); - } - - if(obs == 2) { - temp += ReadyItem(); - temp += StudyableSkills(); - } - - if (describe) { - temp += AString("; ") + *describe; - } - temp += "."; - f->PutStr(temp); -} - -AString Unit::TemplateReport() -{ - /* Write the report */ - AString temp; - temp = *name; - - if (guard == GUARD_GUARD) temp += ", on guard"; - if (label) temp += AString(", ") + *label; - if (guard == GUARD_AVOID) temp += ", avoiding"; - if (GetFlag(FLAG_BEHIND)) temp += ", behind"; - if (GetFlag(FLAG_COMMANDER)) temp += ", commanding faction"; - if (reveal == REVEAL_UNIT) temp += ", revealing unit"; - if (reveal == REVEAL_FACTION) temp += ", revealing faction"; - if (GetFlag(FLAG_HOLDING)) temp += ", holding"; - if (GetFlag(FLAG_AUTOTAX)) temp += ", taxing"; - if (GetFlag(FLAG_NOAID)) temp += ", receiving no aid"; - if (GetFlag(FLAG_SHARING)) temp += ", sharing"; - if (GetFlag(FLAG_CONSUMING_UNIT)) temp += ", consuming unit's food"; - if (GetFlag(FLAG_CONSUMING_FACTION)) temp += ", consuming faction's food"; - if (GetFlag(FLAG_NOCROSS_WATER)) temp += ", won't cross water"; - temp += SpoilsReport(); - - temp += items.Report(2, 1, 0, type); - temp += ". Weight: "; - temp += AString(items.Weight()); - temp += ". Capacity: "; - temp += AString(FlyingCapacity()); - temp += "/"; - temp += AString(RidingCapacity()); - temp += "/"; - temp += AString(WalkingCapacity()); - temp += "/"; - temp += AString(SwimmingCapacity()); - temp += ". Skills: "; - temp += skills.Report(GetMen()); - - if (type == U_MAGE || type == U_GUARDMAGE) { - temp += MageReport(); - } - temp += ReadyItem(); - temp += StudyableSkills(); - - if (describe) { - temp += AString("; ") + *describe; - } - temp += "."; - return temp; -} - -AString *Unit::BattleReport(int obs) -{ - AString *temp = new AString(""); - if(Globals->BATTLE_FACTION_INFO) - *temp += GetName(obs); - else - *temp += *name; - - if (GetFlag(FLAG_BEHIND)) *temp += ", behind"; - if (GetFlag(FLAG_FIGHTASFOOT)) *temp += ", fighting as foot"; - if (GetFlag(FLAG_FIGHTASRIDE)) *temp += ", fighting as cavalry"; - - *temp += items.BattleReport(type); - - forlist (&skills) { - Skill *s = (Skill *)elem; - if (SkillDefs[s->type].flags & SkillType::BATTLEREP) { - int lvl = GetSkill(s->type); - if (lvl) { - *temp += ", "; - *temp += SkillDefs[s->type].name; - *temp += " "; - *temp += lvl; - } - } - } - - if (describe) { - *temp += "; "; - *temp += *describe; - } - - *temp += "."; - return temp; -} - -void Unit::ClearOrders() -{ - canattack = 1; - nomove = 0; - enter = 0; - build = NULL; - leftShip = 0; - destroy = 0; - if (attackorders) delete attackorders; - attackorders = 0; - if (evictorders) delete evictorders; - evictorders = 0; - if (stealorders) delete stealorders; - stealorders = 0; - promote = 0; - promotequiet = 0; - taxing = TAX_NONE; - advancefrom = 0; - movepoints = 0; - if (monthorders) delete monthorders; - monthorders = 0; - if (herostudyorders) delete herostudyorders; - herostudyorders = 0; - inTurnBlock = 0; - presentTaxing = 0; - if (presentMonthOrders) delete presentMonthOrders; - presentMonthOrders = 0; - if (teleportorders) delete teleportorders; - teleportorders = 0; - typeorders.DeleteAll(); - giveorders.DeleteAll(); - sendorders.DeleteAll(); - withdraworders.DeleteAll(); - wishdraworders.DeleteAll(); - wishskillorders.DeleteAll(); - bankorders.DeleteAll(); - buyorders.DeleteAll(); - sellorders.DeleteAll(); - forgetorders.DeleteAll(); - exchangeorders.DeleteAll(); - transportorders.DeleteAll(); -} - - -void Unit::SafeClearOrders() -{ -//Called when a unit dies, and becomes a spirit of the dead. Cannot delete -//any orders which may have led to the battle, as these are likely to be deleted -//later. -//Instead, simply leave them and make sure they cannot lead to any further game -//effects (ie unit cannot attack & steal orders are hardcoded so dead units can't steal). -//Since they are not reset to zero, should be no memory leaks. - -//don't let it attack further - canattack = 0; - nomove = 1; - enter = 0; - build = NULL; - leftShip = 0; - destroy = 0; -//don't delete attack order - if (evictorders) delete evictorders; - evictorders = 0; -//don't delete steal orders - promote = 0; - taxing = TAX_NONE; - advancefrom = 0; - movepoints = 0; - if (monthorders) delete monthorders; - monthorders = 0; - inTurnBlock = 0; - presentTaxing = 0; - if (presentMonthOrders) delete presentMonthOrders; - presentMonthOrders = 0; - activecastorder = 0; - if (teleportorders) delete teleportorders; - teleportorders = 0; - castlistorders.DeleteAll(); - giveorders.DeleteAll(); - sendorders.DeleteAll(); - withdraworders.DeleteAll(); - wishdraworders.DeleteAll(); - wishskillorders.DeleteAll(); - bankorders.DeleteAll(); - buyorders.DeleteAll(); - sellorders.DeleteAll(); - forgetorders.DeleteAll(); - exchangeorders.DeleteAll(); - transportorders.DeleteAll(); -} - -void Unit::ClearCastOrder() -{ - castlistorders.DeleteAll(); -} - -void Unit::ClearTeleportOrders() -{ - if(!Globals->ARCADIA_MAGIC) { - castlistorders.DeleteAll(); //can't have more than one cast order - } - if (teleportorders) delete teleportorders; - teleportorders = 0; -} - -void Unit::DefaultOrders(Object *obj, int peasantfac) -{ - ClearOrders(); - if (type == U_WMON) { - if (ObjectDefs[obj->type].monster == -1) { - guard = GUARD_AVOID; //resetting, gets lost (when advancing?) - reveal = REVEAL_NONE; //Arcadia mod only, to fix earlier reveal faction mistake. - MoveOrder *o = new MoveOrder; - o->advancing = 0; - int aper = Hostile(); - aper *= Globals->MONSTER_ADVANCE_HOSTILE_PERCENT; - aper /= 100; - - if(aper < Globals->MONSTER_ADVANCE_MIN_PERCENT) - aper = Globals->MONSTER_ADVANCE_MIN_PERCENT; - - int n = getrandom(100); - if(n < aper) o->advancing = 1; - MoveDir *d = new MoveDir; - int tries = 0; //BS mod to make monsters move sensible directions. - int direc = -1; -#define MAXTRIES 10 - while(tries < MAXTRIES) { - direc = getrandom(NDIRS); - if(obj->region->neighbors[direc]) { - if( CanSwim() ) tries = MAXTRIES; - else if( (TerrainDefs[obj->region->neighbors[direc]->type].similar_type != R_OCEAN) && - (obj->region->neighbors[direc]->willsink == 0 || - (obj->region->willsink != 0 && obj->region->neighbors[direc]->willsink >= obj->region->willsink)) ) tries = MAXTRIES; - else direc = -1; - } - tries++; - } - if(direc > -1) { - d->dir = direc; - o->dirs.Add(d); - monthorders = o; - } else { - //no move orders - delete d; - delete o; - } - } - } else if(type == U_GUARD) { - if (guard != GUARD_GUARD) - guard = GUARD_SET; - } else if(type == U_GUARDMAGE) { -// combat = S_FIRE; combat skill stored and set. -//wandering peasants: // maybe have some chance of them settling in the region ... - } else if(faction->num == peasantfac) { - reveal = REVEAL_FACTION; - if(type == U_NORMAL && getrandom(2)) { - ProduceOrder *order = new ProduceOrder; - order->skill = -1; - order->item = I_SILVER; - monthorders = order; - return; - } - MoveOrder *o = new MoveOrder; - o->advancing = 0; - MoveDir *d = new MoveDir; - int tries = 0; - int direc = -1; - while(tries < MAXTRIES) { - direc = getrandom(NDIRS); - if(obj->region->neighbors[direc]) { - if( CanMoveTo(obj->region, obj->region->neighbors[direc]) ) tries = MAXTRIES; - } - tries++; - } - d->dir = direc; - o->dirs.Add(d); - monthorders = o; - } else { - /* Set up default orders for factions which submit none */ - if(obj->region->type != R_NEXUS) { - if(GetFlag(FLAG_AUTOTAX) && - Globals->TAX_PILLAGE_MONTH_LONG && Taxers(1)) { - taxing = TAX_AUTO; - } else { - ProduceOrder *order = new ProduceOrder; - order->skill = -1; - order->item = I_SILVER; - monthorders = order; - } - } - } -} - -void Unit::PostTurn(ARegion *r) -{ - if (type == U_WMON) { - forlist(&items) { - Item *i = (Item *) elem; - if(!(ItemDefs[i->type].type & IT_MONSTER) && !getrandom(3)) { //Nylandor patch, 67% chance of monsters keeping spoils per turn. - items.Remove(i); - delete i; - } - } - if(free > 0) --free; - } -} - -void Unit::SetName(AString *s) -{ - if (s) { - AString *newname = s->getlegal(); - if (!newname) { - delete s; - return; - } - *newname += AString(" (") + num + ")"; - delete s; - delete name; - name = newname; - } -} - -void Unit::SetDescribe(AString *s) -{ - if (describe) delete describe; - if (s) { - AString *newname = s->getlegal(); - delete s; - describe = newname; - } else - describe = 0; -} - -void Unit::SetLabel(AString *s) -{ - if (label) delete label; - if (s) { - AString *newname = s->getlegal(); - delete s; - label = newname; - } else - label = 0; -} - -int Unit::IsAlive() -{ -//note if a mage is dead under Arcadia, it can be returned here as still alive - this is to prevent them being discarded midturn -//or trashed in the :kill() routine. - if(type == U_MAGE || type == U_APPRENTICE) { - return(GetMen()); - } else { - forlist(&items) { - Item *i = (Item *) elem; - if (IsSoldier(i->type) && i->num > 0) - return 1; - } - } - return 0; -} - -int Unit::IsReallyAlive() -{ - if(dead) return 0; - else return IsAlive(); -} - -//This returns zero unless the unit is DEFINITELY stationary for the rest of the turn. -//This does not yet take into account enter orders, but should be generalised to -//do so if it is ever called before enter orders take place -int Unit::IsStationary() -{ - if(monthorders && (monthorders->type == O_MOVE || - monthorders->type == O_ADVANCE || - monthorders->type == O_FOLLOW || - monthorders->type == O_SAIL)) return 0; - if(object->IsBoat()) { - forlist(&object->units) { - Unit *u = (Unit *) elem; - if(u->monthorders && u->monthorders->type == O_SAIL) return 0; - } - } - return 1; -} - -void Unit::SetMen(int t, int n) -{ - if (ItemDefs[t].type & IT_MAN) { - int oldmen = GetMen(); - items.SetNum(t, n); - int newmen = GetMen(); - if (newmen < oldmen) { - delete skills.Split(oldmen, oldmen - newmen); - } - } else { - /* This is probably a monster in this case */ - items.SetNum(t, n); - } -} - -int Unit::GetMen(int t) -{ - return items.GetNum(t); -} - -int Unit::GetMons() -{ - int n=0; - forlist(&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MONSTER) { - n += i->num; - } - } - return n; -} - -int Unit::GetMen() -{ - int n = 0; - forlist(&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MAN) { - n += i->num; - } - } - return n; -} -/* -int Unit::GetLeaders() -{ - int n = 0; - forlist (&items) { - Item *i = (Item *)elem; - if (ItemDefs[i->type].type & IT_LEADER) { - n += i->num; - } - } - return n; -} -*/ -int Unit::GetSoldiers() -{ - int n = 0; - forlist(&items) { - Item *i = (Item *) elem; - if (IsSoldier(i->type)) n+=i->num; - } - - return n; -} - -int Unit::GetRealSoldiers() -{ - int n = 0; - forlist(&items) { - Item *i = (Item *) elem; - if (IsSoldier(i->type) && !(ItemDefs[i->type].type & IT_ILLUSION) ) n += i->num; - } - - return n; -} - -int Unit::GetAttackRiding() -{ - int riding = 0; - if (type == U_WMON) { - forlist(&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MONSTER) { - if (ItemDefs[i->type].fly) { - if(!Globals->REAL_EXPERIENCE) return 5; - else return 6; - } - if (ItemDefs[i->type].ride) riding = 3; - } - } - return riding; - } else { - riding = GetSkill(S_RIDING); - int bonusriding = GetSkill(S_SWIFTNESS); - int lowriding = 0; - int minweight = 10000; - forlist(&items) { - Item *i = (Item *)elem; - if (ItemDefs[i->type].type & IT_MAN) - if (ItemDefs[i->type].weight < minweight) - minweight = ItemDefs[i->type].weight; - } - forlist_reuse (&items) { - Item *i = (Item *)elem; - if (ItemDefs[i->type].fly - ItemDefs[i->type].weight >= minweight) - return (riding+bonusriding); - if (ItemDefs[i->type].ride-ItemDefs[i->type].weight >= minweight) { - if (riding <= 3 && bonusriding <= 3) return (riding+bonusriding); - lowriding = 3; - } - } - if(bonusriding > lowriding) bonusriding = lowriding; - return (lowriding+bonusriding); - } -} - -int Unit::GetDefenseRiding() -{ - if (guard == GUARD_GUARD) return 0; - - int riding = 0; - int weight = Weight(); - - if (CanFly(weight)) { - if(!Globals->REAL_EXPERIENCE) riding = 5; - else riding = 6; - } - else if (CanRide(weight)) riding = 3; - - if (GetMen()) { - int manriding = GetSkill(S_RIDING); - int bonusriding = GetSkill(S_SWIFTNESS); - if (riding < bonusriding) bonusriding = riding; - if (manriding < riding) return (manriding+bonusriding); - else return (riding+bonusriding); - } else if (type == U_WMON && riding) riding = riding/2 + 1; //make monsters easier to catch. 6->4, 3->2 - - return riding; -} - -int Unit::GetSkill(int sk) -{ - if (sk == S_TACTICS) return GetAttribute("tactics"); - if (sk == S_STEALTH) return GetAttribute("stealth"); - if (sk == S_OBSERVATION) return GetAttribute("observation"); - if (sk == S_ENTERTAINMENT) return GetAttribute("entertainment"); - if(skills.IsDisabled(sk)) return 0; //either don't have the skill, or it's been disabled. - int retval = GetRealSkill(sk); - return retval; -} - -void Unit::SetSkill(int sk, int level) -{ - skills.SetDays(sk, GetDaysByLevel(level) * GetMen()); -} - -void Unit::SetSkill(int sk, int level, int experlevel) -{ - if(Globals->REAL_EXPERIENCE) skills.SetDays(sk, GetDaysByLevel(level) * GetMen(), GetDaysByLevel(experlevel) * GetMen()); - else skills.SetDays(sk, GetDaysByLevel(level+experlevel) * GetMen()); -} - -int Unit::GetRealSkill(int sk) -{ - if (GetMen()) { - return GetLevelByDays(skills.GetDays(sk)/GetMen(),skills.GetExper(sk)/GetMen()); - } else { - return 0; - } -} - -int Unit::GetDaysSkill(int sk) -{ - if (GetMen()) { - return GetLevelByDays(skills.GetDays(sk)/GetMen()); - } else { - return 0; - } -} - -int Unit::GetExperSkill(int sk) -{ - if (GetMen()) { - return GetLevelByDays(skills.GetExper(sk)/GetMen()); - } else { - return 0; - } -} - - -void Unit::ForgetSkill(int sk) -{ - skills.SetDays(sk, 0, 0); //REAL_EXPERIENCE Patch - - if(combat == sk) { - combat = -1; - Event("Combat spell set to none."); - } - - if(!Globals->ARCADIA_MAGIC) { - if (type == U_MAGE) { - forlist(&skills) { - Skill *s = (Skill *) elem; - if(SkillDefs[s->type].flags & SkillType::MAGIC) { - return; - } - } - type = U_NORMAL; - } - if(type == U_APPRENTICE) { - forlist(&skills) { - Skill *s = (Skill *) elem; - if(SkillDefs[s->type].flags & SkillType::APPRENTICE) { - return; - } - } - type = U_NORMAL; - } - } else { - if (sk == S_HEROSHIP && type == U_MAGE) { - type = U_LEADER; - AdjustSkills(0); - } else if(sk == S_LEADERSHIP && type == U_LEADER) { - type = U_NORMAL; - AdjustSkills(0); - } - } -} - -int Unit::CheckDepend(int lev, SkillDepend &dep) -{ - AString skname = dep.skill; - int sk = LookupSkill(&skname); - if (sk == -1) return 0; - int temp = GetRealSkill(sk); - if(temp < dep.level) return 0; - if(lev >= temp) return 0; - return 1; -} - -int Unit::CanStudy(int sk) -{ - int curlev = GetDaysSkill(sk); - if(curlev >= GetSkillKnowledgeMax(sk) && GetExperSkill(sk) >= GetSkillExperMax(sk) ) return 0; //for REAL_EXPERIENCE only (should ifglobal it), this means that if reached max exper level, cannot keep studying. - - if(SkillDefs[sk].flags & SkillType::DISABLED) return 0; - - unsigned int c; - for(c = 0; c < sizeof(SkillDefs[sk].depends)/sizeof(SkillDepend); c++) { - if(SkillDefs[sk].depends[c].skill == NULL) return 1; - SkillType *pS = FindSkill(SkillDefs[sk].depends[c].skill); - if (pS && (pS->flags & SkillType::DISABLED)) continue; - if(!CheckDepend(curlev, SkillDefs[sk].depends[c])) return 0; - } - return 1; -} - -int Unit::Study(int sk, int days, int quiet, int overflow) -{ - //Upgrading gets handled differently to other skills. - if(SkillDefs[sk].flags & SkillType::UPGRADE) { - switch(sk) { - case S_LEADERSHIP: - if(type != U_NORMAL) { - Error("STUDY: Only normal units can study leadership", quiet); - return 0; - } else type = U_LEADER; - return 1; - case S_HEROSHIP: - if(type != U_LEADER || GetMen() != 1) { - Error("STUDY: Only one man leader units can study heroship", quiet); - return 0; - } - type = U_MAGE; - return 1; - default: - break; - } - } - - Skill *s; - - if(Globals->SKILL_LIMIT_NONLEADERS && IsNormal()) { - if (skills.Num()) { - s = (Skill *) skills.First(); - if (s->type != sk) { - //Real experience patch - if(s->days >= 30*GetMen() || s->experience >= 30*GetMen()) { - Error("STUDY: Can know only 1 skill.", quiet); - return 0; - } - } - } - } - int max = GetSkillKnowledgeMax(sk); - if (GetDaysSkill(sk) >= max) { - if(!Globals->REAL_EXPERIENCE) { - Error("STUDY: Maximum level for skill reached.", quiet); - return 0; - } else if (!overflow) { - Error("STUDY: Maximum knowledge level for skill reached, teaching has no effect.", quiet); - return 0; - } else if (GetExperSkill(sk) >= GetSkillExperMax(sk) ) { - Error("STUDY: Maximum level for skill reached.", quiet); - return 0; - } - } - - if (!CanStudy(sk) && overflow) { //overflow == 0 is only called for teaching, when to stick to old behaviour we don't want this checked. For Arcadia IV, review this. - Error("STUDY: Doesn't have the pre-requisite skills to study that.", quiet); - return 0; - } - - skills.SetDays(sk, skills.GetDays(sk) + days); - AdjustSkills(overflow); - - /* Check to see if we need to show a skill report */ - int lvl = GetRealSkill(sk); - if (lvl > faction->skills.GetDays(sk)) { - faction->skills.SetDays(sk, lvl); - faction->shows.Add(new ShowSkill(sk, lvl)); - } - return 1; -} - -void Unit::Experience(int sk, int experience, int group, int dividenonspecials) //group =1, dividenonspecials =1, by default. -{ - if(!Globals->REAL_EXPERIENCE) return; - if(experience < 1) return; - - Skill *s; - - if(Globals->SKILL_LIMIT_NONLEADERS && IsNormal()) { - //if can know only one skill, and first skill is not the one to experience, do not get experience. - if (skills.Num()) { - s = (Skill *) skills.First(); - if (s->type != sk) { - return; - } - } - } - - if(GetSkillExperMax(sk) == 0) return; - - if(dividenonspecials) { - //if non-specialist skill, divide experience gain by 2 (from 10 to 5 in most cases). - if(!IsASpeciality(sk)) experience /= 2; - } - - if(experience < 1) return; - - if(SkillDefs[sk].baseskill != -1 && SkillDefs[sk].baseskill != sk) { - //check to make sure some silly GM hasn't given a baseskill a different baseskill (cascading experiences and possibly infernal loops) - if(SkillDefs[SkillDefs[sk].baseskill].baseskill == -1 || - SkillDefs[SkillDefs[sk].baseskill].baseskill == SkillDefs[sk].baseskill) { - int baseexp = (experience)/2; - if(baseexp>4) baseexp = 4; - Experience(SkillDefs[sk].baseskill, baseexp, group, 0); //don't divide non-specials again! - } - } - - if(group) experience *= GetMen(); - - skills.SetExper(sk, skills.GetExper(sk) + experience); - AdjustSkills(1); - - int lvl = GetRealSkill(sk); - if (lvl > faction->skills.GetDays(sk)) { - faction->skills.SetDays(sk, lvl); - faction->shows.Add(new ShowSkill(sk, lvl)); - } - -} - -int Unit::IsASpeciality(int sk) -{ - if (SkillDefs[sk].flags & SkillType::DISABLED) return 0; - - forlist (&items) { - Item *i = (Item *)elem; - if (ItemDefs[i->type].flags & ItemType::DISABLED) continue; - if (!(ItemDefs[i->type].type & IT_MAN)) continue; - if(!(IsSpeciality(SkillDefs[sk].abbr, i->type)) && (SkillDefs[sk].baseskill < 0 || !(IsSpeciality(SkillDefs[SkillDefs[sk].baseskill].abbr, i->type)))) return 0; - } - return 1; -} - -int Unit::GetSkillKnowledgeMax(int sk) -/* REAL_EXPERIENCE Patch */ -//returns maximum knowledge level of a skill (not number of days study!) -{ - if((SkillDefs[sk].flags & SkillType::MAGIC) && !IsMage()) return 0; - - int max = -2; - - if (SkillDefs[sk].flags & SkillType::DISABLED) return 0; - - forlist (&items) { - Item *i = (Item *)elem; - if (ItemDefs[i->type].flags & ItemType::DISABLED) continue; - if (!(ItemDefs[i->type].type & IT_MAN)) continue; - int m = SkillMax(SkillDefs[sk].abbr, i->type); - if ((max == -2 && m > max) || (m < max)) max = m; //need this to return 0 or 1 for hero skills, as this gets added up to 2 or 3 below. - } - - if(max < 0) max = 0; - - switch(type) { - case U_NORMAL: - case U_GUARD: - return max; //2 or 1 - case U_SPECIALIST: - case U_LEADER: - case U_APPRENTICE: - return (max+1); //3 or 2 - case U_MAGE: - case U_GUARDMAGE: - return (max+2); //4 or 3 - default: - return max; - } -} - -int Unit::GetSkillExperMax(int sk) -/* REAL_EXPERIENCE Patch */ -//returns maximum experience level of a skill -{ - int max = GetSkillKnowledgeMax(sk); //set experience and knowledge maxes equal. - //add in level of appropriate glamour spell - doesn't exist yet - return max; -/* - int max = -1; - - if (SkillDefs[sk].flags & SkillType::DISABLED) return 0; - - forlist (&items) { - Item *i = (Item *)elem; - if (ItemDefs[i->type].flags & ItemType::DISABLED) continue; - if (!(ItemDefs[i->type].type & IT_MAN)) continue; - int m = SkillExperMax(SkillDefs[sk].abbr, i->type); - if ((max == -1 && m > max) || (m < max)) max = m; - } - - if(max < 0) max = 0; - - switch(type) { - case U_NORMAL: - return max; - case U_SPECIALIST: - case U_LEADER: - return (max+1); - case U_MAGE: - return (max+2); - default: - return max; - } - */ -} - -int Unit::Practice(int sk) -{ - if(Globals->REAL_EXPERIENCE) return 1; - - int bonus, men, curlev, reqsk, reqlev, days; - unsigned int i; - - bonus = Globals->SKILL_PRACTICE_AMOUNT; - if (practiced || (bonus < 1)) return 1; - days = skills.GetDays(sk); - men = GetMen(); - - if (men < 1 || days < 1) return 0; - - /* - * Let's do this check for max level correctly.. Non-leader units - * won't ever be able to get to 450 days like the original code checked - * for. - */ - int max = GetSkillKnowledgeMax(sk); - curlev = GetDaysSkill(sk); - if (curlev >= max) return 0; - - for(i = 0; i < sizeof(SkillDefs[sk].depends)/sizeof(SkillDepend); i++) { - AString skname = SkillDefs[sk].depends[i].skill; - reqsk = LookupSkill(&skname); - if (reqsk == -1) break; - if (SkillDefs[reqsk].flags & SkillType::DISABLED) continue; - reqlev = GetRealSkill(reqsk); - if (reqlev <= curlev) { - if (Practice(reqsk)) - return 1; - // We don't meet the reqs, and can't practice that - // req, but we still need to check the other reqs. - bonus = 0; - } - } - - if (bonus) { - Study(sk, men * bonus, 1); - practiced = 1; - } - - return bonus; -} - -int Unit::IsMage() -{ - if(type == U_MAGE || type == U_GUARDMAGE) return 1; - return 0; -} - -int Unit::IsLeader() -{ -// if (GetLeaders()) return 1; - if(type == U_LEADER) return 1; - return 0; -} - -int Unit::IsNormal() -{ - if (GetMen() && !IsLeader() && !IsMage()) return 1; - return 0; -} - -void Unit::AdjustSkills(int overflow) -//overflow allows for movement of skills between experience and knowledge -{ - if(!Globals->REAL_EXPERIENCE) overflow = 0; - - // First, is the unit a leader? - // - if(!IsNormal()) { //ie is a mage or leader - // - // Unit is all leaders: Make sure no skills are > max - // - forlist(&skills) { - Skill *theskill = (Skill *) elem; - int max = GetSkillKnowledgeMax(theskill->type); - int expermax = GetSkillExperMax(theskill->type); - if (GetDaysSkill(theskill->type) >= max) { - if(overflow) { - int extra = theskill->days - GetMen() * GetDaysByLevel(max); - if(extra<0) extra = 0; //should never get called - if (SkillDefs[theskill->type].flags & SkillType::MAGIC) { - if(IsASpeciality(SkillDefs[theskill->type].baseskill)) theskill->experience += extra / 3; - else theskill->experience += extra / 6; //halved for non-specials. - } else theskill->experience += extra / 3; //full roll over whether speciality or not? - } - theskill->days = GetDaysByLevel(max) * GetMen(); - } - if (GetExperSkill(theskill->type) >= expermax) { - if(overflow) { - int extra = theskill->experience - GetMen() * GetDaysByLevel(expermax); - if(extra<0) extra = 0; //should never get called - if (CanStudy(theskill->type)) { - theskill->days += extra / 3; - } - } - theskill->experience = GetDaysByLevel(expermax) * GetMen(); - } - if (overflow && GetDaysSkill(theskill->type) >= max) { - theskill->days = GetDaysByLevel(max) * GetMen(); - } - } - } else { - if(Globals->SKILL_LIMIT_NONLEADERS) { - // - // Not a leader, can only know 1 skill - // - if (skills.Num() > 1) { - // - // Find highest skill, eliminate others - // - unsigned int max = 0; - int maxlevel = 0; - //highest skill is defined by days+experience, with the exception that a level 1 skill is - //always counted as higher than a level 0 skill. - - Skill *maxskill = 0; - forlist(&skills) { - Skill *s = (Skill *) elem; - if (s->days + s->experience > max) { - if(s->days >= 30 || s->experience >= 30 || maxlevel == 0) - max = s->days + s->experience; - if(s->days >= 30 || s->experience >= 30) maxlevel = 1; - maxskill = s; - } - } - { - forlist(&skills) { - Skill *s = (Skill *) elem; - if (s != maxskill) { - skills.Remove(s); - delete s; - } - } - } - } - } - - // - // Limit remaining skill to max - // - forlist(&skills) { - Skill *theskill = (Skill *) elem; - int max = GetSkillKnowledgeMax(theskill->type); - int expermax = GetSkillExperMax(theskill->type); - if (GetDaysSkill(theskill->type) >= max) { - if(overflow) { - int extra = theskill->days - GetMen() * GetDaysByLevel(max); - if(extra<0) extra = 0; //should never get called - - if(IsASpeciality(theskill->type)) theskill->experience += extra / 3; - else theskill->experience += extra / 6; - } - theskill->days = GetDaysByLevel(max) * GetMen(); - } - if (GetExperSkill(theskill->type) >= expermax) { - if(overflow) { - int extra = theskill->experience - GetMen() * GetDaysByLevel(expermax); - if(extra<0) extra = 0; //should never get called - theskill->days += extra / 3; - } - theskill->experience = GetDaysByLevel(expermax) * GetMen(); - } - if (overflow && GetDaysSkill(theskill->type) >= max) { - theskill->days = GetDaysByLevel(max) * GetMen(); - } - } - } -} - -int Unit::MaintCost() -{ -// int retval = 0; - int i; - if (type == U_WMON || type == U_GUARD || type == U_GUARDMAGE) return 0; - - int men = GetMen(); - int okethnic = 0; - - if(Globals->ARCADIA_MAGIC) { - int type = GetEthnicity(); - if(type == RA_MIXED) { - men = 0; - forlist(&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MAN) { - ManType *mt = FindRace(ItemDefs[i->type].abr); - if(mt->ethnicity == faction->ethnicity) men += i->num; - else men += 2*i->num; //double maintenance cost for non-ethnic men. - } - } - } else if(type != faction->ethnicity) men *= 2; //double maintenance cost for non-ethnic men. - else okethnic = 1; - } - - if(type == U_LEADER || type == U_MAGE) { - if(Globals->ARCADIA_MAGIC && type == U_MAGE) { - men *= 5; //$100 or $200 - } - // Handle leaders - // Leaders are counted at maintenance_multiplier * skills in all except - // the case where it's not being used (mages, leaders, all) - if (Globals->MULTIPLIER_USE != GameDefs::MULT_NONE) { - i = men * SkillLevels() * Globals->MAINTENANCE_MULTIPLIER; - if (i < (men * Globals->LEADER_COST)) - i = men * Globals->LEADER_COST; - } else - i = men * Globals->LEADER_COST; - return i; - - } else { - - // Handle non-leaders - // Non leaders are counted at maintenance_multiplier * skills only if - // all characters pay that way. - if (Globals->MULTIPLIER_USE == GameDefs::MULT_ALL) { - i = men * SkillLevels() * Globals->MAINTENANCE_MULTIPLIER; - if (i < (men * Globals->MAINTENANCE_COST)) - i = men * Globals->MAINTENANCE_COST; - } else - i = men * Globals->MAINTENANCE_COST; - return i; - - } - - return 0; -} - -void Unit::Short(int needed, int hunger) -{ - int i, n = 0, levels; - - if (faction->IsNPC()) - return; // Don't starve monsters and the city guard! - - if (needed < 1 && hunger < 1) return; - - switch(Globals->SKILL_STARVATION) { - case GameDefs::STARVE_MAGES: - if(type == U_MAGE) SkillStarvation(); - return; - case GameDefs::STARVE_LEADERS: - if(IsLeader()) SkillStarvation(); - return; - case GameDefs::STARVE_ALL: - SkillStarvation(); - return; - } - - for (i = 0; i<= NITEMS; i++) { - if(!(ItemDefs[ i ].type & IT_MAN)) { - // Only men need sustenance. - continue; - } - - if(ItemDefs[i].type & IT_LEADER) { - // Don't starve leaders just yet. - continue; - } - - while (GetMen(i)) { - if (getrandom(100) < Globals->STARVE_PERCENT) { - SetMen(i, GetMen(i) - 1); - n++; - } - if (Globals->MULTIPLIER_USE == GameDefs::MULT_ALL) { - levels = SkillLevels(); - i = levels * Globals->MAINTENANCE_MULTIPLIER; - if (i < Globals->MAINTENANCE_COST) - i = Globals->MAINTENANCE_COST; - needed -= i; - } else - needed -= Globals->MAINTENANCE_COST; - hunger -= Globals->UPKEEP_MINIMUM_FOOD; - if (needed < 1 && hunger < 1) { - if (n) Error(AString(n) + " starve to death.", 0); - return; - } - } - } - - // Now starve leaders - for (int i = 0; i<= NITEMS; i++) { - if(!(ItemDefs[ i ].type & IT_MAN)) { - // Only men need sustenance. - continue; - } - - if (!(ItemDefs[i].type & IT_LEADER)) { - // now we're doing leaders - continue; - } - - while (GetMen(i)) { - if (getrandom(100) < Globals->STARVE_PERCENT) { - SetMen(i, GetMen(i) - 1); - n++; - } - if (Globals->MULTIPLIER_USE != GameDefs::MULT_NONE) { - levels = SkillLevels(); - i = levels * Globals->MAINTENANCE_MULTIPLIER; - if (i < Globals->LEADER_COST) - i = Globals->LEADER_COST; - needed -= i; - } else - needed -= Globals->LEADER_COST; - hunger -= Globals->UPKEEP_MINIMUM_FOOD; - if (needed < 1 && hunger < 1) { - if (n) Error(AString(n) + " starve to death.", 0); - return; - } - } - } -} - -int Unit::Weight() -{ - int retval = items.Weight(); - return retval; -} - -int Unit::FlyingCapacity() -{ - int cap = 0; - forlist(&items) { - Item *i = (Item *) elem; - cap += ItemDefs[i->type].fly * i->num; - } - - return cap; -} - -int Unit::RidingCapacity() -{ - int cap = 0; - forlist(&items) { - Item *i = (Item *) elem; - cap += ItemDefs[i->type].ride * i->num; - } - - return cap; -} - -int Unit::SwimmingCapacity() -{ - int cap = 0; - forlist(&items) { - Item *i = (Item *) elem; - cap += ItemDefs[i->type].swim * i->num; - } - - return cap; -} - -int Unit::WalkingCapacity() -{ - int cap = 0; - forlist(&items) { - Item *i = (Item *) elem; - cap += ItemDefs[i->type].walk * i->num; - if(ItemDefs[i->type].hitchItem != -1) { - int hitch = ItemDefs[i->type].hitchItem; - if(!(ItemDefs[hitch].flags & ItemType::DISABLED)) { - int hitches = items.GetNum(hitch); - int hitched = i->num; - if(hitched > hitches) hitched = hitches; - cap += hitched * ItemDefs[i->type].hitchwalk; - } - } - } - - return cap; -} - - - -int Unit::CanFly(int weight) -{ - if (FlyingCapacity() > 0 && FlyingCapacity() >= weight) return 1; //empty units don't fly - return 0; -} - -int Unit::CanReallySwim() -{ - if (SwimmingCapacity() > 0 && SwimmingCapacity() >= items.Weight()) return 1; - if (dead) return 1; //ARCADIA_MAGIC Patch (ghosts can remain after regions sink!) - return 0; -} - -int Unit::CanSwim() -{ - if(this->CanReallySwim()) - return 1; - if((Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) && this->CanFly()) - return 1; - return 0; -} - -int Unit::CanFly() -{ - int weight = items.Weight(); - return CanFly(weight); -} - -int Unit::CanRide(int weight) -{ - if (RidingCapacity() >= weight) return 1; - return 0; -} - -int Unit::CanWalk(int weight) -{ - if (WalkingCapacity() >= weight) return 1; - return 0; -} - -int Unit::TryToSwim() -//returns 1 if can swim, return 0 otherwise -{ - //In progress! - - switch(Globals->FLIGHT_OVER_WATER) { - case GameDefs::WFLIGHT_UNLIMITED: - if(CanSwim()) return 1; - //this is old behaviour, someone else can code new! - break; - - case GameDefs::WFLIGHT_MUST_LAND: - if(type == U_WMON && CanSwim()) return 1; //monsters that fly don't drown - if(leftShip) { - leftShip = 0; //no idea what this does - return 1; - } - //fall thru! - case GameDefs::WFLIGHT_NONE: - if(CanReallySwim()) return 1; - //we can't swim yet ... - if(SwimmingCapacity()) { - //but maybe we will be able to! - int tries = items.Num(); - while(tries-- > 0) { - int maxweight = 0; - int type = -1; - //pick the heaviest item to discard first. Ignore men - forlist(&items) { - Item *i = (Item *) elem; - if((ItemDefs[i->type].type & IT_MAN)) continue; - if((ItemDefs[i->type].weight - ItemDefs[i->type].swim) > maxweight) { - maxweight = ItemDefs[i->type].weight - ItemDefs[i->type].swim; - type = i->type; - } - } - if(type == -1) { - //only men left - forlist(&items) { - Item *i = (Item *) elem; - if((ItemDefs[i->type].weight - ItemDefs[i->type].swim) > maxweight) { - maxweight = ItemDefs[i->type].weight - ItemDefs[i->type].swim; - type = i->type; - } - } - } - if(type < 0) break; - int tolose = (items.Weight() - SwimmingCapacity() + maxweight - 1)/maxweight; //this is the number of our heaviest item we need to discard (need to round up). - //careful ... what if this is a man? - //Warning: if there are no swimming men in the unit this code might leave items but no men. Perhaps should discard all items before any men ... hmm. - if((ItemDefs[type].type & IT_MAN)) { - if(items.GetNum(type) <= tolose) { - tolose = items.GetNum(type); - SetMen(type,0); - } else SetMen(type, items.GetNum(type) - tolose); - Event(AString("Disbands ") + ItemString(type, tolose) + "."); - } else { - if(items.GetNum(type) <= tolose) { - tolose = items.GetNum(type); - items.SetNum(type,0); - } else items.SetNum(type, items.GetNum(type) - tolose); - Event(AString("Discards ") + ItemString(type, tolose) + "."); - } - - if(CanReallySwim()) return 1; - } - } - if(CanReallySwim()) return 1; //this shouldn't be needed; just being overly thorough - break; - default: // Should never happen - break; - } - return 0; -} - -int Unit::CanSeaFly() -{ - //this is a specific alternative to introducing a fifth movement class 'riding-at-sea' - int cap = 0; - forlist(&items) { - Item *i = (Item *) elem; - //if an item can both ride and swim, we assume it can ride at sea. - int seaflying = ItemDefs[i->type].swim; - if(ItemDefs[i->type].fly < seaflying) seaflying = ItemDefs[i->type].ride; - if(seaflying > 0) cap += seaflying * i->num; - } -/* - cap = ItemDefs[I_DOLPHIN].swim * items.GetNum(I_DOLPHIN); -*/ - if(cap >= items.Weight()) return 1; - return 0; -} - -int Unit::CanSeaRide() -{ - //this is a specific alternative to introducing a fifth movement class 'riding-at-sea' - int cap = 0; - forlist(&items) { - Item *i = (Item *) elem; - //if an item can both ride and swim, we assume it can ride at sea. - //if a mount can swim, we assume it can ride at sea - int seariding = ItemDefs[i->type].swim; - if(ItemDefs[i->type].ride < seariding && !(ItemDefs[i->type].type & IT_MOUNT)) seariding = ItemDefs[i->type].ride; - if(seariding > 0) cap += seariding * i->num; - } -/* - cap = ItemDefs[I_DOLPHIN].swim * items.GetNum(I_DOLPHIN); -*/ - if(cap >= items.Weight()) return 1; - return 0; -} - -int Unit::MoveType(ARegion *regionto) -{ - /* Check if we should be able to 'swim' */ - /* This should become it's own M_TYPE sometime */ - //we can swim if we are going to ocean from anywhere, or if we are going to land FROM ocean. - //likewise, if we are going to OR from ocean, and cannot swim, we cannot move even if we can walk and are going to land. - if((regionto && TerrainDefs[regionto->type].similar_type == R_OCEAN) || - TerrainDefs[object->region->type].similar_type == R_OCEAN) { - - if((Globals->FLIGHT_OVER_WATER != GameDefs::WFLIGHT_NONE) && this->CanFly()) return M_FLY; - - if(CanReallySwim()) { - if(CanSeaFly()) return M_FLY; - if(CanSeaRide()) return M_RIDE; - return M_WALK; - } - else return M_NONE; - } - - int weight = items.Weight(); - //do fake terrain for ARCADIAN_CHECKER patch. - if((regionto && TerrainDefs[regionto->type].similar_type == R_FAKE) || - TerrainDefs[object->region->type].similar_type == R_FAKE) { - //we're going between two fake regions or a fake and a land region. - if (CanFly(weight)) return M_FLY; - if (CanRide(weight)) return M_RIDE; - if (CanReallySwim()) { - if(CanSeaFly()) return M_FLY; - if(CanSeaRide()) return M_RIDE; - return M_WALK; - } - if (CanWalk(weight)) return M_WALK; - } - - if (CanFly(weight)) return M_FLY; - if (CanRide(weight)) return M_RIDE; - if (CanWalk(weight)) return M_WALK; - return M_NONE; -} - -int Unit::CalcMovePoints(ARegion *regionto) -{ - switch (MoveType(regionto)) { - case M_NONE: - return 0; - case M_WALK: - return Globals->FOOT_SPEED; - case M_RIDE: - return Globals->HORSE_SPEED; - case M_FLY: - return Globals->FLY_SPEED + GetAttribute("flying"); - } - return 0; -} - -int Unit::CanMoveTo(ARegion *r1, ARegion *r2) -{ -//moving to r1 from r2 - - if (r1 == r2) { - //hexside terrain mod. If the unit has advanced here, then subtract any modifiers due to edge terrain. - if(Globals->HEXSIDE_TERRAIN && advancefrom) { - int dir = -1; - for(int i=0; ineighbors[i] == r1) dir = i; - } - if(dir == -1) return 1; - Hexside *h = advancefrom->hexside[dir]; - crossbridge += HexsideDefs[h->type].advancepen; - if(h->road < 0) crossbridge += HexsideDefs[H_ROAD].advancepen; - if(h->bridge < 0) crossbridge += HexsideDefs[H_BRIDGE].advancepen; //this is going to suffer from the same problems described in atlantisdev post 6274, relating to movements with more than one advance command issued. - } - return 1; - } - - int exit = 1; - int i; - int dir; -//we seem to be checking the connection was 2-way ... but shouldn't we be subtracting the penalty even if one way? - for (i=0; ineighbors[i] == r2) { - exit = 0; - dir = i; - break; - } - } - if (exit) return 0; - exit = 1; - for (i=0; ineighbors[i] == r1) { - exit = 0; - if(!CanFly()) { - Hexside *h = r2->hexside[i]; - crossbridge += HexsideDefs[h->type].advancepen; - if(h->road < 0) crossbridge += HexsideDefs[H_ROAD].advancepen; - if(h->bridge < 0) crossbridge += HexsideDefs[H_BRIDGE].advancepen; - } - break; - } - } - if (exit) return 0; - - int mt = MoveType(r2); - if (((TerrainDefs[r1->type].similar_type == R_OCEAN) || - (TerrainDefs[r2->type].similar_type == R_OCEAN)) && - (!CanSwim() || GetFlag(FLAG_NOCROSS_WATER))) - return 0; - int mp = CalcMovePoints(r1) - movepoints; - int mc = r2->MoveCost(mt, r1, dir, 0); - if (mp < mc || mc < 0) return 0; //mc less than 0 means blocked from moving there. - return 1; -} - -int Unit::CanCatch(ARegion *r, Unit *u) -{ - return faction->CanCatch(r, u); -} - -int Unit::CanSee(ARegion *r, Unit *u, int practice) -{ - return faction->CanSee(r, u, practice); -} - -int Unit::AmtsPreventCrime(Unit *u) -{ - if(!u) return 0; - - int amulets = items.GetNum(I_AMULETOFTS); - if((u->items.GetNum(I_RINGOFI) < 1) || (amulets < 1)) return 0; - int men = GetMen(); - if(men <= amulets) return 1; - if(!Globals->PROPORTIONAL_AMTS_USAGE) return 0; - if(getrandom(men) < amulets) return 1; - return 0; -} - -int Unit::GetAttitude(ARegion *r, Unit *u) -{ - if (faction == u->faction) return A_ALLY; - int att = faction->GetAttitude(u->faction->num); - if (att >= A_FRIENDLY && att >= faction->defaultattitude) return att; - - if (CanSee(r, u) == 2) - return att; - else - return faction->defaultattitude; -} - -int Unit::Hostile() -{ - if (type != U_WMON) return 0; - int retval = 0; - forlist(&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MONSTER) { - MonType *mp = FindMonster(ItemDefs[i->type].abr, - (ItemDefs[i->type].type & IT_ILLUSION)); - int hos = mp->hostile; - if (hos > retval) retval = hos; - } - } - return retval; -} - -int Unit::Forbids(ARegion *r, Unit *u) -{ - if (guard != GUARD_GUARD) return 0; - if (!IsReallyAlive()) return 0; - if (!CanSee(r, u, Globals->SKILL_PRACTICE_AMOUNT > 0)) return 0; - if (!CanCatch(r, u)) return 0; - if (GetAttitude(r, u) < A_NEUTRAL) return 1; - return 0; -} - -/* This function was modified to either return the amount of - taxes this unit is eligible for (numtaxers == 0) or the - number of taxing men (numtaxers > 0). -*/ -int Unit::Taxers(int numtaxers) -{ - int totalMen = GetMen(); - int illusions = 0; - int creatures = 0; - int taxers = 0; - int basetax = 0; - int weapontax = 0; - int armortax = 0; - - // check out items - int numMelee= 0; - int numUsableMelee = 0; - int numBows = 0; - int numUsableBows = 0; - int numMounted= 0; - int numUsableMounted = 0; - int numMounts = 0; - int numUsableMounts = 0; - int numBattle = 0; - int numUsableBattle = 0; - int numArmor = 0; - - //added by BS - int spareMelee = 0; - - forlist (&items) { - Item *pItem = (Item *) elem; - BattleItemType *pBat = NULL; - - if ((ItemDefs[pItem->type].type & IT_BATTLE) && - ((pBat = FindBattleItem(ItemDefs[pItem->type].abr)) != NULL) && - (pBat->flags & BattleItemType::SPECIAL)) { - // Only consider offensive items - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_USABLE_BATTLE_ITEM) && - (!(pBat->flags & BattleItemType::MAGEONLY) || - type == U_MAGE || type == U_APPRENTICE)) { - numUsableBattle += pItem->num; - numBattle += pItem->num; - continue; // Don't count this as a weapon as well! - } - if (Globals->WHO_CAN_TAX & GameDefs::TAX_BATTLE_ITEM) { - numBattle += pItem->num; - continue; // Don't count this as a weapon as well! - } - } - - if (ItemDefs[pItem->type].type & IT_WEAPON) { - WeaponType *pWep = FindWeapon(ItemDefs[pItem->type].abr); - int num = pItem->num; - int numUse = 0; - int basesk = 0; - AString skname = pWep->baseSkill; - int sk = LookupSkill(&skname); - if (sk != -1) basesk = GetSkill(sk); - if (basesk == 0) { - skname = pWep->orSkill; - sk = LookupSkill(&skname); - if(sk != -1) basesk = GetSkill(sk); - } - /* - //use this bit if weapons that don't need a skill for combat shouldn't need one for taxing - if (!(pWep->flags & WeaponType::NEEDSKILL)) { - numUsableMelee += numUse; - numMelee += num; - } - */ - //added by BS - if (!(pWep->flags & WeaponType::NEEDSKILL)) { - spareMelee += num; //for BS mod these, with a horse and riding, allow taxation. - } - - if (basesk) { - numUse = num; - if (!(pWep->flags & WeaponType::NEEDSKILL)) { - numUsableMelee += numUse; - numMelee += num; - spareMelee -= num; //to avoid double counting; if here, these weapons are usable with the units skills already - } else if (pWep->flags & WeaponType::NOFOOT) { - numUsableMounted += numUse; - numMounted += num; - } else { - // Presume that anything else is a bow! - numUsableBows += pItem->num; - numBows += pItem->num; - } - } - } - - if (ItemDefs[pItem->type].type & IT_MOUNT) { - MountType *pm = FindMount(ItemDefs[pItem->type].abr); - if (pm->skill) { - AString skname = pm->skill; - int sk = LookupSkill(&skname); - if (pm->minBonus <= GetSkill(sk)) - numUsableMounts += pItem->num; - } else - numUsableMounts += pItem->num; - numMounts += pItem->num; - } - - if (ItemDefs[pItem->type].type & IT_MONSTER) { - if (ItemDefs[pItem->type].type & IT_ILLUSION) - illusions += pItem->num; - else - creatures += pItem->num; - } - - if (ItemDefs[pItem->type].type & IT_ARMOR) { - numArmor += pItem->num; - } - } - - - // Ok, now process the counts! - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_ANYONE) || - ((Globals->WHO_CAN_TAX & GameDefs::TAX_COMBAT_SKILL) && - GetSkill(S_COMBAT)) || - ((Globals->WHO_CAN_TAX & GameDefs::TAX_BOW_SKILL) && - (GetSkill(S_CROSSBOW) || GetSkill(S_LONGBOW))) || - ((Globals->WHO_CAN_TAX & GameDefs::TAX_RIDING_SKILL) && - GetSkill(S_RIDING)) || - ((Globals->WHO_CAN_TAX & GameDefs::TAX_STEALTH_SKILL) && - GetSkill(S_STEALTH))) { - basetax = totalMen; //ie in this case, everyone in the unit can tax. Not sure the bonus are right in complex situations though! -BS - taxers = totalMen; - - // Weapon tax bonus - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_ANYONE) || - ((Globals->WHO_CAN_TAX & GameDefs::TAX_COMBAT_SKILL) && - GetSkill(S_COMBAT)) || - ((Globals->WHO_CAN_TAX & GameDefs::TAX_STEALTH_SKILL) && - GetSkill(S_STEALTH))) { - if (numUsableMounted > numUsableMounts) { - weapontax = numUsableMounts; - } else { - weapontax = numUsableMounted; - } - weapontax += numMelee; - } - - if(((Globals->WHO_CAN_TAX & GameDefs::TAX_BOW_SKILL) && - (GetSkill(S_CROSSBOW) || GetSkill(S_LONGBOW)))) { - weapontax += numUsableBows; - } - if((Globals->WHO_CAN_TAX & GameDefs::TAX_RIDING_SKILL) && - GetSkill(S_RIDING)) { - if(weapontax < numUsableMounts) weapontax = numUsableMounts; - } - - } else { - - if (Globals->WHO_CAN_TAX & GameDefs::TAX_USABLE_WEAPON) { - if (numUsableMounted > numUsableMounts) { //numusablemounted is a weapon type - weapontax = numUsableMounts; - taxers = numUsableMounts; - numMounts -= numUsableMounts; - numUsableMounts = 0; - } else { - weapontax = numUsableMounted; - taxers = numUsableMounted; - numMounts -= numUsableMounted; - numUsableMounts -= numUsableMounted; - } - weapontax += numMelee + numUsableBows; //shouldn't this be numUsableMelee? Not that it matters since in the current incarnation numMelee = numUsableMelee, but still ... - taxers += numMelee + numUsableBows; - } else if (Globals->WHO_CAN_TAX & GameDefs::TAX_ANY_WEAPON) { - weapontax = numMelee + numBows + numMounted; - taxers = numMelee + numBows + numMounted; - } else { - if (Globals->WHO_CAN_TAX & - GameDefs::TAX_MELEE_WEAPON_AND_MATCHING_SKILL) { - if (numUsableMounted > numUsableMounts) { - weapontax += numUsableMounts; - taxers += numUsableMounts; - numMounts -= numUsableMounts; - numUsableMounts = 0; - } else { - weapontax += numUsableMounted; - taxers += numUsableMounted; - numMounts -= numUsableMounted; - numUsableMounts -= numUsableMounted; - } - weapontax += numUsableMelee; - taxers += numUsableMelee; - } - if (Globals->WHO_CAN_TAX & - GameDefs::TAX_BOW_SKILL_AND_MATCHING_WEAPON) { - weapontax += numUsableBows; - taxers += numUsableBows; - } - } - - if (Globals->WHO_CAN_TAX & GameDefs::TAX_HORSE) { - weapontax += numMounts; - taxers += numMounts; - } - else if (Globals->WHO_CAN_TAX & GameDefs::TAX_HORSE_AND_RIDING_SKILL) { - weapontax += numMounts; - taxers += numUsableMounts; - } - //BS mod - else if (Globals->WHO_CAN_TAX & GameDefs::TAX_HORSE_AND_RIDING_SKILL_AND_MELEE_WEAPON) { - //don't understand how the numMounts / numUsableMounts system works (or doesn't), so just doing this: - if(numUsableMounts > spareMelee) { - weapontax += spareMelee; - taxers += spareMelee; - } else { - weapontax += numUsableMounts; - taxers += numUsableMounts; - } - } - - if (Globals->WHO_CAN_TAX & GameDefs::TAX_BATTLE_ITEM) { - weapontax += numBattle; - taxers += numBattle; - } - else if (Globals->WHO_CAN_TAX & GameDefs::TAX_USABLE_BATTLE_ITEM) { - weapontax += numUsableBattle; - taxers += numUsableBattle; - } - - } - - // Ok, all the items categories done - check for mages taxing - if (type == U_MAGE) { - if (Globals->WHO_CAN_TAX & GameDefs::TAX_ANY_MAGE) { - basetax = totalMen; - taxers = totalMen; - } - else { - if (Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_COMBAT_SPELL) { - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_DAMAGE) && - SkillDefs[combat].flags & SkillType::DAMAGE) { - basetax = totalMen; - taxers = totalMen; - } - - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_FEAR) && - SkillDefs[combat].flags & SkillType::FEAR) { - basetax = totalMen; - taxers = totalMen; - } - - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_OTHER) && - SkillDefs[combat].flags & SkillType::MAGEOTHER) { - basetax = totalMen; - taxers = totalMen; - } - } else { - forlist(&skills) { - Skill *s = (Skill *)elem; - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_DAMAGE) && - SkillDefs[s->type].flags & SkillType::DAMAGE) { - basetax = totalMen; - taxers = totalMen; - break; - } - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_FEAR) && - SkillDefs[s->type].flags & SkillType::FEAR) { - basetax = totalMen; - taxers = totalMen; - break; - } - if ((Globals->WHO_CAN_TAX & GameDefs::TAX_MAGE_OTHER) && - SkillDefs[s->type].flags & SkillType::MAGEOTHER) { - basetax = totalMen; - taxers = totalMen; - break; - } - } - } - } - } - - armortax = numArmor; - - // Check for overabundance - if(weapontax > totalMen) weapontax = totalMen; - if(armortax > weapontax) armortax = weapontax; - - //added by BS - if(basetax > totalMen) basetax = totalMen; - - // Adjust basetax in case of weapon taxation - if(basetax < weapontax) basetax = weapontax; - - // Now check for an overabundance of tax enabling objects - if (taxers > totalMen) taxers = totalMen; - - // And finally for creatures - if (Globals->WHO_CAN_TAX & GameDefs::TAX_CREATURES) - basetax += creatures; - taxers += creatures; - if (Globals->WHO_CAN_TAX & GameDefs::TAX_ILLUSIONS) - basetax += illusions; - taxers += illusions; - - - if(numtaxers) return(taxers); - - int taxes = Globals->TAX_BASE_INCOME * basetax - + Globals->TAX_BONUS_WEAPON * weapontax - + Globals->TAX_BONUS_ARMOR * armortax; - return(taxes); -} - -int Unit::GetFlag(int x) -{ - return (flags & x); -} - -void Unit::SetFlag(int x, int val) -{ - if (val) - flags = flags | x; - else - if (flags & x) flags -= x; -} - -void Unit::CopyFlags(Unit *x) -//This is currently used only for FORM orders. May have to modify it to use for anything else. -BS -{ - flags = x->flags; - if(x->guard == GUARD_AVOID) guard = GUARD_AVOID; //Arcadia mod; guard and autotax do not get carried over. - else guard = GUARD_NONE; - SetFlag(FLAG_AUTOTAX, 0); - //BS mod: - SetFlag(FLAG_VISIB, 0); - SetFlag(FLAG_INVIS, 0); - SetFlag(FLAG_COMMANDER, 0); -/* if (x->Taxers(1)) { - if (x->guard != GUARD_SET && x->guard != GUARD_ADVANCE) - guard = x->guard; - } else { - SetFlag(FLAG_AUTOTAX, 0); - }*/ - reveal = x->reveal; -} - -int Unit::GetBattleItem(AString &itm) -{ - int item = LookupItem(&itm); - if (item == -1) return -1; - - int num = items.GetNum(item); - if (num < 1) return -1; - - if (!(ItemDefs[item].type & IT_BATTLE)) return -1; - // Exclude weapons. They will be handled later. - if (ItemDefs[item].type & IT_WEAPON) return -1; - items.SetNum(item, num - 1); - return item; -} - -int Unit::GetArmor(AString &itm, int ass) -{ - int item = LookupItem(&itm); - ArmorType *pa = FindArmor(itm.Str()); - - if (pa == NULL) return -1; - //if assassination, and armour is not useinassassinate, and unit is attacker or armour is no definassassinate (BS mod) - if (ass && !(pa->flags & ArmorType::USEINASSASSINATE) && (ass == 2 || !(pa->flags & ArmorType::DEFINASSASSINATE) ) ) return -1; - - int num = items.GetNum(item); - if (num < 1) return -1; - - if (!(ItemDefs[item].type & IT_ARMOR)) return -1; - items.SetNum(item, num - 1); - return item; -} - -int Unit::GetMount(AString &itm, int canFly, int canRide, int ocean, int &bonus, int &type) -{ - - bonus = 0; - - int item = LookupItem(&itm); - MountType *pMnt = FindMount(itm.Str()); - - if(ocean) { - //if this mount can swim in ocean, we can ride here - if(ItemDefs[item].swim) canRide = 1; - //otherwise; normal behaviour (ie no riding in Xan) - } else { - //if we can't ride, we can't ride. - if(!ItemDefs[item].ride) canRide = 0; - //otherwise, normal behaviour - } - - // This region doesn't allow riding or flying, so no mounts, bail - if(!canFly && !canRide) return -1; - - //we can either fly or swim - int num = items.GetNum(item); - if (num < 1) return -1; - - if (canFly) { - // If the mount cannot fly, and the region doesn't allow - // riding mounts, bail - if (!ItemDefs[item].fly && !canRide) return -1; - } /*else { - // This region allows riding mounts, so if the mount - // can not carry at a riding level, bail - if (!ItemDefs[item].ride && !ItemDefs[item].swim) return -1; - }*/ - - if (pMnt->skill) { - AString skname = pMnt->skill; - int sk = LookupSkill(&skname); - bonus = GetSkill(sk); - if(bonus < pMnt->minBonus) { - // Unit isn't skilled enough for this mount - bonus = 0; - return -1; - } - // Limit to max mount bonus; - if(bonus > pMnt->maxBonus) bonus = pMnt->maxBonus; - - if(ItemDefs[item].fly) type = 4; - else type = 2; - - // If the mount can fly and the terrain doesn't allow - // flying mounts, limit the bonus to the maximum hampered - // bonus allowed by the mount - if(ItemDefs[item].fly && !canFly) { - if(bonus > pMnt->maxHamperedBonus) - bonus = pMnt->maxHamperedBonus; - type = 2; - } - - // Practice the mount's skill - Practice(sk); - } - - // Get the mount - items.SetNum(item, num - 1); - return item; -} - -int Unit::GetWeapon(AString &itm, int riding, int ridingBonus, - int &attackBonus, int &defenseBonus, int &attacks) -{ - int item = LookupItem(&itm); - WeaponType *pWep = FindWeapon(itm.Str()); - - if (pWep == NULL) return -1; - - int num = items.GetNum(item); - if (num < 1) return -1; - - if (!(ItemDefs[item].type & IT_WEAPON)) return -1; - - attackBonus = 0; - defenseBonus = 0; - attacks = 1; - - // Found a weapon, check flags and skills - int baseSkillLevel = CanUseWeapon(pWep, riding); - // returns -1 if weapon cannot be used, else the usable skill level - if(baseSkillLevel == -1) return -1; - - // Attack and defense skill - attackBonus = baseSkillLevel + pWep->attackBonus; - if(pWep->flags & WeaponType::NOATTACKERSKILL) - defenseBonus = pWep->defenseBonus; - else - defenseBonus = baseSkillLevel + pWep->defenseBonus; - // Riding bonus - if(pWep->flags & WeaponType::RIDINGBONUS) attackBonus += ridingBonus; - if(pWep->flags & (WeaponType::RIDINGBONUSDEFENSE|WeaponType::RIDINGBONUS)) - defenseBonus += ridingBonus; - // Number of attacks - attacks = pWep->numAttacks; - // Note: NUM_ATTACKS_SKILL must be > NUM_ATTACKS_HALF_SKILL - if(attacks >= WeaponType::NUM_ATTACKS_SKILL) - attacks += baseSkillLevel - WeaponType::NUM_ATTACKS_SKILL; - else if(attacks >= WeaponType::NUM_ATTACKS_HALF_SKILL) - attacks += (baseSkillLevel +1)/2 - WeaponType::NUM_ATTACKS_HALF_SKILL; - // Sanity check - if(attacks == 0) attacks = 1; - - // get the weapon - items.SetNum(item, num-1); - return item; -} - -void Unit::MoveUnit(Object *toobj) -{ - if(object) object->units.Remove(this); - object = toobj; - if(object) object->units.Add(this); -} - -void Unit::Event(const AString & s) -{ - AString temp = *name + ": " + s; - faction->Event(temp); -} - -void Unit::Error(const AString & s, int quiet) -{ - if(quiet) { - if(Globals->SUPPRESS_ERRORS == GameDefs::SHOW_AS_EVENTS) { - Event(s); - return; - } else if(Globals->SUPPRESS_ERRORS == GameDefs::SUPPRESS_ALL) return; - } - AString temp = *name + ": " + s; - faction->Error(temp); -} - -void Unit::Message(const AString & s) -{ - faction->Message(s); -} - -int Unit::GetAttribute(char *attrib) -{ - AttribModType *ap = FindAttrib(attrib); - if(ap == NULL) return 0; - AString temp; - int base = 0; - int bonus = 0; - int monbase = -1; - int monbonus = 0; - - if (ap->flags & AttribModType::CHECK_MONSTERS) { - forlist (&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MONSTER) { - MonType *mp = FindMonster(ItemDefs[i->type].abr, - (ItemDefs[i->type].type & IT_ILLUSION)); - int val = 0; - temp = attrib; - if (temp == "observation") val = mp->obs; - else if (temp == "stealth") val = mp->stealth; - else if (temp == "tactics") val = mp->tactics; - else continue; - if (monbase == -1) monbase = val; - else if (ap->flags & AttribModType::USE_WORST) - monbase = (val < monbase) ? val : monbase; - else - monbase = (val > monbase) ? val : monbase; - } - } - } - - for(int index = 0; index < 6; index++) { //BS mod 5 to 6 to expand stealth. - int val = 0; - int valuestored = 0; - if (ap->mods[index].flags & AttribModItem::SKILL) { - temp = ap->mods[index].ident; - int sk = LookupSkill(&temp); - val = GetRealSkill(sk); - valuestored = 1; - if(val > 0) { - if (ap->mods[index].modtype == AttribModItem::UNIT_LEVEL_HALF) { - val = ((val + 1)/2) * ap->mods[index].val; - } else if (ap->mods[index].modtype == AttribModItem::CONSTANT) { - val = ap->mods[index].val; - } else { - val *= ap->mods[index].val; - } - } - } else if (ap->mods[index].flags & AttribModItem::ITEM) { - val = 0; - temp = ap->mods[index].ident; - int item = LookupItem(&temp); - if (item != -1) { - valuestored = 1; - if (ap->mods[index].flags & AttribModItem::PERMAN) { - int men = GetMen(); - if (men <= items.GetNum(item)) - val = ap->mods[index].val; - } else { - if (items.GetNum(item) > 0) - val = ap->mods[index].val; - } - } - } else if (ap->mods[index].flags & AttribModItem::FLAGGED) { - temp = ap->mods[index].ident; - if (temp == "invis" && GetFlag(FLAG_INVIS)) { - val = ap->mods[index].val; - valuestored = 1; - } - if (temp == "visib" && GetFlag(FLAG_VISIB)) { - val = ap->mods[index].val; - valuestored = 1; - } - if (temp == "guard" && guard == GUARD_GUARD) { - val = ap->mods[index].val; - valuestored = 1; - } - } - if (ap->mods[index].flags & AttribModItem::NOT) - val = ((val == 0) ? ap->mods[index].val : 0); - if (valuestored && ap->mods[index].modtype == AttribModItem::FORCECONSTANT) - return val; - // Only flags can add to monster bonuses - if (ap->mods[index].flags & AttribModItem::FLAGGED) { - if (ap->flags & AttribModType::CHECK_MONSTERS) monbonus += val; - } - if (ap->mods[index].flags & AttribModItem::CUMULATIVE) - base += val; - else if (val > bonus) bonus = val; - } - - base += bonus; - - if (monbase != -1) { - monbase += monbonus; - if (ap->flags & AttribModType::USE_WORST) - base = (monbase < base) ? monbase : base; - else - base = (monbase > base) ? monbase : base; - } - return base; -} - -int Unit::PracticeAttribute(char *attrib) -{ - AttribModType *ap = FindAttrib(attrib); - if(ap == NULL) return 0; - for(int index = 0; index < 5; index++) { - if (ap->mods[index].flags & AttribModItem::SKILL) { - AString temp = ap->mods[index].ident; - int sk = LookupSkill(&temp); - if (sk != -1) - if (Practice(sk)) return 1; - } - } - return 0; -} - -int Unit::GetProductionBonus(int item) -{ - int bonus = 0; - if (ItemDefs[item].mult_item != -1) - bonus = items.GetNum(ItemDefs[item].mult_item); - else - bonus = GetMen(); - if (bonus > GetMen()) bonus = GetMen(); - return bonus * ItemDefs[item].mult_val; -} - -int Unit::SkillLevels() -{ - int levels = 0; - forlist(&skills) { - Skill *s = (Skill *)elem; - levels += GetLevelByDays(s->days/GetMen(),s->experience/GetMen()); - } - return levels; -} - -Skill *Unit::GetSkillObject(int sk) -{ - forlist(&skills) { - Skill *s = (Skill *)elem; - if(s->type == sk) - return s; - } - return NULL; -} - -void Unit::SkillStarvation() -{ - int can_forget[NSKILLS]; - int count = 0; - int i; - for(i = 0; i < NSKILLS; i++) { - if(SkillDefs[i].flags & SkillType::DISABLED) { - can_forget[i] = 0; - continue; - } - if(GetSkillObject(i)) { - can_forget[i] = 1; - count++; - } else { - can_forget[i] = 0; - } - } - for(i = 0; i < NSKILLS; i++) { - if (!can_forget[i]) continue; - Skill *si = GetSkillObject(i); - for(int j=0; j < NSKILLS; j++) { - if(SkillDefs[j].flags & SkillType::DISABLED) continue; - Skill *sj = GetSkillObject(j); - if(!sj) continue; // prevents a crash if a unit doesn't know all the prerequisites. - int dependancy_level = 0; - unsigned int c; - for(c=0;c < sizeof(SkillDefs[i].depends)/sizeof(SkillDepend);c++) { - AString skname = SkillDefs[i].depends[c].skill; - if (skname == SkillDefs[j].abbr) { - dependancy_level = SkillDefs[i].depends[c].level; - break; - } - } - if(dependancy_level > 0) { - if(GetLevelByDays(sj->days) == GetLevelByDays(si->days)) { //REAL_EXPERIENCE Patch: No change because go by study days only here. No starvation of experience? - can_forget[j] = 0; - count--; - } - } - } - } - if(!count) { - forlist(&items) { - Item *i = (Item *)elem; - if(ItemDefs[i->type].type & IT_MAN) { - count += items.GetNum(i->type); - items.SetNum(i->type, 0); - } - } - AString temp = AString(count) + " starve to death."; - Error(temp, 0); - return; - } - count = getrandom(count)+1; - for(i = 0; i < NSKILLS; i++) { - if(can_forget[i]) { - if(--count == 0) { - Skill *s = GetSkillObject(i); - AString temp = AString("Starves and forgets one level of ")+ - SkillDefs[i].name + "."; - Error(temp, 0); - switch(GetLevelByDays(s->days)) { - case 1: - s->days -= 30; - if(s->days <= 0) - ForgetSkill(i); - break; - case 2: - s->days -= 60; - break; - case 3: - s->days -= 90; - break; - case 4: - s->days -= 120; - break; - case 5: - s->days -= 150; - break; - } - } - } - } - return; -} - -int Unit::CanUseWeapon(WeaponType *pWep, int riding) -{ - if (riding == -1) { - if(pWep->flags & WeaponType::NOFOOT) return -1; - } else { - if(pWep->flags & WeaponType::NOMOUNT) return -1; - } - return CanUseWeapon(pWep); -} - -int Unit::CanUseWeapon(WeaponType *pWep) -{ - int baseSkillLevel = 0; - int tempSkillLevel = 0; - - int bsk, orsk; - AString skname; - if (pWep->baseSkill != NULL) { - skname = pWep->baseSkill; - bsk = LookupSkill(&skname); - if (bsk != -1) baseSkillLevel = GetSkill(bsk); - } - - if (pWep->orSkill != NULL) { - skname = pWep->orSkill; - orsk = LookupSkill(&skname); - if (orsk != -1) tempSkillLevel = GetSkill(orsk); - } - - if(tempSkillLevel > baseSkillLevel) { - baseSkillLevel = tempSkillLevel; - Practice(orsk); - } else - Practice(bsk); - - if(pWep->flags & WeaponType::NEEDSKILL && !baseSkillLevel) return -1; - - return baseSkillLevel; -} - -int Unit::GetEnergy(int transferring) -{ -//this should be used when checking a mages energy after the move phase but before the maintenance phase - eg during combat or teleportation. - if(transferred == 0 && transferring == 0) return energy; - transferring += transferred; -//for consistency, the cost here must match the cost in Unit::EnergyRecharge(). These could perhaps be combined into a new method. - if(dead) return -1; - int skill = GetSkill(S_CREATE_PORTAL); - if(skill < 1) skill = 1; - int cost = (transferring + 40 * skill - 1) / (40 * skill); - - return (energy - cost); -} - -void Unit::SetMoney(int n) -{ - items.SetNum(I_SILVER, n); -} - -int Unit::GetMoney() -{ - return items.GetNum(I_SILVER); -} - - -int Unit::GetSharedNum(int item) -{ - if(item < 0 || item > NITEMS) return 0; - int count = 0; - - if (ItemDefs[item].type & IT_MAN) - return items.GetNum(item); - - forlist((&object->region->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if ((u == this) || - (u->faction == faction && u->GetFlag(FLAG_SHARING))) - count += u->items.GetNum(item); - } - } - - return count; -} - -int Unit::GetSharedNum(int item, int quantity) -{ - if(item < 0 || item > NITEMS) return 0; - //speed optimiser: - if(items.GetNum(item) >= quantity) return 1; - //else - if(GetSharedNum(item) >= quantity) return 1; - return 0; -} - -int Unit::ConsumeShared(int item, int n) -{ - if(item < 0 || item > NITEMS) return 0; - if(!GetSharedNum(item,n)) return 0; - - if (items.GetNum(item) >= n) { - // This unit doesn't need to use shared resources - items.SetNum(item, items.GetNum(item) - n); - return 1; - } - - // Use up items carried by the using unit first - n -= items.GetNum(item); - items.SetNum(item, 0); - - forlist((&object->region->objects)) { - Object *obj = (Object *) elem; - forlist((&obj->units)) { - Unit *u = (Unit *) elem; - if (u->faction == faction && u->GetFlag(FLAG_SHARING)) { - if (u->items.GetNum(item) < 1) - continue; - if (u->items.GetNum(item) >= n) { - u->items.SetNum(item, u->items.GetNum(item) - n); - u->Event(AString("Shares ") + ItemString(item, n) + - " with " + *name + "."); - return 1; - } - u->Event(AString("Shares ") + - ItemString(item, u->items.GetNum(item)) + - " with " + *name + "."); - n -= u->items.GetNum(item); - u->items.SetNum(item, 0); - } - } - } - return 1; -} - -int Unit::GetSharedMoney() -{ - return GetSharedNum(I_SILVER); -} - -int Unit::GetSharedMoney(int quantity) -{ - return (GetSharedNum(I_SILVER) >= quantity); -} - -int Unit::ConsumeSharedMoney(int n) -{ - return ConsumeShared(I_SILVER, n); -} - -int Unit::GetEthnicity() -{ - int racetype = -1; - - forlist(&items) { - Item *i = (Item *) elem; - if (ItemDefs[i->type].type & IT_MAN) { - ManType *mt = FindRace(ItemDefs[i->type].abr); - if(racetype < 0) racetype = mt->ethnicity; - else if(racetype != mt->ethnicity) return RA_MIXED; - } - } - if(racetype < 0) return RA_NA; - - return racetype; -} - -int Unit::GetSeniority() -{ - //no functional effect, just decides who leads an army - int score = 0; - switch(type) { - case U_MAGE: - case U_GUARDMAGE: - score += 30; - break; - case U_APPRENTICE: - score += 20; - break; - case U_LEADER: - case U_GUARD: - score += 10; - break; - case U_SPECIALIST: - score += 5; - break; - default: - break; - } - if(flags & FLAG_COMMANDER) score += 40; - score += GetSkill(S_COMBAT) + GetSkill(S_LONGBOW) + GetSkill(S_CROSSBOW) + - GetSkill(S_HEALING) + 2*GetSkill(S_BASE_BATTLETRAINING) + - 2*GetSkill(S_TOUGHNESS) + 2*GetSkill(S_FRENZY) + - GetSkill(S_OBSERVATION) + GetSkill(S_STEALTH); - if (combat != -1) score += 3*GetSkill(combat); - score += getrandom(2+score/5); - return score; -} diff --git a/arcadia/unit.h b/arcadia/unit.h deleted file mode 100644 index ea623eae8..000000000 --- a/arcadia/unit.h +++ /dev/null @@ -1,371 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2000/MAR/14 Larry Stanbery Replaced specfic skill bonus functions with -// generic function. -// Added function to compute production bonus. -// 2001/FEB/07 Joseph Traub Changes to allow mage support for city guards. -// 2001/Feb/18 Joseph Traub Added support for Apprentices. -// 2001/Feb/25 Joseph Traub Added a flag preventing units from crossing -// water. - -#ifndef UNIT_CLASS -#define UNIT_CLASS - -class Unit; -class UnitId; - -#include "faction.h" -#include "alist.h" -#include "gameio.h" -#include "orders.h" -#include "fileio.h" -#include "skills.h" -#include "items.h" -#include "object.h" - -enum { - GUARD_NONE, - GUARD_GUARD, - GUARD_AVOID, - GUARD_SET, - GUARD_ADVANCE -}; - -enum { - TAX_NONE, - TAX_TAX, - TAX_PILLAGE, - TAX_AUTO, -}; - -enum { - REVEAL_NONE, - REVEAL_UNIT, - REVEAL_FACTION -}; - -enum { - TACTICS_NONE, - TACTICS_DEFENSIVE, - TACTICS_AGGRESSIVE -}; - -enum { - U_NORMAL, - U_SPECIALIST, - U_LEADER, - U_MAGE, - U_GUARD, - U_WMON, - U_GUARDMAGE, - U_APPRENTICE, - NUNITTYPES -}; - -#define MAX_READY 4 // maximum number of ready weapons or armors - -#define FLAG_BEHIND 0x0001 -#define FLAG_NOCROSS_WATER 0x0002 -#define FLAG_AUTOTAX 0x0004 -#define FLAG_HOLDING 0x0008 -#define FLAG_NOAID 0x0010 -#define FLAG_INVIS 0x0020 -#define FLAG_CONSUMING_UNIT 0x0040 -#define FLAG_CONSUMING_FACTION 0x0080 -#define FLAG_NOSPOILS 0x0100 -#define FLAG_FLYSPOILS 0x0200 -#define FLAG_WALKSPOILS 0x0400 -#define FLAG_RIDESPOILS 0x0800 -#define FLAG_SWIMSPOILS 0x1000 -#define FLAG_SAILSPOILS 0x2000 -#define FLAG_FIGHTASFOOT 0x4000 -#define FLAG_FIGHTASRIDE 0x8000 -#define FLAG_VISIB 0x10000 -#define FLAG_SHARING 0x20000 -#define FLAG_COMMANDER 0x40000 - - -class UnitId : public AListElem { - public: - UnitId(); - ~UnitId(); - AString Print(); - - int unitnum; /* if 0, it is a new unit */ - int alias; - int faction; -}; - -class UnitPtr : public AListElem { - public: - Unit * ptr; -}; -UnitPtr *GetUnitList(AList *, Unit *); - -class Unit : public AListElem -{ - public: - Unit(); - Unit(int,Faction *,int = 0); - ~Unit(); - - void SetMonFlags(); - void MakeWMon(char *,int,int); - - void Writeout( Aoutfile *f ); - void Readin( Ainfile *f, AList *, ATL_VER v ); - - AString SpoilsReport(void); - int CanGetSpoil(Item *i); - void WriteReport(Areport *,int,int,int,int, int); - AString GetName(int); - AString MageReport(); - AString ReadyItem(); - AString StudyableSkills(); - AString * BattleReport(int); - AString TemplateReport(); - - void ClearOrders(); - void SafeClearOrders(); // Needed for Arcadia mages. - void AddCastOrder(CastOrder *order); //in spells.cpp, arcadian addition - void ClearCastOrder(); - void ClearTeleportOrders(); - void DefaultOrders(Object *, int peasantfac=0); - void SetName(AString *); - void SetDescribe(AString *); - void SetLabel(AString *); - void PostTurn(ARegion *reg); - - int IsMage(); - int IsLeader(); - int IsNormal(); - int GetMons(); - int GetMen(); -// int GetLeaders(); - int GetSoldiers(); - int GetRealSoldiers(); //excludes illusions - int GetMen(int); - void SetMen(int,int); - int GetMoney(); - void SetMoney(int); - int IsAlive(); - int IsReallyAlive(); //introduced for Arcadia. - int IsStationary(); //introduced for SEND - int GetEthnicity(); - - int MaintCost(); - void Short(int, int); - int SkillLevels(); - void SkillStarvation(); - Skill *GetSkillObject(int); - int AgeDead(); //ARCADIA_MAGIC patch - - int GetAttackRiding(); - int GetDefenseRiding(); - - // - // These are rule-set specific, in extra.cpp. - // - // LLS - int GetAttribute(char *ident); - int PracticeAttribute(char *ident); - int GetProductionBonus(int); - -/* Do study stuff so experience gets learnt after study. - Do production/combat/riding/stealth stuff so total level used. - Do experience learning - */ - - int GetSkill(int); //returns zero if skill is disabled - void SetSkill(int,int); - void SetSkill(int,int,int); /* REAL_EXPERIENCE Patch */ - int IsASpeciality(int skill); - int GetSkillKnowledgeMax(int); - int GetSkillExperMax(int); /* REAL_EXPERIENCE Patch */ - int GetRealSkill(int); - int GetDaysSkill(int); - int GetExperSkill(int); - void ForgetSkill(int); - int CheckDepend(int,SkillDepend &s); - int CanStudy(int); - int Study(int,int, int quiet = 0, int overflow = 1); /* Returns 1 if it succeeds */ - void Experience(int sk,int exp,int group = 1, int dividenonspecials = 1); //if(group), multiplies experience by nummen. - int Practice(int); - void AdjustSkills(int overflow = 0); - - /* Return 1 if can see, 2 if can see faction */ - int CanSee(ARegion *,Unit *, int practice = 0); - int CanCatch(ARegion *,Unit *); - int AmtsPreventCrime(Unit *); - int GetAttitude(ARegion *,Unit *); /* Get this unit's attitude toward - the Unit parameter */ - int Hostile(); - int Forbids(ARegion *,Unit *); - int Weight(); - int FlyingCapacity(); - int RidingCapacity(); - int SwimmingCapacity(); - int WalkingCapacity(); - int CanFly(int); - int CanRide(int); - int CanWalk(int); - int CanFly(); - int CanSwim(); - int CanReallySwim(); - int TryToSwim(); - int CanSeaFly(); - int CanSeaRide(); - int MoveType(ARegion *regionto = NULL); - int CalcMovePoints(ARegion *reg); - int CanMoveTo(ARegion *,ARegion *); - int GetFlag(int); - void SetFlag(int,int); - void CopyFlags(Unit *); - int GetBattleItem(AString &itm); - int GetArmor(AString &itm, int ass); - int GetMount(AString &itm, int canFly, int canRide, int ocean, int &bonus, int &type); - int GetWeapon(AString &itm, int riding, int ridingBonus, - int &attackBonus, int &defenseBonus, int &attacks); - int CanUseWeapon(WeaponType *pWep, int riding); - int CanUseWeapon(WeaponType *pWep); - int Taxers(int); - - void MoveUnit( Object *newobj ); - int HasBoat(ARegion *reg); //in runorders.cpp - - void Event(const AString &); - void Error(const AString &, int quiet = 0); - void Message(const AString &); //BS mod - - Faction *faction; - Faction *formfaction; - Object *object; - AString *name; - AString *describe; - AString *label; - int num; - int type; - int GetEnergy(int transferring = 0); - int energy; // this is only for mages in ARCADIA_MAGIC - int dead; // this is only for mages in ARCADIA_MAGIC - int resurrects; // this is only for mages in ARCADIA_MAGIC - int mastery; // this is only for mages in ARCADIA_MAGIC - int transferred; //this is for portal mages in ARCADIA_MAGIC. It need not be saved in the gamefile; should be reset to zero every month. - int foggy; // Has this unit got fog following him around? - int MaxEnergy(); // this is only for mages in ARCADIA_MAGIC - int EnergyRecharge(); - int EnergyMaintenance(int maxallowed); - int MysticEvent(); // returns 0 if no mystic event, or 1-4 if there is (4 most serious). - int GetCastCost(int spell, int extracost, int multiplier = 1, int levelpenalty = 0); - int GetCombatCost(int spell, int multiplier = 1); - int GetFirstCombatCost(int spell, int multiplier = 1); - void WanderingExperience(int message); - int GetSeniority(); - - int alias; - int gm_alias; /* used for gm manual creation of new units */ - int guard; /* Also, avoid- see enum above */ - int reveal; - int tactics; - int flags; - int taxing; - int movepoints; - int canattack; - int nomove; - SkillList skills; - ItemList items; - ItemList itemsintransit; - int combat; - int readyItem; - int readyWeapon[MAX_READY]; - int readyArmor[MAX_READY]; - AList oldorders; - int needed; /* For assessing maintenance */ - int hunger; - int stomach_space; - int losses; - int free; - int practiced; // Has this unit practiced a skill this turn - //three terms for Arcadian economy spells - int numtraded; //total value of trades made - int nummerchanted; - int numquartermastered; - - int crossbridge; //Used in combat code to see if a unit needs to cross a bridge to get to a combat. Set to zero in Game::GetSides. - int movementmalus; - int marker; //use wherever, clear before using. - void CrossHexside(ARegion *from, ARegion *to); - - //Set of routines to allow sharing of items/money between units, when wanted. - int GetSharedNum(int); - int GetSharedNum(int, int); - int ConsumeShared(int,int); - int GetSharedMoney(); - int GetSharedMoney(int); //returns 1 if the unit has access to at least the specified money - int ConsumeSharedMoney(int); - - /* Orders */ - int destroy; - int enter; - Object *build; - int leftShip; - UnitId *promote; - int promotequiet; - AList typeorders; //list of pointers to AStrings. Rest are lists of orders - AList findorders; - AList giveorders; - AList sendorders; - AList withdraworders; - AList wishdraworders; - AList wishskillorders; - AList bankorders; - AList buyorders; - AList sellorders; - AList forgetorders; - AList castlistorders; - CastOrder *activecastorder; - TeleportOrder *teleportorders; - Order *stealorders; - Order *monthorders; - StudyOrder *herostudyorders; - AttackOrder *attackorders; - EvictOrder *evictorders; - ARegion *advancefrom; - - AList exchangeorders; - AList turnorders; - int inTurnBlock; - Order *presentMonthOrders; - int presentTaxing; - AList transportorders; - Unit *former; - - AList gavemento; //list of unitid's. -}; - -#endif diff --git a/arcadia/world.cpp b/arcadia/world.cpp deleted file mode 100644 index 99a125499..000000000 --- a/arcadia/world.cpp +++ /dev/null @@ -1,2628 +0,0 @@ -// START A3HEADER -// -// This source file is part of the Atlantis PBM game program. -// Copyright (C) 1995-1999 Geoff Dunbar -// -// 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, in the file license.txt. If not, write -// to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -// Boston, MA 02111-1307, USA. -// -// See the Atlantis Project web page for details: -// http://www.prankster.com/project -// -// END A3HEADER -// MODIFICATIONS -// Date Person Comments -// ---- ------ -------- -// 2000/SEP/06 Joseph Traub Added base man cost to allow races to have -// different base costs -#include "game.h" -#include "gamedata.h" - -// Make sure this is correct. The default is 1000 towns and 1000 regions. -#define NUMBER_OF_TOWNS 1000 - -static char *regionnames[] = -{ - "A'irhin", - "A'vespol", - "Abernecht", - "Abernethy", - "Abeuton", - "Abrenton", - "Achash", - "Achoep't", - "Achydale", - "Ackisse", - "Adem", - "Adoen'ph", - "Agemos", - "Aigiaton", - "Aikoburg", - "Aildadale", - "Aisheaberg", - "Alabrin-a-grim", - "Alabrin-a-karak", - "Alabrin-a-thol", - "Alabrin-ban", - "Alabrin-dor", - "Alabrin-killuk", - "Alabrin-lum", - "Alabrin-tor", - "Alabrin-ungol", - "Aleberg", - "Alettin", - "Aleuld", - "Aleym", - "Altenarchen", - "Altengrad", - "Altenheim", - "Altenhowe", - "Altenmar", - "Altenmark", - "Altenmeir", - "Altenten", - "Altenvoltan", - "Aman-a-gun", - "Aman-a-karak", - "Aman-a-lin", - "Aman-dor", - "Aman-killuk", - "Aman-krag", - "Aman-tor", - "Aman-ungol", - "Anneeton", - "Ar'lor", - "Ardden", - "Ardeton", - "Ardorm", - "Ardvale", - "Arouton", - "Arreydale", - "Asaberg", - "Asend", - "Ashdim", - "Askul-a-grim", - "Askul-a-luk", - "Askul-a-menak", - "Askul-dum", - "Askul-tor", - "Askul-ungol", - "Asouton", - "Asyust", - "Athatgost", - "Athbrod", - "Athbrodtor", - "Athbroduen", - "Athdor", - "Athen", - "Athfin", - "Athfindor", - "Atoodale", - "Aubuiville", - "Aughsale", - "Auqeiberg", - "Aweville", - "Awych", - "Aynedale", - "Ayrayberg", - "Bach", - "Baeshieton", - "Bal-a-menak", - "Bal-ban", - "Bal-dor", - "Bal-kai", - "Bal-krag", - "Banon", - "Banyc", - "Bekr", - "Beldani", - "Beldorf", - "Belelt", - "Belfelt", - "Belgrad", - "Belholm", - "Belmar", - "Belport", - "Belten", - "Belvoltan", - "Benlech", - "Berriedale", - "Bi-bet", - "Bihat", - "Blelscha", - "Bleuroiberg", - "Bochest", - "Boseedale", - "Bray-whoed", - "Breuneuburg", - "Breunt", - "Brilr", - "Brimathanwe", - "Brimaund", - "Brimdiadel", - "Brimdor", - "Brimfinanfel", - "Brimfinin", - "Brimgoldon", - "Brimgost", - "Brimloroth", - "Brimoldon", - "Brimsordon", - "Brimsormar", - "Brimthanund", - "Brok-ban", - "Brupque", - "Bugblod", - "Bugburg", - "Buk-a-for", - "Buk-a-grim", - "Buk-a-gun", - "Buk-a-luk", - "Buk-a-menak", - "Buk-a-thol", - "Buk-kai", - "Buk-mun", - "Buk-tor", - "Bulss", - "Burbruk", - "Burdan", - "Burdotn", - "Burer", - "Burfeld", - "Burhate", - "Burheimport", - "Burmark", - "Burmund", - "Burn", - "Burrgtur", - "Burscough", - "Burten", - "Burvoltan", - "Busst", - "By-loep", - "Byvneld", - "Cay-rouc", - "Cedaiburg", - "Ceiqoeville", - "Cekin", - "Cerlat", - "Cesheville", - "Ceydayburg", - "Chai-touss", - "Chakal", - "Chaold", - "Charyn", - "Chelauton", - "Chordeburg", - "Chraisouton", - "Chres", - "Chretlt", - "Chrordrreld", - "Chryas", - "Chryqyville", - "Cirannost", - "Ciranoth", - "Cirdiadel", - "Cirfinar", - "Cirfingost", - "Cirlorar", - "Cirmar", - "Cirmarmar", - "Cirreyton", - "Cirrond", - "Cirsoranwe", - "Cirsorrond", - "Cirsorund", - "Co-cil", - "Cobel", - "Cochtai", - "Coemeeton", - "Conandon", - "Condialun", - "Conolin", - "Conrollun", - "Conthiel", - "Corarchen", - "Corbruk", - "Corburg", - "Cordotn", - "Corhowe", - "Corlanque", - "Cormar", - "Corport", - "Corten", - "Craumeudale", - "Crawnkim", - "Creibeyville", - "Cretin", - "Crirtoeberg", - "Cryage", - "Crylim", - "Da-teay", - "Danug", - "Darbruk", - "Darburg", - "Dardorf", - "Darfelt", - "Dargrad", - "Darheim", - "Darholm", - "Darill", - "Darrshy", - "Darstad", - "Darvoltan", - "Dea-phount", - "Deeneuburg", - "Del'ougha", - "Delgnal", - "Denche", - "Denhver", - "Densen", - "Denum", - "Descton", - "Detan", - "Die-meiq", - "Die-tand", - "Diseville", - "Doedbygd", - "Donnbrun", - "Doratoth", - "Dorbroddor", - "Dorenath", - "Dorfinanfel", - "Dospan", - "Drae-phen", - "Draon", - "Drogburg", - "Droggrod", - "Drogungol", - "Drumcollogher", - "Duath", - "Duikouburg", - "Dun-a-for", - "Dun-a-grim", - "Dun-a-gun", - "Dun-a-menak", - "Dun-dum", - "Dun-kai", - "Dun-krag", - "Dun-lum", - "Dunarchen", - "Dunbeath", - "Dunbruk", - "Duncansby", - "Dunfanaghy", - "Dunfeld", - "Dunhowestad", - "Duniville", - "Dunmar", - "Dunmeir", - "Dunstad", - "Dunvoltan", - "Dur-a-dum", - "Dur-a-for", - "Dur-a-grim", - "Dur-a-gun", - "Dur-a-lin", - "Dur-a-menak", - "Dur-a-thol", - "Dur-dum", - "Dur-kai", - "Dur-mun", - "Dwor-a-dum", - "Dwor-a-lin", - "Dwor-a-luk", - "Dwor-ungol", - "Dyckkel", - "Dynati", - "Dynayr'a", - "Dynryno", - "Dynvery", - "Dyqua", - "E'delar", - "E'vertur", - "Eakoedale", - "Eaphaidale", - "Echrang", - "Echuy", - "Eedoiberg", - "Eemauton", - "Eephiadale", - "Einarchen", - "Einbruk", - "Einburg", - "Eindorf", - "Einfelt", - "Eingrad", - "Einheim", - "Einmund", - "Einstad", - "Eintenheim", - "Eirraeville", - "Eisedale", - "Eiyodale", - "Eldiamar", - "Elfinund", - "Ellorgost", - "Eloanfel", - "Eloat", - "Eloatanfel", - "Eloinin", - "Eloolanwe", - "Elosordor", - "Elosornost", - "Elothananfel", - "Elothantor", - "Elothielath", - "Elothieldel", - "Elotor", - "Eltayton", - "Em'enth'ilt", - "Em'urny", - "Emata", - "Emeld", - "Emez", - "Emtkal", - "Endauen", - "Enddordor", - "Endforar", - "Endfordel", - "Endlorgost", - "Endthanath", - "Endthielath", - "Endthielnost", - "Enormo", - "Entiny", - "Enuville", - "Esheaberg", - "Esidale", - "Essblor", - "Esttend", - "Estundo", - "Estyz", - "Eter'ck", - "Ethilath", - "Ethilatuen", - "Ethilenmar", - "Ethilfinlun", - "Ethilfintor", - "Ethilfordor", - "Ethilforlun", - "Ethilmarar", - "Ethilor", - "Ethilthielar", - "Ethilthielath", - "Etiburg", - "Eubiton", - "Euldiberg", - "Eurauberg", - "Eyldaton", - "Eynaudale", - "Eyneberg", - "Faetooton", - "Fo-rhes", - "Fontenbrun", - "Forbrin-a-lin", - "Forbrin-a-thol", - "Forbrin-dum", - "Forbrin-killuk", - "Forbrin-lum", - "Forbrin-mun", - "Forbrin-tor", - "Forbrodnost", - "Forfindon", - "Forgolost", - "Forloroth", - "Frainberg", - "Fundslye", - "Garoldi", - "Gei-steit", - "Gha'ech'ounn", - "Githaanwe", - "Githanost", - "Githathgost", - "Githatund", - "Githbrodost", - "Githdiator", - "Githforlun", - "Githolor", - "Githsoror", - "Giththanost", - "Glenagallagh", - "Glorforgost", - "Gnackstein", - "Gon-a-grim", - "Gon-a-karak", - "Gon-kai", - "Gon-killuk", - "Gon-tor", - "Gonas", - "Graevbygd", - "Gragburg", - "Grandotn", - "Granfeld", - "Granfelt", - "Grangrad", - "Granheim", - "Granhowe", - "Granmar", - "Granmark", - "Granmund", - "Granport", - "Granstadfeld", - "Granten", - "Gresberg", - "Grimburg", - "Grimgrod", - "Grisbygd", - "Gycer", - "Haphr", - "Hathden", - "Hatria", - "Helarchen", - "Helbruk", - "Heldorf", - "Helfeld", - "Helfelt", - "Helheim", - "Helhowe", - "Helmsdale", - "Helmund", - "Helten", - "Hiraor", - "Hiratund", - "Hirdiagost", - "Hirdor", - "Hirindor", - "Hirrolor", - "Hirsorost", - "Hirthieldon", - "Hirthielgost", - "Ho-luid", - "Ho-zak", - "Hoersalsveg", - "Holeiville", - "Honess", - "Hootauburg", - "Huilooton", - "Hynodale", - "I'rothnal", - "Iadaeburg", - "Iaia", - "Iaierd's", - "Iamayberg", - "Ianteydale", - "Iarada", - "Iaryton", - "Ieteuville", - "Ietooton", - "Ightonn", - "Ightrady", - "Ikoville", - "Imacho", - "Imad", - "Immtur", - "Inadon", - "Inaet", - "Inaid", - "Inath", - "Inathanwe", - "Inaveri", - "Inbrodin", - "Ineault'y", - "Ineed'u", - "Ingaik't", - "Ingard'w", - "Ingoeq'o", - "Ingolnost", - "Ingtiao", - "Inlorin", - "Inlorlun", - "Intaiton", - "Inuen", - "Iphouville", - "Irom'n", - "Irord", - "Irteaville", - "Isbur", - "Issac", - "Issel", - "Ithrag-a-gun", - "Ithrag-a-thol", - "Ithrag-killuk", - "Ithrag-krag", - "Itis", - "Iyoton", - "Jailouton", - "Jervbygd", - "Joerruberg", - "Joveaburg", - "Jydel", - "Kae-yik", - "Kar-a-dum", - "Kar-a-karak", - "Kar-a-lin", - "Kar-killuk", - "Kar-mun", - "Karaz-a-gun", - "Karaz-a-karak", - "Karaz-a-luk", - "Karaz-kai", - "Karaz-killuk", - "Karaz-tor", - "Karaz-ungol", - "Kargslag", - "Kau-throos", - "Ke-throuz", - "Kedsul", - "Keltver", - "Kim'eng", - "Kinccer", - "Kintura", - "Ko-stran", - "Kuileyton", - "Kul-a-lin", - "Kul-a-thol", - "Kul-kai", - "Kul-lum", - "Landldtas", - "Landtorm", - "Langholm", - "Larusk", - "Lau-sment", - "Lee-rhaig", - "Lei-neac", - "Leiroodale", - "Lemaberg", - "Lephngha", - "Leu-sarra", - "Li-laif", - "Linarchen", - "Linfeld", - "Linfelt", - "Lingrad", - "Linhowe", - "Linmark", - "Linmeir", - "Linport", - "Linstad", - "Linten", - "Linvoltan", - "Linvoltanstad", - "Llathmsul", - "Llau-kaiss", - "Lloyer", - "Lo-riag", - "Loiss", - "Loo-luk", - "Lorador", - "Lorfinath", - "Lorforin", - "Lormarnost", - "Lorol", - "Lorrolnost", - "Lortkel", - "Lostoodale", - "Lothatar", - "Lothatlun", - "Lothenlun", - "Lothforor", - "Lothinath", - "Lothmar", - "Lothmarund", - "Lotholmar", - "Lothrolnost", - "Lothsormar", - "Lothsorost", - "Lou-jort", - "Lu-drep", - "Ludnt", - "Lyeissy", - "Lyekalo", - "Lyeoso", - "Lynton", - "Magdenarchen", - "Magdenburg", - "Magdenfelt", - "Magdengrad", - "Magdenholm", - "Magdenmar", - "Magdenmark", - "Magdenten", - "Magdenvoltan", - "Mararchen", - "Marburg", - "Mardotn", - "Marfeld", - "Marheim", - "Marholm", - "Marmark", - "Marmeir", - "Marmund", - "Marport", - "Marsbrun", - "Marsburg", - "Mautayville", - "Melq", - "Meqiville", - "Mikedale", - "Morer", - "Mosghae", - "Mullaghcarn", - "Mun-a-dol", - "Mun-a-dum", - "Mun-a-karak", - "Mun-a-luk", - "Mun-a-menak", - "Mun-ban", - "Mun-dum", - "Mun-kai", - "Mun-krag", - "Mun-mun", - "Mun-tor", - "Mundarchen", - "Munddotn", - "Mundfeld", - "Mundfelt", - "Mundholm", - "Mundmar", - "Mundmeir", - "Mundmund", - "Mundport", - "Mundvoltan", - "Mustlor", - "Mym", - "N'omiss", - "Naild", - "Naqrd", - "Narga-a-dum", - "Narga-a-gun", - "Narga-a-karak", - "Narga-dor", - "Narga-lum", - "Narga-tor", - "Nargburg", - "Narggog", - "Navenby", - "Ne-coiss", - "Nellvit", - "Nepler", - "Netos", - "Neuarchen", - "Neubruk", - "Neuburg", - "Neufelt", - "Neuheim", - "Neuholm", - "Neuhowe", - "Neumeir", - "Neumund", - "Ney-brer", - "Niavauton", - "Nildss", - "Nima", - "Nimathgost", - "Nimdoranwe", - "Nimfortor", - "Nimloror", - "Nimolrond", - "Nimthanlun", - "Nimthiel", - "Nimthielanfel", - "No-tan", - "Nolaville", - "Nomeaburg", - "Norarchen", - "Norburg", - "Normeir", - "Norport", - "Norstad", - "Norten", - "Nuchr", - "Nugm", - "Nyaec'p", - "Nyon", - "O'arbur", - "Oephoville", - "Oigeadale", - "Oiloedale", - "Oimiaton", - "Okaberg", - "Oldbtur", - "Oliaburg", - "Ollo-a-for", - "Ollo-a-gun", - "Ollo-a-lin", - "Ollo-a-luk", - "Ollo-ban", - "Ollo-dor", - "Ollo-krag", - "Ollo-ungol", - "Oltouton", - "Omeerr'a", - "Omert", - "Omlir", - "Onaberg", - "Ondeydale", - "Onym", - "Onyq", - "Oontaedale", - "Oopyberg", - "Oosadale", - "Ootaton", - "Oqauton", - "Orart", - "Ordaville", - "Orm'ser", - "Ormfmor", - "Ormgryte", - "Ormwor", - "Oroldu", - "Orrebygd", - "Orrooville", - "Orys", - "Osdelu", - "Oseberg", - "Osray", - "Oufodale", - "Oughang", - "Oughen", - "Ounuton", - "Phyrdynal", - "Pirrtor", - "Pogelveir", - "Poghkaugh", - "Poloon'u", - "Polrayo", - "Porthcawl", - "Praestbygd", - "Qua-stass", - "Quataia", - "Quaundeville", - "Quayfeeton", - "Quiage", - "Quivuberg", - "Quoraeberg", - "Quynnoedale", - "Radeng", - "Radiaanwe", - "Radol", - "Radwary", - "Raennost", - "Ragolmar", - "Rak'ves", - "Rakhat", - "Ramaroth", - "Ran'kal'aet", - "Ranlvor", - "Rappbygd", - "Rasorath", - "Ravsurn", - "Raypero", - "Reilburg", - "Rephv", - "Reycaberg", - "Ri-bliz", - "Ri-ruif", - "Riecburg", - "Riecdorf", - "Riecfelt", - "Riecheim", - "Riecholm", - "Riecmeir", - "Riecstad", - "Riecvoltan", - "Rieloidale", - "Rilad", - "Rillen", - "Riltas", - "Rirdieberg", - "Robaedale", - "Rodmosa", - "Roi-nael", - "Rosh", - "Ruage", - "Rudoeton", - "Rudyburg", - "Rulale", - "Ruran", - "Rusrddyn", - "Ruzb", - "Ryssler", - "Sa-lan", - "Sacphin", - "Sae-wim", - "Sam'iae", - "Samath", - "Saran", - "Sas", - "Say-sweyld", - "Sch'oskin", - "Schai-reuf", - "Scheemaburg", - "Schiesieburg", - "Schockdorm", - "Schodild", - "Schointoville", - "Seathayburg", - "Seedadale", - "Seetouburg", - "Sei-yuss", - "Sei-zhet", - "Shasnlye", - "Shasz", - "Shookeedale", - "Shul", - "Shy'est'ud", - "Shyelda", - "Shykssit", - "Siqness", - "Sirshaugh", - "Sissul", - "Skokholm", - "Skottskog", - "Sleckz", - "Slelt", - "Slethkden", - "Slisuburg", - "Sluen", - "Smagoberg", - "Smauleaton", - "Smianoville", - "Smuchrris", - "Smyzlia", - "Sneyleeberg", - "Snoi-theyn", - "Somat", - "Soo-tyn", - "Soqmold", - "Soranwe", - "Soratath", - "Soratgost", - "Sorathanfel", - "Sordorost", - "Sorfindon", - "Sorindel", - "Sorlorar", - "Soroldel", - "Sorthandon", - "Sorthanuen", - "Sost", - "Stay-blin", - "Steesaville", - "Stram", - "Strardouton", - "Stroqough", - "Stugslett", - "Sul'em'uq", - "Swae-raind", - "Swedtves", - "Swie-sar", - "Sychser", - "Tabck", - "Tai'urn'ys", - "Tailiton", - "Tan'at", - "Tanaughe", - "Tanbald", - "Tar-a-for", - "Tar-a-lin", - "Tar-a-luk", - "Tar-dor", - "Tar-dum", - "Tar-krag", - "Tar-tor", - "Tar-ungol", - "Tas'bur", - "Tha-seurr", - "Thaifooton", - "Thandiaanfel", - "Thandianost", - "Thanmaranfel", - "Thanthielnost", - "Ther'awu", - "Ther'nal", - "Thereck", - "Therl", - "Thidest", - "Tho-phiag", - "Thor-a-for", - "Thor-a-thol", - "Thor-dor", - "Thor-kai", - "Thor-tor", - "Thr'taiton", - "Thradiedale", - "Threves", - "Thrindedale", - "Throk", - "Throzmunt", - "Thrysay", - "Thyrkim", - "Tiault", - "Tinien'nt", - "Tinynt", - "Tiphklye", - "Tonisi", - "Tonraky", - "Tonusty", - "Toraville", - "Tourburg", - "Tovale", - "Trabddel", - "Tral", - "Treasaeton", - "Treen", - "Treshrd", - "Triasheuton", - "Trydt", - "Tui-trouph", - "Tur'kel", - "Turfold", - "Turturn", - "Turuy", - "U'anghon", - "Uissaeburg", - "Und'em", - "Und'ris'ian", - "Undildo", - "Unnuiton", - "Uriberg", - "Useville", - "Ustayl'rt", - "Ustoist'ch", - "Uxelberg", - "Uzburg", - "Verburg", - "Verdorf", - "Verholm", - "Vermar", - "Vermark", - "Verstad", - "Vesler", - "Voiyeuville", - "Volarchen", - "Volburg", - "Voldorf", - "Volfeld", - "Volgrad", - "Volholm", - "Volhowe", - "Volvoltan", - "Vor'ary", - "W'tiaenth", - "Waidbruk", - "Waiddorf", - "Waidgrad", - "Waidheim", - "Waidholm", - "Waidmar", - "Waidmeir", - "Waidten", - "Wastenburg", - "Wastendotnfeld", - "Wastenfelt", - "Wastenheim", - "Wastenholm", - "Wastenmar", - "Wastenmund", - "Wastenvoltan", - "Wenghmor", - "Wh'inekal", - "Whoezeaburg", - "Wiadeuberg", - "Worad", - "Worir", - "Yeroll", - "Yertiss", - "Yleaberg", - "Yoneiburg", - "Yqauton", - "Yriaberg", - "Zh'ostas", - "Zho-raud", - "Zigar", - "Zogburg", - "A'emwor", - "A'rilurn", - "Aathon", - "Aberaeron", - "Aberdaron", - "Aberdovey", - "Abersoch", - "Abrantes", - "Achen", - "Achuimi", - "Ackler", - "Adrano", - "AeBrey", - "Age'acho", - "Age'radi", - "Ageen", - "Aghleam", - "Aisbrun", - "Aisfor", - "Aisgrois", - "Aisnuon", - "Aispuit", - "Akbou", - "Aldage", - "Aldan", - "Aleccer", - "Aletiss", - "Alfaro", - "Alghero", - "Almeria", - "Altnaharra", - "Ancroft", - "Ang'vora", - "Anom", - "Anque", - "Anran", - "Anshun", - "Anstruther", - "Antor", - "Arbroath", - "Arcila", - "Ardfert", - "Ardraka", - "Ardurn", - "Arezzo", - "Ariano", - "Arlon", - "Asay", - "Ash'sul", - "Ashblod", - "Ashdrog", - "Ashgog", - "Ashrot", - "Ashsay", - "Ashshybel", - "Ashslag", - "Ashuk", - "Ashwaz", - "Asjild", - "Asnrak", - "Asonack", - "Ater", - "Athmardor", - "Athrust", - "Aughaugha", - "Avanos", - "Aveiro", - "Awtorm", - "Badalona", - "Baechahoela", - "Baest", - "Baiaisle", - "Baibrun", - "Baibur", - "Baiburbur", - "Baidinon", - "Baifel", - "Baifelgris", - "Baigris", - "Baimais", - "Bainuon", - "Baipuit", - "Bairiennegrois", - "Ballindine", - "Balta", - "Bancest", - "Banlar", - "Barika", - "Bastak", - "Bayonne", - "Beaubur", - "Beaudinon", - "Beaufor", - "Bejaia", - "Bel'em", - "Belver", - "Bemeniky", - "Beragh", - "Bergland", - "Berneray", - "Berori", - "Binhai", - "Birde", - "Bocagobi", - "Bocholt", - "Bogbad", - "Bogdrog", - "Bogmadie", - "Bogrot", - "Bogslag", - "Boguz", - "Bopol", - "Borodit", - "Braga", - "Branbad", - "Branblod", - "Brandor", - "Brangrod", - "Branrun", - "Branshak", - "Branthang", - "Branthor", - "Brechlin", - "Brimdordel", - "Briminnost", - "Brimmarmar", - "Brimolanwe", - "Brimost", - "Brodick", - "Bugbad", - "Bugdor", - "Bugungol", - "Bugwaz", - "Burgare", - "Burongha", - "Buyet", - "Cadel", - "Calpio", - "Canna", - "Capperwe", - "Caprera", - "Carahue", - "Carbost", - "Carnforth", - "Carrigaline", - "Caserta", - "Cathcer", - "Catrianchi", - "Cerrir", - "Ch'therir", - "Cheath", - "Chedaru", - "Chedely", - "Chesuli", - "Cheswor", - "Chiem", - "Cimtas", - "Ciroldon", - "Cirrolmar", - "Clatter", - "Cloaugh", - "Cluen", - "Coilaco", - "Conaint", - "Conanath", - "Conanwe", - "Conator", - "Condorath", - "Condorund", - "Conforost", - "Conrolgost", - "Conthieldel", - "Coraisle", - "Corbur", - "Cordel", - "Corinth", - "Cormais", - "Cornon", - "Corofin", - "Corpuit", - "Corran", - "Corrienne", - "Corwen", - "Cossul", - "Crail", - "Cremona", - "Crerakroth", - "Crieff", - "Cromarty", - "Cumbraes", - "Cuormver", - "D'adlor", - "D'aughough", - "Daingean", - "Dankest", - "Darag", - "Dariro", - "Darm", - "Darunt", - "Decca", - "Dedihow", - "Dedotyl", - "Denbur", - "Denew'rt", - "Denilt", - "Denlor", - "Derron", - "Derwent", - "Deubrun", - "Deubur", - "Deudinon", - "Deugrande", - "Deveron", - "Dezhou", - "Dhakdor", - "Dhakghul", - "Dhakgrod", - "Dhakwaz", - "Dilavyk", - "Donnais", - "Donndinon", - "Donnnuon", - "Doramed", - "Dorantor", - "Dormardel", - "Dormaruen", - "Dornoch", - "Dorothtin", - "Dorsorin", - "Draerusk", - "Draib", - "Drall", - "Drammes", - "Drard", - "Dremmer", - "Drense", - "Drimnin", - "Drogbad", - "Drogbul", - "Drummore", - "Dryck", - "Drymen", - "Dunkeld", - "Dunmanus", - "Dunster", - "Durness", - "Durthblod", - "Durthrot", - "Durthrun", - "Durththang", - "Duucshire", - "Dynaw", - "Dyrutote", - "E'ervor", - "E'shyough", - "Ech'hon'oec", - "Echech", - "Echim", - "Echlir", - "Echvild", - "Eighteiai", - "Eightobana", - "Eingeeldu", - "Elathmar", - "Elfinin", - "Elgomaar", - "Ellesmere", - "Ellon", - "Elmanu", - "Elmrake", - "Elmut", - "Elodiauen", - "Emlther", - "Emys'a", - "Enburen", - "Endandon", - "Endbrodanfel", - "Endinmar", - "Endlormar", - "Endolnost", - "Endris", - "Endrolar", - "Enechan", - "Enfar", - "Engogh", - "Engwina", - "Enhen", - "Enlcha", - "Enrile", - "Enthon", - "Enthyl'nt", - "Erisort", - "Eriss", - "Erootu", - "Erqueo", - "Errak", - "Eskerfan", - "Essend", - "Essuck", - "Estkal", - "Etdshy", - "Ethaqi", - "Ethilatnost", - "Ethildiaanfel", - "Ethilforanfel", - "Ethilsortor", - "Ethilsoruen", - "Etilda", - "Ettrick", - "F'darche", - "Fanders", - "Faoughia", - "Farafra", - "Ferbane", - "Fetlar", - "Flock", - "Florina", - "Fontenais", - "Fontenaisle", - "Fontenfor", - "Fontengrois", - "Fontennuondel", - "Fontenois", - "Fontenquel", - "Fontenrienne", - "Fordiauen", - "Fordorlun", - "Formarund", - "Formby", - "Forthieldel", - "Galloway", - "Ganzhou", - "Gar'em", - "GealCharn", - "Gecijej", - "Gededyki", - "Gerr", - "Ghaoth", - "Ghasver", - "Ghathat", - "Gifford", - "Girvan", - "Githdormar", - "Githdoror", - "Githendor", - "Githforar", - "Githsoroth", - "Glenanane", - "Glin", - "Glomera", - "Glormandia", - "Glorsordel", - "Gluggby", - "Gnoelhaala", - "Golconda", - "Gorbad", - "Gorbul", - "Gordor", - "Gorthang", - "Gorungol", - "Gourock", - "Gragblod", - "Gragbul", - "Graggabab", - "Gragghul", - "Gragthang", - "Grandola", - "Grendel", - "Grendinon", - "Grenmais", - "Grenois", - "Grenpuit", - "Gresir", - "Greverre", - "Grimbad", - "Griminish", - "Grimrot", - "Grimrun", - "Groddland", - "Grue", - "Gudup", - "Gurkacre", - "Gytokas", - "Haikou", - "Halkirk", - "Handan", - "Hasmerr", - "Hateto", - "Hawodu", - "Heald", - "Helmsley", - "Helsicke", - "Helvete", - "Heold", - "Hikub", - "Hiren", - "Hirenuen", - "Hoisais", - "Hoisaisle", - "Hoisburaisle", - "Hoisdel", - "Hoisdinon", - "Hoisgris", - "Hoislanque", - "Hoisnuon", - "Hoisois", - "Hoisquel", - "Honeer'o", - "Honeng", - "Hostcer", - "Hullevala", - "I'ceraw", - "Iaortai", - "Iath", - "Ichidi", - "Ickellund", - "Ightrodat", - "Ildit", - "Ildtury", - "Imltai", - "Imoretore", - "Imyld", - "Inaden", - "Inananwe", - "Inber", - "Indortor", - "Ineisu", - "Ingingo", - "Inoltor", - "Inthielost", - "Inverie", - "Ioughosula", - "Iruiv'w", - "Iseteng", - "Isom", - "Issche", - "Issnina", - "Itkali", - "Ityest", - "Ityt", - "Jaca", - "Jahrom", - "Jeormel", - "Jining", - "Joen", - "Jotel", - "Kaddervar", - "Kal'oma", - "Kalaur'o", - "Kalol", - "Kalshy", - "Karand", - "Kargbul", - "Karggabab", - "Karggog", - "Kargslag", - "Kargthang", - "Kargthor", - "Kargungol", - "Karothea", - "Kashmar", - "Kawapo", - "Kekeloh", - "Kelade", - "Keswick", - "Ketyst", - "Kielder", - "Killorglin", - "Kimrem", - "Kimsay", - "Kinbrace", - "Kintore", - "Kirriemuir", - "Klen", - "Knesekt", - "Kobbe", - "Koheda", - "Komarken", - "Kovel", - "Krod", - "Kuny", - "Kursk", - "Kynys", - "L'oria", - "Lagos", - "Lagysar", - "Lakah", - "Lamlash", - "Lapsam", - "Larache", - "Larkanth", - "Larmet", - "Larok", - "Larothold", - "Latuz", - "Lautaro", - "Lavan", - "Lediro", - "Leighlin", - "Lemos", - "Ler'usk'uil", - "Lerbeli", - "Lervir", - "Leven", - "Licata", - "Licert", - "Light", - "Lijyxebo", - "Lilais", - "Lilaisle", - "Lildinon", - "Lilgrande", - "Lilgrois", - "Lilmais", - "Lilnon", - "Lilnuon", - "Lilois", - "Lilrienne", - "Limavady", - "Lingen", - "Lintan", - "Lion", - "Lipicuxe", - "Liscannor", - "Llirad", - "Llolald", - "Locarno", - "Loceria", - "Lochalsh", - "Lochcarron", - "Lochinver", - "Lochmaben", - "Lolosutu", - "Lom", - "Loner", - "Loras", - "Lorathlun", - "Lorathor", - "Lorayther", - "Lorbroddel", - "Lorbrodrond", - "Lorgolgost", - "Lorima", - "Lormaroth", - "Lormartor", - "Lorthalm", - "Lorthielmar", - "Lotan", - "Lothamar", - "Lothathath", - "Lothdornost", - "Lothinin", - "Lothmarlun", - "Lothmaruen", - "Lotholuen", - "Louer", - "Lurkabo", - "Lutedose", - "Luthiir", - "Lybster", - "Lydel", - "Lye'mos", - "Lyeak", - "Lyehir", - "Lyfel", - "Lyquel", - "Macila", - "Maharoxe", - "Mallaig", - "Marsdel", - "Mataro", - "Mauvtan", - "Meet", - "Melfi", - "Melvaig", - "Menter", - "Methven", - "Moffat", - "Moifbel", - "Monaisle", - "Monamolin", - "Monbrun", - "Monbur", - "Mondinon", - "Monfel", - "Monfor", - "Mongris", - "Mongrois", - "Monlanque", - "Monmais", - "Monzon", - "Mor'ser", - "Morblod", - "Morella", - "Morena", - "Morgabab", - "Morgel", - "Morgog", - "Morrun", - "Morslag", - "Mortenford", - "Morungol", - "Morwara", - "Moryr", - "Mosiap'i", - "Mosuf", - "Mulle", - "Mupac", - "Murom", - "Muskel", - "Nabrun", - "Nadam", - "Nadinon", - "Nafor", - "Nagrande", - "Nagrois", - "Nairn", - "Nakyce", - "Naletran", - "Namais", - "Namaisbur", - "Nanuon", - "Naper", - "Naquelrienne", - "Narbul", - "Nargabab", - "Nargbul", - "Nargrod", - "Nargshak", - "Nargslag", - "Nargungol", - "Nargwaz", - "Narienne", - "Narrot", - "Narshak", - "Nazblod", - "Nazghul", - "Nazgog", - "Nazgrod", - "Nazrot", - "Nazshak", - "Nazthang", - "Negar", - "Nenol", - "NephinBeg", - "Nimathost", - "Nimathtor", - "Nimenor", - "Niskby", - "Nolle", - "Nonyvu", - "Nork", - "Nosen", - "Nugyru", - "Nurac", - "Nusay", - "Nutaru", - "Nyauss'c", - "Nybusa", - "Nyduvy", - "Nylarey", - "Nyon", - "Nysasha", - "Nysaw", - "Nysgarim", - "O'agetin", - "Odirtu", - "Oldgale", - "Oldreng", - "Olenek", - "Oloron", - "Onuise", - "Oranmore", - "Orelda", - "Ormwary", - "Orrach", - "Oruivu", - "Os'radi", - "Osereunti", - "Osurnkim", - "Oughlaw", - "Oughxpol", - "Palmi", - "Panyu", - "Parais", - "Parfel", - "Partry", - "Pary", - "Pauer", - "Payawofy", - "Penhalolen", - "Perald", - "Perel", - "Peres", - "Perkel", - "Perrana", - "Perski", - "Phaitwar", - "Phidyntia", - "Planken", - "Plattland", - "Pleagne", - "Poleld", - "Polyk", - "Portimao", - "Potenza", - "Poval", - "Preetsome", - "Presu", - "Prettstern", - "Pycatoca", - "Quainai", - "Quiser", - "Quokelhin", - "Radiaoth", - "Ragolrond", - "Rainanwe", - "Rainlun", - "Rakach", - "Rakiy", - "Rakkal", - "Ranaw", - "Randar", - "Ranshya", - "Rantlu", - "RathLuire", - "Rayhat", - "Raymdyn", - "Rayos", - "Rayting", - "Reildel", - "Reilfel", - "Reilfor", - "Reilgris", - "Reilgrois", - "Reilmais", - "Reilnon", - "Reilois", - "Reilrienne", - "Rekelny", - "Remosyne", - "Rethel", - "Retica", - "Rhakin", - "Rhihin", - "Riggenthorpe", - "Riltend", - "Ristril", - "Robune", - "Rochfort", - "Rod'ar", - "Rodair'n", - "Roddendor", - "Rodoro", - "Rodwor", - "Roin", - "Roptille", - "Roril", - "Roskelem", - "Roter", - "Rothrila", - "Rothtim", - "Rozocil", - "Rueve", - "Runahesy", - "Rusila", - "Rycydome", - "Rynok", - "Sagunto", - "Saklebille", - "Salen", - "Sandwick", - "Sarab", - "Sarkanvale", - "Sash", - "Satiasam", - "Sayqua", - "Scandamia", - "Scarinish", - "Schiaqlor", - "Schoineenth", - "Schyacher", - "Schyine", - "Schywor", - "Scourie", - "Seen", - "Sefitat", - "Ser'en'et", - "Seress'a", - "Serilelo", - "Serov", - "Seruph", - "Setihe", - "Setur", - "Shanyin", - "Shyselm", - "Siegen", - "Sienbrun", - "Siendel", - "Siendinon", - "Sienlanque", - "Siennuon", - "Sienrienne", - "Sihep", - "Sinan", - "Sines", - "Sisasa", - "Situciru", - "Situlim", - "Skelid", - "Skelnysard", - "Skim", - "Skomer", - "Sl'tinough", - "Sledmere", - "Sm'kelmos", - "Smotur", - "Smuiss", - "Snyaldshy", - "Sobabaho", - "Sondhon", - "Soratath", - "Sorator", - "Soratuen", - "Sorbrodanfel", - "Sorisdale", - "Spakker", - "Stackforth", - "Staklesse", - "Stilye", - "Stinchar", - "Stoem", - "Stoer", - "Streang", - "Strichen", - "Stroest", - "Stroma", - "Suide", - "Sulsum", - "Sultenth", - "Sulwor", - "Surdel", - "Surfel", - "Surlanque", - "Surpuit", - "Swedelale", - "Swuor", - "Syimler", - "Syque", - "Sytiti", - "Tabuk", - "Tageick", - "Taial", - "Taidald", - "Taiq", - "Tanros", - "Tantona", - "Taold", - "Tarraspan", - "Tearque", - "Teeleld", - "Terixybi", - "Tetuan", - "Teyaludu", - "Thanathmar", - "Thanloruen", - "Ther'ban", - "Thorbad", - "Thorbul", - "Thordor", - "Thorgrod", - "Thorrot", - "Thorungol", - "Thurso", - "Tia'en'ab", - "Tiadar", - "Tiaougha", - "Tiemcen", - "Tiksi", - "Tiny", - "Tolsta", - "Toluis", - "Tonays'u", - "Tonentin", - "Tonther", - "Toppola", - "Toreg", - "Torell", - "Torridon", - "Torril", - "Tortur", - "Toumser", - "Tourgrande", - "Tourlanque", - "Tourois", - "Tourquel", - "Tourrienne", - "Trapani", - "Tromeforth", - "Tudela", - "Tur'enda", - "Turaym'k", - "Tureer'l", - "Turia", - "Tynumyv", - "U'ildaw", - "U'osad", - "Umoc", - "Umoth", - "Und'rak", - "Untnqua", - "Untvory", - "Urnraynys", - "Uskus'k", - "Ustumi", - "Uthbad", - "Uthblod", - "Uthbul", - "Uthghul", - "Uthrun", - "Uththor", - "Uzbad", - "Uzdor", - "Uzghul", - "Uzgog", - "Uzgoth", - "Uzrot", - "Uzrun", - "Uzshak", - "Uzslag", - "Vaila", - "Valga", - "Vather", - "Ver'buro", - "Verguin", - "Vernlund", - "Veroit", - "Verrod", - "Versaisle", - "Versfor", - "Versgris", - "Verslanque", - "Verslanquebur", - "Versmais", - "Versnon", - "Versrienne", - "Verum", - "Ves'kel", - "Vesul", - "Victoria", - "Vigurr", - "Vojowex", - "Vorild", - "Vosetosi", - "Waimer", - "Wariav'gh", - "Warick", - "Warilt", - "Wett", - "Whald", - "Whaor", - "Wheescha", - "Wheinwor", - "Wicaess", - "Woiknal", - "Worelm", - "Worhon", - "Wygece", - "Wysakol", - "Xontormia", - "Y'tinny", - "Yahevoru", - "Yakleks", - "Ydaso", - "Yejel", - "Yeritoni", - "Yleya", - "Ypipix", - "Ypoluemo", - "Yuci", - "Zaalsehuur", - "Zafahyro", - "Zamora", - "Zapulla", - "Zhedar", - "Zicoge", - "Zoddor", - "Zodgabab", - "Zodghul", - "Zodgrod", - "Zodrun", - "Zodslag", - "Zodthang", - "Zodungol", - "Zogghul", - "Zoggog", - "Zoggoth", - "Zoggrod", - "Zogthang", - "Zyrosihu", -}; - -// -// The following stuff is just for in this file, to setup the names during -// world setup -// - -static int nnames; -static int * nameused; -static int ntowns; -static int nregions; - -void SetupNames() -{ - nnames = sizeof regionnames / sizeof (char *); - nameused = new int[nnames]; - - for (int i=0; i= number) i=0; - } - for (i=0; iMULTI_HEX_NEXUS) { - ny = 2; - while(nx <= 0) { - Awrite("How many hexes should the nexus region be?"); - nx = Agetint(); - if (nx == 1) ny = 1; - else if (nx % 2) { - nx = 0; - Awrite("The width must be a multiple of 2."); - } - } - } else { - nx = 1; - } - - int xx = 0; - while (xx <= 0) { - Awrite("How wide should the map be? "); - xx = Agetint(); - if( xx % 8 ) { - xx = 0; - Awrite( "The width must be a multiple of 8." ); - } - } - int yy = 0; - while (yy <= 0) { - Awrite("How tall should the map be? "); - yy = Agetint(); - if( yy % 8 ) { - yy = 0; - Awrite( "The height must be a multiple of 8." ); - } - } - - regions.CreateLevels(2 + Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + Globals->ABYSS_LEVEL); - - SetupNames(); - - regions.CreateNexusLevel( 0, nx, ny, "nexus" ); - regions.CreateSurfaceLevel( 1, xx, yy, 0 ); - - // Create underworld levels - int i; - for(i = 2; i < Globals->UNDERWORLD_LEVELS+2; i++) { - int xs = regions.GetLevelXScale(i); - int ys = regions.GetLevelYScale(i); - regions.CreateUnderworldLevel(i, xx/xs, yy/ys, "underworld"); - } - // Underdeep levels - for(i=Globals->UNDERWORLD_LEVELS+2; - i<(Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS+2); i++) { - int xs = regions.GetLevelXScale(i); - int ys = regions.GetLevelYScale(i); - regions.CreateUnderdeepLevel(i, xx/xs, yy/ys, "underdeep"); - } - - if(Globals->ABYSS_LEVEL) { - regions.CreateAbyssLevel(Globals->UNDERWORLD_LEVELS + - Globals->UNDERDEEP_LEVELS + 2, "abyss"); - } - - CountNames(); - - if(Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS == 1) { - regions.MakeShaftLinks( 2, 1, 8 ); - } else if(Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS) { - int i, ii; - // shafts from surface to underworld - regions.MakeShaftLinks(2, 1, 10); - for(i=3; iUNDERWORLD_LEVELS+2; i++) { - regions.MakeShaftLinks(i, 1, 10*i-10); - } - // Shafts from underworld to underworld - if(Globals->UNDERWORLD_LEVELS > 1) { - for(i = 3; i < Globals->UNDERWORLD_LEVELS+2; i++) { - for(ii = 2; ii < i; ii++) { - if(i == ii+1) { - regions.MakeShaftLinks(i, ii, 12); - } else { - regions.MakeShaftLinks(i, ii, 24); - } - } - } - } - // underdeeps to underworld - if(Globals->UNDERDEEP_LEVELS && Globals->UNDERWORLD_LEVELS) { - // Connect the topmost of the underdeep to the bottommost - // underworld - regions.MakeShaftLinks(Globals->UNDERWORLD_LEVELS+2, - Globals->UNDERWORLD_LEVELS+1, 12); - } - // Now, connect the underdeep levels together - if(Globals->UNDERDEEP_LEVELS > 1) { - for(i = Globals->UNDERWORLD_LEVELS+3; - i < Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS+2; - i++) { - for(ii = Globals->UNDERWORLD_LEVELS+2; ii < i; ii++) { - if(i == ii+1) { - regions.MakeShaftLinks(i, ii, 12); - } else { - regions.MakeShaftLinks(i, ii, 25); - } - } - } - } - } - - regions.SetACNeighbors( 0, 1, xx, yy ); - - regions.InitSetupGates( 1 ); - // Set up gates on all levels of the underworld - for(int i=2; i < Globals->UNDERWORLD_LEVELS+2; i++) { - regions.InitSetupGates( i ); - } - // Underdeep has no gates, only the possible shafts above. - - regions.FinalSetupGates(); - - regions.CalcDensities(); -} - -int ARegionList::GetRegType( ARegion *pReg ) -{ - // - // Figure out the distance from the equator, from 0 to 3. - // - int lat = ( pReg->yloc * 8 ) / ( pRegionArrays[ pReg->zloc ]->y ); - if (lat > 3) - { - lat = (7 - lat); - } - - // Underworld region - if((pReg->zloc > 1) && (pReg->zloc < Globals->UNDERWORLD_LEVELS+2)) { - int r = getrandom(4); - switch (r) { - case 0: - return R_OCEAN; - case 1: - return R_CAVERN; - case 2: - return R_UFOREST; - case 3: - return R_TUNNELS; - default: - return( 0 ); - } - } - - // Underdeep region - if((pReg->zloc > Globals->UNDERWORLD_LEVELS+1) && - (pReg->zloc < Globals->UNDERWORLD_LEVELS+ - Globals->UNDERDEEP_LEVELS+2)) { - int r = getrandom(4); - switch(r) { - case 0: - return R_OCEAN; - case 1: - return R_CHASM; - case 2: - return R_DFOREST; - case 3: - return R_GROTTO; - default: - return (0); - } - } - - // surface region - if( pReg->zloc == 1 ) { - int r = getrandom(64); - switch (lat) - { - case 0: /* Arctic regions */ - if (r < 24) return R_TUNDRA; - if (r < 32) return R_MOUNTAIN; - if (r < 40) return R_FOREST; - return R_PLAIN; - case 1: /* Colder regions */ - if (r < 16) return R_PLAIN; - if (r < 40) return R_FOREST; - if (r < 48) return R_MOUNTAIN; - return R_SWAMP; - case 2: /* Warmer regions */ - if (r < 20) return R_PLAIN; - if (r < 28) return R_FOREST; - if (r < 36) return R_MOUNTAIN; - if (r < 44) return R_SWAMP; - if (r < 52) return R_JUNGLE; - return R_DESERT; - case 3: /* tropical */ - if (r < 16) return R_PLAIN; - if (r < 24) return R_MOUNTAIN; - if (r < 36) return R_SWAMP; - if (r < 48) return R_JUNGLE; - return R_DESERT; - } - return R_OCEAN; - } - - if( pReg->zloc == 0 ) - { - // - // This really shouldn't ever get called. - // - return( R_NEXUS ); - } - - // - // This really shouldn't get called either - // - return( R_OCEAN ); -} - -int ARegionList::GetLevelXScale(int level) -{ - // Surface and nexus are unscaled - if(level < 2) return 1; - -//ArcadiaIII specific world creation - return 1; - - // If we only have one underworld level it's 1/2 size - if(Globals->UNDERWORLD_LEVELS == 1 && Globals->UNDERDEEP_LEVELS == 0) - return 2; - - // We have multiple underworld levels - if(level >= 2 && level < Globals->UNDERWORLD_LEVELS+2) { - // Topmost level is full size in x direction - if(level == 2) return 1; - // All other levels are 1/2 size - return 2; - } - if(level >= Globals->UNDERWORLD_LEVELS+2 && - level < (Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS+2)){ - // Topmost underdeep level is 1/2 size - if(level == Globals->UNDERWORLD_LEVELS+2) return 2; - // All others are 1/4 size - return 4; - } - // We couldn't figure it out, assume not scaled. - return 1; -} - -int ARegionList::GetLevelYScale(int level) -{ - // Surface and nexus are unscaled - if(level < 2) return 1; - -//ArcadiaIII specific world creation - return 1; - - // If we only have one underworld level it's 1/2 size - if(Globals->UNDERWORLD_LEVELS == 1 && Globals->UNDERDEEP_LEVELS == 0) - return 2; - - // We have multiple underworld levels - if(level >= 2 && level < Globals->UNDERWORLD_LEVELS+2) { - // Topmost level is 1/2 size in the y direction - if(level == 2) return 2; - // Bottommost is 1/4 size in the y direction - if(level == Globals->UNDERWORLD_LEVELS+1) return 4; - // All others are 1/2 size in the y direction - return 2; - } - if(level >= Globals->UNDERWORLD_LEVELS+2 && - level < (Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS+2)){ - // All underdeep levels are 1/4 size in the y direction. - return 4; - } - // We couldn't figure it out, assume not scaled. - return 1; -} - -int ARegionList::CheckRegionExit(ARegion *pFrom, ARegion *pTo ) -{ - if((pFrom->zloc==1) || - (pFrom->zloc>Globals->UNDERWORLD_LEVELS+Globals->UNDERDEEP_LEVELS+1)) { - return( 1 ); - } - - int chance = 0; - if( pFrom->type == R_CAVERN || pFrom->type == R_UFOREST || - pTo->type == R_CAVERN || pTo->type == R_UFOREST ) - { - chance = 25; - } - if( pFrom->type == R_TUNNELS || pTo->type == R_TUNNELS) - { - chance = 50; - } - if(pFrom->type == R_GROTTO || pFrom->type == R_DFOREST || - pTo->type == R_GROTTO || pTo->type == R_DFOREST) { - // better connected underdeeps - chance = 40; - } - if(pFrom->type == R_CHASM || pTo->type == R_CHASM) { - chance = 60; - } - if (getrandom(100) < chance) { - return( 0 ); - } - return( 1 ); -} - -int ARegionList::GetWeather( ARegion *pReg, int month ) -{ - if (pReg->zloc == 0) - { - return W_NORMAL; - } - - if( pReg->zloc > 1 ) - { - return( W_NORMAL ); - } - - int ysize = pRegionArrays[ 1 ]->y; - - if ((3*( pReg->yloc+1))/ysize == 0) - { - /* Northern third of the world */ - if (month > 9 || month < 2) - { - return W_WINTER; - } - else - { - return W_NORMAL; - } - } - - if ((3*( pReg->yloc+1))/ysize == 1) - { - /* Middle third of the world */ - if (month == 11 || month == 0 || month == 5 || month == 6) - { - return W_MONSOON; - } - else - { - return W_NORMAL; - } - } - - if (month > 3 && month < 8) - { - /* Southern third of the world */ - return W_WINTER; - } - else - { - return W_NORMAL; - } -} - -int ARegion::CanBeStartingCity( ARegionArray *pRA ) -{ - if(type == R_OCEAN) return 0; - if (!IsCoastal()) return 0; - if (town && town->pop == 5000) return 0; - - int regs = 0; - AList inlist; - AList donelist; - - ARegionPtr * temp = new ARegionPtr; - temp->ptr = this; - inlist.Add(temp); - - while(inlist.Num()) { - ARegionPtr * reg = (ARegionPtr *) inlist.First(); - for (int i=0; iptr->neighbors[i]; - if (!r2) continue; - if (r2->type == R_OCEAN) continue; - if (GetRegion(&inlist,r2->num)) continue; - if (GetRegion(&donelist,r2->num)) continue; - regs++; - if (regs>20) return 1; - ARegionPtr * temp = new ARegionPtr; - temp->ptr = r2; - inlist.Add(temp); - } - inlist.Remove(reg); - donelist.Add(reg); - } - return 0; -} - -void ARegion::MakeStartingCity() -{ - if(!Globals->TOWNS_EXIST) return; - - if(Globals->GATES_EXIST) gate = -1; - if( !town ) - { - AddTown(); - } - - town->pop = 5000*Globals->POP_LEVEL; - town->basepop = 5000*Globals->POP_LEVEL; - - float ratio; - Market *m; - markets.DeleteAll(); - if(Globals->START_CITIES_START_UNLIMITED) { - for (int i=0; iPOP_LEVEL,5000*Globals->POP_LEVEL,-1,-1); - markets.Add(m); - } - } - ratio = ItemDefs[race].baseprice / (float)Globals->BASE_MAN_COST; - m=new Market(M_BUY,race,(int)(Wages()*4*ratio),-1,5000*Globals->POP_LEVEL,5000*Globals->POP_LEVEL,-1,-1); - markets.Add(m); - if(Globals->LEADERS_EXIST) { - ratio=ItemDefs[I_LEADERS].baseprice/(float)Globals->BASE_MAN_COST; - m = new Market(M_BUY,I_LEADERS,(int)(Wages()*4*ratio),-1, - 5000*Globals->POP_LEVEL,5000*Globals->POP_LEVEL,-1,-1); - markets.Add(m); - } - } else { - SetupCityMarket(); - ratio = ItemDefs[race].baseprice / (float)Globals->BASE_MAN_COST; - /* Setup Recruiting */ - m = new Market( M_BUY, race, (int)(Wages()*4*ratio), - Population()/(5*Globals->POP_LEVEL), 0, 10000*Globals->POP_LEVEL, 0, 2000 ); - markets.Add(m); - if( Globals->LEADERS_EXIST ) { - ratio=ItemDefs[I_LEADERS].baseprice/(float)Globals->BASE_MAN_COST; - m = new Market( M_BUY, I_LEADERS, (int)(Wages()*4*ratio), - Population()/(25*Globals->POP_LEVEL), 0, 10000, 0, 400 ); - markets.Add(m); - } - } -} - -int ARegion::IsStartingCity() { //This doesn't work in Arcadia - if (town && town->pop == 5000) return 1; - return 0; -} - -int ARegion::IsSafeRegion() -{ - if(type == R_NEXUS) return 1; - return( Globals->SAFE_START_CITIES && IsStartingCity() ); -} - -ARegion *ARegionList::GetStartingCity( ARegion *AC, - int i, - int level, - int maxX, - int maxY ) -{ - ARegionArray *pArr = pRegionArrays[ level ]; - ARegion * reg = 0; - - if( pArr->x < maxX ) maxX = pArr->x; - if( pArr->y < maxY ) maxY = pArr->y; - - int tries = 0; - while (!reg && tries < 10000) { - // - // We'll just let AC exits be all over the map. - // - int x = getrandom( maxX ); - int y = 2 * getrandom( maxY / 2 ) + x % 2; - - reg = pArr->GetRegion( x, y); - - if(!reg || !reg->CanBeStartingCity( pArr )) { - reg = 0; - tries++; - continue; - } - - for (int j=0; jneighbors[j]) continue; - if (GetDistance(reg,AC->neighbors[j]) < maxY / 10 + 2 ) { - reg = 0; - tries++; - break; - } - } - } - - // Okay, we failed to find something that normally would work - // we'll just take anything that's of the right distance - tries = 0; - while (!reg && tries < 10000) { - // - // We couldn't find a normal starting city, let's just go for ANY - // city - // - int x = getrandom( maxX ); - int y = 2 * getrandom( maxY / 2 ) + x % 2; - reg = pArr->GetRegion( x, y); - if (!reg || reg->type == R_OCEAN) { - tries++; - reg = 0; - continue; - } - - for (int j=0; jneighbors[j]) continue; - if (GetDistance(reg,AC->neighbors[j]) < maxY / 10 + 2 ) { - reg = 0; - tries++; - break; - } - } - } - - // Okay, if we still don't have anything, we're done. - return reg; -} -