Allure-0.5.0.0/0000755000000000000000000000000012555263417011276 5ustar0000000000000000Allure-0.5.0.0/CHANGELOG.md0000644000000000000000000001350612555263417013114 0ustar0000000000000000## [v0.5.0.0, aka 'Halfway through space'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.101.0...v0.5.0.0) - let AI put excess items in shared stash and use them out of shared stash - let UI multiple items pickup routine put items that don't fit into equipment into shared stash, if possible, not into inventory pack - re-enable the ability to hear close, invisible foes - add a few more AI and autonomous henchmen tactics (CTRL-T) - keep difficulty setting over session restart - change some game start keybindings - replace the Duel game mode with the Raid game mode - various bugfixes, minor improvements and balancing ## [v0.4.101.1, aka 'Officially fun'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.100.0...v0.4.101.1) - the game is now officially fun to play, with a seal of the Galactic Council - introduce unique boss monsters and unique artifact items - add robots that heal the player, in particular as a mid-game reset for HP - move spaceship airlock to level 10 and beef up spaceship crew - let AI gang up, attempt stealth and react to player aggressiveness - spawn actors fast, close to the enemy and in large numbers - spawn actors less and less often on a given level, but with growing depth - prefer weapons with effects, if recharged - make the bracing melee bonus additive, not multiplicative - let explosions buffet actors around - make braced actors immune to translocation effects - make actor domination yet less common and deadly - use mouse for movement, actor selection, aiming - don't run straight with selected actors, but go-to cross-hair with them - speed up default frame rate, slow down projectiles visually - rework item manipulation UI - you can pick up many items at once and it costs only one turn - allow actors to apply and project from the shared stash - reverse messages shown in player diary - display actor organs and stats - split highscore tables wrt game modes - move score calculation formula to content - don't keep the default/example config file commented out; was misleading - update vs the naughtily changed v0.5.0.0 of LambdaHack content API ## [v0.4.100.0, aka 'The last interstellar thaw'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.99.0...v0.4.100.0) - update vs the unexpectedly thawed v0.5.0.0 of LambdaHack content API - unexpectedly add items with timeouts and temporary effects - start campaign on level 3 and don't spawn aliens until level 4 - rebalance campaign (probably still too hard) - tweak skills of some factions and actors - rename tablets to chips to make their vanishing easier to understand - make colorful characters bold (if it resizes your fonts, turn off via colorIsBold = False in config file or --noColorIsBold on commandline) - start the game with a screensaver safari mode - improve keyboard handling on Windows - add i386 Linux and Windows compilation targets to Makefile ## [v0.4.99.0, aka 'Player escapes through airlock'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.14...v0.4.99.0) - balance game content a bit (campaign still unbalanced) - fix a bug where doors can't be closed - assign AI tactics to players, in particular use follow-the-leader in safari - specify monster spawn rate per-cave - generally update content to the new v0.5.0.0 of LambdaHack content API ## [v0.4.14, aka 'Out of cosmic balance'](https://github.com/AllureOfTheStars/Allure/compare/v0.4.12...v0.4.14) - add tons of new (unbalanced) items, actors and descriptions - add a simple cabal test in addition to make-test and travis-test - add items of Wonder and of Marvel - add game mechanics, items and places to enable stealthy tactics - add lots of shrapnel (explosions) and organs (body parts) - expose a bit of the plot via new game modes and their order ## [v0.4.12](https://github.com/AllureOfTheStars/Allure/compare/v0.4.10...v0.4.12) - make walls lit by default to simplify exploration - improve and simplify dungeon generation - simplify running and permit multi-actor runs - let items explode and generate shrapnel projectiles - add game difficulty setting (initial HP scaling right now) - allow recording, playing back and looping commands - implement pathfinding via per-actor BFS over the whole level - extend setting targets for actors in UI tremendously - implement autoexplore, go-to-target, etc., as macros - let AI use pathfinding, switch leaders, pick levels to swarm to - force level/leader changes on spawners (even when played by humans) - extend and redesign UI bottom status lines ## [v0.4.10](https://github.com/AllureOfTheStars/Allure/compare/v0.4.8...v0.4.10) - screensaver game modes (AI vs AI) - improved AI (can now climbs stairs, etc.) - multiple, multi-floor staircases - multiple savefiles - configurable framerate and combat animations ## [v0.4.8](https://github.com/AllureOfTheStars/Allure/compare/v0.4.6.5...v0.4.8) - experimental multiplayer modes - a lot of gameplay changes induced by the engine overhaul and in particular the client-server rewrite ## [v0.4.6.5](https://github.com/AllureOfTheStars/Allure/compare/v0.4.6...v0.4.6.5) - this is a minor release, primarily intended to fix the broken compilation on Hackage - changes since 0.4.6 are mostly unrelated to gameplay: - strictly typed config files split into UI and rules - a switch from Text to String throughout the codebase - use of the external library miniutter for English sentence generation ## [v0.4.6](https://github.com/AllureOfTheStars/Allure/compare/v0.4.4...v0.4.6) - the Main Menu - improved and configurable mode of squad combat ## [v0.4.4](https://github.com/AllureOfTheStars/Allure/compare/v0.4.3...v0.4.4) - missiles flying for three turns (by an old kosmikus' idea) - visual feedback for targeting - animations of combat and individual monster moves ## [v0.4.3](https://github.com/AllureOfTheStars/Allure/compare/v0.4.2...v0.4.3) - the Allure of the Stars game depends on the LambdaHack engine library Allure-0.5.0.0/CREDITS0000644000000000000000000000027612555263417012323 0ustar0000000000000000All kinds of contributions to Allure of the Stars are gratefully welcome! Some of the contributors are listed below, in chronological order. Andres Loeh Mikolaj Konarski Krzysztof PÅ‚awski Allure-0.5.0.0/LICENSE0000644000000000000000000010333012555263417012303 0ustar0000000000000000 GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU Affero General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Remote Network Interaction; Use with the GNU General Public License. Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU Affero General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . Allure-0.5.0.0/Setup.hs0000644000000000000000000000005712555263417012734 0ustar0000000000000000import Distribution.Simple main = defaultMain Allure-0.5.0.0/README.md0000644000000000000000000001522212555263417012557 0ustar0000000000000000Allure of the Stars [![Build Status](https://travis-ci.org/AllureOfTheStars/Allure.svg?branch=master)](https://travis-ci.org/AllureOfTheStars/Allure)[![Build Status](https://drone.io/github.com/AllureOfTheStars/Allure/status.png)](https://drone.io/github.com/AllureOfTheStars/Allure/latest) =================== [Allure of the Stars] [6] is a near-future Sci-Fi [roguelike] [2] and tactical squad game. Have a look at [PLAYING.md](GameDefinition/PLAYING.md) or jump straight into the fray. ![gameplay screenshot](https://raw.githubusercontent.com/AllureOfTheStars/media/master/screenshot/campaign3.png) The game is written in [Haskell] [1] using the [LambdaHack] [10] roguelike game engine. Long-term goals of the project are high replayability and auto-balancing through procedural content generation and persistent content modification based on player behaviour. Installation from binary archives --------------------------------- Pre-compiled game binaries for some platforms are available through the [release page] [11] and from the [Nix Packages Collection] [12]. To manually install a binary archive, make sure you have the GTK libraries suite on your system, unpack the Allure archive and run the executable in the unpacked directory. On Windows, if you don't already have GTK installed (e.g., for the GIMP picture editor) please download and run (with default settings) the GTK installer from http://sourceforge.net/projects/gtk-win/ Screen and keyboard configuration --------------------------------- The game UI can be configured via a config file. A file with the default settings, the same as built into the binary, is in [GameDefinition/config.ui.default](GameDefinition/config.ui.default). When the game is run for the first time, the file is copied to the official location, which is `~/.Allure/config.ui.ini` on Linux and `C:\Users\\AppData\Roaming\Allure\config.ui.ini` (or `C:\Documents And Settings\user\Application Data\Allure\config.ui.ini` or something else altogether) on Windows. Screen font can be changed and enlarged by editing the config file at its official location or by CTRL-right-clicking on the game window. If you use the numeric keypad, use the NumLock key on your keyboard to toggle the game keyboard mode. With NumLock off, you walk with the numeric keys and run with SHIFT (or CONTROL) and the keys. This mode is probably the best if you use mouse for running. When you turn NumLock on, the reversed key setup enforces good playing habits by setting as the default the run command (which automatically stops at threats, keeping you safe) and requiring SHIFT (or CONTROL) for the error-prone step by step walking. If you don't have the numeric keypad, you can use laptop keys (uk8o79jl) or you can enable the Vi keys (aka roguelike keys) in the config file. Compilation from source ----------------------- If you want to compile your own binaries from the source code, use Cabal (already a part of your OS distribution, or available within [The Haskell Platform] [7]), which also takes care of all the dependencies. You also need the GTK libraries for your OS. On Linux, remember to install the -dev versions as well. On Windows follow [the same steps as for Wine] [13]. On OSX, if you encounter problems, you may want to [compile the GTK libraries from sources] [14]. The latest official version of the game can be downloaded, compiled and installed automatically by Cabal from [Hackage] [3] as follows cabal update cabal install gtk2hs-buildtools cabal install Allure --force-reinstalls For a newer version, install a matching LambdaHack library snapshot from a development branch, download the game source from [github] [5] and run `cabal install` from the main directory. Compatibility notes ------------------- If you are using a terminal frontend, numeric keypad may not work correctly depending on versions of the libraries, terminfo and terminal emulators. The curses frontend is not fully supported due to the limitations of the curses library. With the vty frontend started in an xterm, CTRL-keypad keys for running seem to work OK, but on rxvt they do not. The commands that require pressing CTRL and SHIFT together won't work either, but fortunately they are not crucial to gameplay. For movement, laptop (uk8o79jl) and Vi keys (hjklyubn, if enabled in config.ui.ini) should work everywhere. GTK works fine, too, both with numeric keypad and with mouse. Testing and debugging --------------------- The [Makefile](Makefile) contains many sample test commands. Numerous tests that use the screensaver game modes (AI vs. AI) and the dumb `stdout` frontend are gathered in `make test`. Of these, travis runs `test-travis-*` on each push to the repo. Test commands with prefix `frontend` start AI vs. AI games with the standard, user-friendly gtk frontend. Run `Allure --help` to see a brief description of all debug options. Of these, `--sniffIn` and `--sniffOut` are very useful (though verbose and initially cryptic), for monitoring the traffic between clients and the server. Some options in the config file may prove useful too, though they mostly overlap with commandline options (and will be totally merged at some point). Further information ------------------- For more information, visit the [wiki] [4] and see [PLAYING.md](GameDefinition/PLAYING.md), [CREDITS](CREDITS) and [LICENSE](LICENSE). Have fun! Copyright --------- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski Allure of the Stars is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program in file LICENSE. If not, see . [1]: http://www.haskell.org/ [2]: http://roguebasin.roguelikedevelopment.org/index.php?title=Berlin_Interpretation [3]: http://hackage.haskell.org/package/Allure [4]: https://github.com/AllureOfTheStars/Allure/wiki [5]: http://github.com/AllureOfTheStars/Allure [6]: http://allureofthestars.com [7]: http://www.haskell.org/platform [10]: http://github.com/LambdaHack/LambdaHack [11]: https://github.com/AllureOfTheStars/Allure/releases/latest [12]: http://hydra.cryp.to/search?query=Allure [13]: http://www.haskell.org/haskellwiki/GHC_under_Wine#Code_that_uses_gtk2hs [14]: http://www.edsko.net/2014/04/27/haskell-including-gtk-on-mavericks Allure-0.5.0.0/Makefile0000644000000000000000000004271112555263417012743 0ustar0000000000000000# Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski # This file is a part of the computer game Allure of the Stars # and is released under the terms of the GNU Affero General Public License. # For license and copyright information, see the file LICENSE. # # All xc* tests assume a profiling build (for stack traces). # See the install-debug target below. install-debug: cabal install --enable-library-profiling --enable-executable-profiling --ghc-options="-fprof-auto-calls" --disable-optimization configure-debug: cabal configure --enable-library-profiling --enable-executable-profiling --ghc-options="-fprof-auto-calls" --disable-optimization xcplay: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --dumpInitRngs xcfrontendCampaign: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 1 --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign xcfrontendRaid: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode raid xcfrontendSkirmish: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode skirmish xcfrontendAmbush: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode ambush xcfrontendBattle: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode battle xcfrontendBattleSurvival: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "battle survival" xcfrontendSafari: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode safari xcfrontendSafariSurvival: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "safari survival" xcfrontendDefense: dist/build/Allure/Allure +RTS -xc -RTS --dbgMsgSer --savePrefix test --newGame 9 --maxFps 60 --dumpInitRngs --automateAll --gameMode defense play: dist/build/Allure/Allure --dbgMsgSer --dumpInitRngs frontendCampaign: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --maxFps 60 --dumpInitRngs --automateAll --gameMode campaign frontendRaid: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode raid frontendSkirmish: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode skirmish frontendAmbush: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 60 --dumpInitRngs --automateAll --gameMode ambush frontendBattle: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode battle frontendBattleSurvival: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "battle survival" frontendSafari: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --maxFps 60 --dumpInitRngs --automateAll --gameMode safari frontendSafariSurvival: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --maxFps 60 --dumpInitRngs --automateAll --gameMode "safari survival" frontendDefense: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 9 --maxFps 60 --dumpInitRngs --automateAll --gameMode defense benchCampaign: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode campaign --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS benchBattle: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS benchFrontendCampaign: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --maxFps 100000 --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode campaign --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS benchFrontendBattle: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --maxFps 100000 --benchmark --stopAfter 60 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42 +RTS -N1 -RTS benchNull: benchCampaign benchBattle bench: benchCampaign benchFrontendCampaign benchBattle benchFrontendBattle test-travis-short: test-short test-travis-medium: test-short test-medium test-travis-medium-no-safari: test-short test-medium-no-safari test-travis-long: test-short test-long test-travis-long-no-safari: test-short test-long-no-safari test: test-short test-medium test-long test-short: test-short-new test-short-load test-medium: testCampaign-medium testRaid-medium testSkirmish-medium testAmbush-medium testBattle-medium testBattleSurvival-medium testSafari-medium testSafariSurvival-medium testPvP-medium testCoop-medium testDefense-medium test-medium-no-safari: testCampaign-medium testRaid-medium testSkirmish-medium testAmbush-medium testBattle-medium testBattleSurvival-medium testPvP-medium testCoop-medium testDefense-medium test-long: testCampaign-long testRaid-medium testSkirmish-medium testAmbush-medium testBattle-long testBattleSurvival-long testSafari-long testSafariSurvival-long testPvP-medium testDefense-long test-long-no-safari: testCampaign-long testRaid-medium testSkirmish-medium testAmbush-medium testBattle-long testBattleSurvival-long testPvP-medium testDefense-long testCampaign-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode campaign > /tmp/stdtest.log testCampaign-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 1 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 400 --dumpInitRngs --automateAll --keepAutomated --gameMode campaign > /tmp/stdtest.log testRaid-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode raid > /tmp/stdtest.log testRaid-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode raid > /tmp/stdtest.log testSkirmish-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish > /tmp/stdtest.log testSkirmish-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish > /tmp/stdtest.log testAmbush-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush > /tmp/stdtest.log testAmbush-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode ambush > /tmp/stdtest.log testBattle-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --keepAutomated --gameMode battle > /tmp/stdtest.log testBattle-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 50 --dumpInitRngs --automateAll --keepAutomated --gameMode battle > /tmp/stdtest.log testBattleSurvival-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 100 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" > /tmp/stdtest.log testBattleSurvival-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 50 --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" > /tmp/stdtest.log testSafari-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 250 --dumpInitRngs --automateAll --keepAutomated --gameMode safari > /tmp/stdtest.log testSafari-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --keepAutomated --gameMode safari > /tmp/stdtest.log testSafariSurvival-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 250 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" > /tmp/stdtest.log testSafariSurvival-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 8 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 200 --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" > /tmp/stdtest.log testPvP-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 60 --dumpInitRngs --automateAll --keepAutomated --gameMode PvP > /tmp/stdtest.log testPvP-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 5 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 30 --dumpInitRngs --automateAll --keepAutomated --gameMode PvP > /tmp/stdtest.log testCoop-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode Coop > /tmp/stdtest.log testCoop-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --keepAutomated --gameMode Coop > /tmp/stdtest.log testDefense-long: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 9 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 500 --dumpInitRngs --automateAll --keepAutomated --gameMode defense > /tmp/stdtest.log testDefense-medium: dist/build/Allure/Allure --dbgMsgSer --savePrefix test --newGame 9 --noDelay --noAnim --maxFps 100000 --frontendStd --benchmark --stopAfter 300 --dumpInitRngs --automateAll --keepAutomated --gameMode defense > /tmp/stdtest.log test-short-new: dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix campaign --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix skirmish --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix PvP --dumpInitRngs --automateAll --keepAutomated --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix Coop --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --newGame 5 --savePrefix defense --dumpInitRngs --automateAll --keepAutomated --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log test-short-load: dist/build/Allure/Allure --dbgMsgSer --savePrefix campaign --dumpInitRngs --automateAll --keepAutomated --gameMode campaign --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix raid --dumpInitRngs --automateAll --keepAutomated --gameMode raid --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix skirmish --dumpInitRngs --automateAll --keepAutomated --gameMode skirmish --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix ambush --dumpInitRngs --automateAll --keepAutomated --gameMode ambush --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix battle --dumpInitRngs --automateAll --keepAutomated --gameMode battle --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix battleSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "battle survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix safari --dumpInitRngs --automateAll --keepAutomated --gameMode safari --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix safariSurvival --dumpInitRngs --automateAll --keepAutomated --gameMode "safari survival" --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix PvP --dumpInitRngs --automateAll --keepAutomated --gameMode PvP --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix Coop --dumpInitRngs --automateAll --keepAutomated --gameMode Coop --frontendStd --stopAfter 2 > /tmp/stdtest.log dist/build/Allure/Allure --dbgMsgSer --savePrefix defense --dumpInitRngs --automateAll --keepAutomated --gameMode defense --frontendStd --stopAfter 2 > /tmp/stdtest.log build-binary: cabal configure -frelease --prefix=/ cabal build Allure rm -rf /tmp/Allure_x_ubuntu-12.04-amd64.tar.gz rm -rf /tmp/AllureOfTheStarsInstall rm -rf /tmp/AllureOfTheStars mkdir -p /tmp/AllureOfTheStars/GameDefinition cabal copy --destdir=/tmp/AllureOfTheStarsInstall cp /tmp/AllureOfTheStarsInstall/bin/Allure /tmp/AllureOfTheStars cp GameDefinition/PLAYING.md /tmp/AllureOfTheStars/GameDefinition cp GameDefinition/scores /tmp/AllureOfTheStars/GameDefinition cp GameDefinition/config.ui.default /tmp/AllureOfTheStars/GameDefinition cp CHANGELOG.md /tmp/AllureOfTheStars cp CREDITS /tmp/AllureOfTheStars cp LICENSE /tmp/AllureOfTheStars cp README.md /tmp/AllureOfTheStars tar -czf /tmp/Allure_x_ubuntu-12.04-amd64.tar.gz -C /tmp AllureOfTheStars build-binary-i386: cabal configure -frelease --prefix=/ --ghc-option="-optc-m32" --ghc-option="-opta-m32" --ghc-option="-optl-m32" --ld-option="-melf_i386" cabal build Allure rm -rf /tmp/Allure_x_ubuntu-12.04-i386.tar.gz rm -rf /tmp/AllureOfTheStarsInstall rm -rf /tmp/AllureOfTheStars mkdir -p /tmp/AllureOfTheStars/GameDefinition cabal copy --destdir=/tmp/AllureOfTheStarsInstall cp /tmp/AllureOfTheStarsInstall/bin/Allure /tmp/AllureOfTheStars cp GameDefinition/PLAYING.md /tmp/AllureOfTheStars/GameDefinition cp GameDefinition/scores /tmp/AllureOfTheStars/GameDefinition cp GameDefinition/config.ui.default /tmp/AllureOfTheStars/GameDefinition cp CHANGELOG.md /tmp/AllureOfTheStars cp CREDITS /tmp/AllureOfTheStars cp LICENSE /tmp/AllureOfTheStars cp README.md /tmp/AllureOfTheStars tar -czf /tmp/Allure_x_ubuntu-12.04-i386.tar.gz -C /tmp AllureOfTheStars # TODO: figure out, whey this must be so different from Linux build-binary-windows-i386: wine cabal configure -frelease wine cabal build exe:Allure rm -rf /tmp/Allure_x_windows-i386.zip rm -rf /tmp/AllureOfTheStarsInstall rm -rf /tmp/AllureOfTheStars mkdir -p /tmp/AllureOfTheStars/GameDefinition wine cabal copy --destdir=Z:/tmp/AllureOfTheStarsInstall cp /tmp/AllureOfTheStarsInstall/users/mikolaj/Application\ Data/cabal/bin/Allure.exe /tmp/AllureOfTheStars cp GameDefinition/PLAYING.md /tmp/AllureOfTheStars/GameDefinition cp GameDefinition/scores /tmp/AllureOfTheStars/GameDefinition cp GameDefinition/config.ui.default /tmp/AllureOfTheStars/GameDefinition cp CHANGELOG.md /tmp/AllureOfTheStars cp CREDITS /tmp/AllureOfTheStars cp LICENSE /tmp/AllureOfTheStars cp README.md /tmp/AllureOfTheStars cp /home/mikolaj/.wine/drive_c/users/mikolaj/gtk/bin/zlib1.dll /tmp/AllureOfTheStars wine Z:/home/mikolaj/.local/share/wineprefixes/7zip/drive_c/Program\ Files/7-Zip/7z.exe a -ssc -sfx Z:/tmp/Allure_x_windows-i386.exe Z:/tmp/AllureOfTheStars Allure-0.5.0.0/Allure.cabal0000644000000000000000000001174212555263417013513 0ustar0000000000000000name: Allure -- The package version. See the Haskell package versioning policy (PVP) -- for standards guiding when and how versions should be incremented. -- http://www.haskell.org/haskellwiki/Package_versioning_policy -- PVP summary:+-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change version: 0.5.0.0 synopsis: Near-future Sci-Fi roguelike and tactical squad game description: Allure of the Stars is a near-future Sci-Fi roguelike and tactical squad game. See the wiki for design notes and contribute. . <> . Please see the changelog file for recent improvements and the issue tracker for short-term plans. Long term goals are high replayability and auto-balancing through procedural content generation and persistent content modification based on player behaviour. . The game is written using the LambdaHack roguelike game engine available at . homepage: http://allureofthestars.com bug-reports: http://github.com/AllureOfTheStars/Allure/issues license: AGPL-3 license-file: LICENSE tested-with: GHC == 7.6, GHC == 7.8, GHC == 7.10 data-files: GameDefinition/config.ui.default, GameDefinition/scores, GameDefinition/PLAYING.md, README.md, LICENSE, CREDITS, CHANGELOG.md extra-source-files: GameDefinition/MainMenu.ascii, Makefile author: Andres Loeh, Mikolaj Konarski and others maintainer: Mikolaj Konarski category: Game build-type: Simple cabal-version: >= 1.10 source-repository head type: git location: git://github.com/AllureOfTheStars/Allure.git flag release description: prepare for a release (expose, optimize, etc.) default: True manual: True executable Allure hs-source-dirs: GameDefinition main-is: Main.hs other-modules: Client.UI.Content.KeyKind, Content.CaveKind, Content.ItemKind, Content.ItemKindActor, Content.ItemKindOrgan, Content.ItemKindBlast, Content.ItemKindTemporary, Content.ModeKind, Content.ModeKindPlayer, Content.PlaceKind, Content.RuleKind, Content.TileKind, TieKnot, Paths_Allure build-depends: LambdaHack >= 0.5.0.0 && < 0.5.1.0, template-haskell >= 2.6 && < 3, base >= 4 && < 5, containers >= 0.5.3.0 && < 1, enummapset-th >= 0.6.0.0 && < 1, filepath >= 1.2.0.1 && < 2, text >= 0.11.2.3 && < 2 default-language: Haskell2010 default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings BangPatterns, RecordWildCards, NamedFieldPuns other-extensions: TemplateHaskell ghc-options: -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -fwarn-unrecognised-pragmas ghc-options: -fno-warn-auto-orphans -fno-warn-implicit-prelude ghc-options: -fno-ignore-asserts -funbox-strict-fields ghc-options: -threaded "-with-rtsopts=-C0.005" -rtsopts if flag(release) ghc-options: -O2 -fno-ignore-asserts "-with-rtsopts=-N1" -- TODO: -N test-suite test type: exitcode-stdio-1.0 hs-source-dirs: GameDefinition, test main-is: test.hs build-depends: LambdaHack, template-haskell >= 2.6 && < 3, base >= 4 && < 5, containers >= 0.5.3.0 && < 1, enummapset-th >= 0.6.0.0 && < 1, filepath >= 1.2.0.1 && < 2, text >= 0.11.2.3 && < 2 default-language: Haskell2010 default-extensions: MonoLocalBinds, ScopedTypeVariables, OverloadedStrings BangPatterns, RecordWildCards, NamedFieldPuns other-extensions: TemplateHaskell ghc-options: -Wall -fwarn-orphans -fwarn-tabs -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates -fwarn-monomorphism-restriction -fwarn-unrecognised-pragmas ghc-options: -fno-warn-auto-orphans -fno-warn-implicit-prelude ghc-options: -fno-ignore-asserts -funbox-strict-fields ghc-options: -threaded "-with-rtsopts=-C0.005" -rtsopts if flag(release) ghc-options: -O2 -fno-ignore-asserts "-with-rtsopts=-N1" -- TODO: -N Allure-0.5.0.0/GameDefinition/0000755000000000000000000000000012555263417014160 5ustar0000000000000000Allure-0.5.0.0/GameDefinition/MainMenu.ascii0000644000000000000000000000415612555263417016711 0ustar0000000000000000---------------------------------------------------------------------------------- | | | >> Allure of the Stars << | | | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | {{{{{{{{{{{{{{{{{{{{{{{{{ | | | | | | Version X.X.X (frontend: gtk, engine: LambdaHack X.X.X) | ---------------------------------------------------------------------------------- Allure-0.5.0.0/GameDefinition/Main.hs0000644000000000000000000000122412555263417015377 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | The main source code file of Allure of the Stars. -- Module "TieKnot" is separated to make it usable in tests. module Main ( main ) where import System.Environment (getArgs) import TieKnot -- | Tie the LambdaHack engine client, server and frontend code -- with the game-specific content definitions, and run the game. main :: IO () main = do args <- getArgs tieKnot args Allure-0.5.0.0/GameDefinition/scores0000644000000000000000000000170212555263417015401 0ustar0000000000000000xœ¥VMLAÝ™ÝþH BD=¨±‰QÆ„‹!ñ" ‰#R‰‰*,¸¡\0¨!áàI=y1‰0Ñ(PÑJñÿDE8y0CEÄÝ2oºvS[ã\æíîÌ|ß{󿛄`³ ¬‰‹]\`AkµÃ§Ówît!ì³¥.scëU‰=Åa–…õK÷Vx åb*«®mª\Í^“N(ë×øpÞg ¾K°=Àì>DégÀþ³ö#±ò ~Ê@Â3€A¬üD^`ð+|z 0„à 1Â@Ò¬o1ø>bå÷ ,ùcÌúq]êÁ##~ÁÝž6fº)óRŠ6X°±>‚Ô´ºð†õ‰~¼€æšK ,…°zÈH #1ÉH #DHÄ•‘  éôç{Ú\šÓfCô…¡Škå Qé‡[Žš2ᡘçé=“o)M‚[¹‘k؈/ƒ x}´LМp/YâÚ´Ä$2åJ¾à†Dþ"”á1d\­™RtI“ç D ê×"±X‰p%¹YÛ®Gùuj•&W¡(éõŸ®ülÛG{Ôx£Njþ€Á'ÙÎÙ$ñÃñ ‘üBÖëá~ÌmÖNeKÉ AÆT÷»(§R¼i¢‰ã‰…©yëÛ‚¶¼§•ŸüæÙ†LNÖ_/Û|8ñø‚ÃJ•ìÚá©,•½^9Ð_ÈhŠ h nþ(¸óÄC5[èN †±n¹Å“’Úõ(³_'4Wµ|¶\Õ°u5fñ(¸·"¹*lõÐ ¸ëXT÷”NJj4¸*mò„)\4G Gð†Åu´ãÙ+Ïy.׿0Zt(¢˜Ë3Ô2¹È!z7ëyÅw â[QñpËJ¼<¡ôóòDPžD”'Ê“„;€×)ŠªdGU¢¨J"n>hÞ,%‰uwû”a‹›W‚²-ÄÆJI lã—(‡n2+ëÏê‰}ŸÒj‚;¯Öp =5W"ÓOOr†W‘}®üò£ªRYåÊ).V ep÷3`E>ù€—•üÛ‚­à÷å)Co Ó‘d¯žûôd@ϽÚeÈ]ÍM=ƒ”M†Z—áSÊ<^×nO‰OÑóöUi Ë…J™ÆhŸGUäªãl¨W¬»¦«í/™s§à$pi¨IÑñ'¹¸9ܤe“ö7ªô©†ÒÓ•ÕïŒø7ÓÆX]Dt¸Â‰»Æ@˜šþD%H`ÁŸ(?>V+?>èsvýíñ¤YAllure-0.5.0.0/GameDefinition/PLAYING.md0000644000000000000000000002574012555263417015615 0ustar0000000000000000Playing Allure of the Stars =========================== Your party of trusted crew-members is about to test their fortune by exploring an abandoned Solar System passenger cruiser. You are going to set up ambushes for it's feral denizens, hide in shadows, cover tracks, bump into unspeakable horrors, hidden mechanisms and astounding technical treasures and make creative use of it all. The mysterious inhabitants of the gigantic spaceship are bound to welcome intruders with bloody surprises of their own. As soon as you turn your back in fear, expect to be chased tirelessly throughout all the decks, by sight, sound and smell. Once the few basic command keys and on-screen symbols are learned, mastery and enjoyment of the game is the matter of tactical skill and literary imagination. To be honest, a lot of imagination is required at this stage of game development, but the game is already playable and winnable. Contributions are welcome. Heroes ------ The heroes are marked on the map with symbols `@` and `1` through `9`. Their goal is to explore a warped, old, once luxurious space liner, battle the horrors within, gather as much gold and precious gems as possible, and escape to tell the tale. The currently chosen party leader is highlighted on the screen and his attributes are displayed at the bottommost status line, which in its most complex form may look as follows. *@12 Adventurer 4d1+5% Calm: 20/60 HP: 33/50 Target: basilisk [**__] The line starts with the list of party members (unless there's only one member) and the shortened name of the team. Clicking on the list selects heroes and the selected run together when `:` or `SHIFT`-left mouse button is pressed. Then comes the damage of the highest damage dice weapon the leader can use, then his current and maximum Calm (composure, focus, attentiveness), then his current and maximum HP (hit points, health). At the end, the personal target of the leader is described, in this case a basilisk monster, with hit points drawn as a bar. Weapon damage and other item stats are displayed using the dice notation `XdY`, which means X rolls of Y-sided dice. A variant denoted `XdsY` is additionally scaled by the level depth in proportion to the maximal spaceship depth. You can read more about combat resolution in section Monsters below. The second status line describes the current level in relation to the party. 5 Lofty hall [33% seen] X-hair: exact spot (71,12) p15 l10 First comes the depth of the current level and its name. Then the percentage of its explorable tiles already seen by the heroes. The 'X-hair' (meaning 'crosshair') is the common focus of the whole party, denoted on the map by a white box and manipulated with movement keys in aiming mode. At the end of the status line comes the length of the shortest path from the leader to the crosshair position and the straight-line distance between the two points. Spaceship --------- The spaceship and other scenario locations consist of one or many levels or decks and each deck consists of a large number of tiles. The basic tile kinds are as follows. terrain type on-screen symbol floor . wall # rock or tree O cache & stairs up < stairs down > open door ' closed door + The game world is persistent, i.e., every time the player visits a deck during a single game, its layout is the same. Commands -------- You walk throughout a level using the left mouse button or the numeric keypad (left diagram) or its compact laptop replacement (middle) or Vi text editor keys (right, also known as "Rogue-like keys", which have to be enabled in config.ui.ini). 7 8 9 7 8 9 y k u \|/ \|/ \|/ 4-5-6 u-i-o h-.-l /|\ /|\ /|\ 1 2 3 j k l b j n In aiming mode (`KEYPAD_*` or `\`) the same keys (or the middle and right mouse buttons) move the crosshair (the white box). In normal mode, `SHIFT` (or `CTRL`) and a movement key make the current party leader run in the indicated direction, until anything of interest is spotted. The `5` keypad key and the `i` and `.` keys consume a turn and make you brace for combat, which reduces any damage taken for a turn and makes it impossible for foes to displace you. You displace enemies or friends by bumping into them with `SHIFT` (or `CTRL`). Melee, searching for secret doors, looting and opening closed doors can be done by bumping into a monster, a wall and a door, respectively. Few commands other than movement, 'g'etting an item from the floor, 'a'pplying an item and 'f'linging an item are necessary for casual play. Some are provided only as specialized versions of the more general commands or as building blocks for more complex convenience macros. E.g., the autoexplore command (key `X`) could be defined by the player as a macro using `CTRL-?`, `CTRL-.` and `V`. The following minimal command set lets you accomplish almost anything in the game, though not necessarily with the fewest number of keystrokes. The full list of commands can be seen in the in-game help accessible from the Main Menu. keys command < ascend a level > descend a level c close door E manage equipment of the leader g or , get items a apply consumable f fling projectile + swerve the aiming line D display player diary T toggle suspect terrain display SHIFT-TAB cycle among all party members ESC cancel action, open Main Menu The only activity not possible with the commands above is the management of non-leader party members. You don't need it, unless your non-leader actors can move or fire opportunistically (via innate skills or rare equipment). If really needed, you can manually set party tactics with `CTRL-T` and you can assign individual targets to party members using the aiming and targeting commands listed below. keys command KEYPAD_* or \ aim at an enemy KEYPAD_/ or | cycle aiming styles + swerve the aiming line - unswerve the aiming line CTRL-? set crosshair to the closest unknown spot CTRL-I set crosshair to the closest item CTRL-{ set crosshair to the closest stairs up CTRL-} set crosshair to the closest stairs down BACKSPACE reset target/crosshair RET or INSERT accept target/choice For ranged attacks, setting the crosshair or individual targets beforehand is not mandatory, because the crosshair is set automatically as soon as a monster comes into view and can still be adjusted while in the missile choice menu. However, if you want to assign persistent personal targets or just inspect the level map closely, you can enter the detailed aiming mode with the right mouse button or with the `*` keypad key that selects enemies or the `/` keypad key that marks a tile. You can move the aiming crosshair with direction keys and assign a personal target to the leader with `RET`. The details of the shared crosshair position and of the personal target are described in the status lines at the bottom of the screen. Commands for saving and exiting the current game, starting a new game, etc., are listed in the Main Menu, brought up by the `ESC` key. Game difficulty setting affects hitpoints at birth for any actors of any UI-using faction. For a person new to roguelikes, the Raid scenario offers a gentle introduction. The subsequent game modes gradually introduce squad combat, stealth, opportunity fire, asymmetric battles and more. Monsters -------- Heroes are not alone in the spaceship. Monstrosities, natural and out of this world, roam the dark halls and crawl from damp air-ducts day and night. While heroes pay attention to all other party members and take care to move one at a time, monsters don't care about each other and all move at once, sometimes brutally colliding by accident. When the hero bumps into a monster or a monster attacks the hero, melee combat occurs. Heroes and monsters running into one another (with the `SHIFT` key) do not inflict damage, but change places. This gives the opponent a free blow, but can improve the tactical situation or aid escape. In some circumstances actors are immune to the displacing, e.g., when both parties form a continuous front-line. In melee combat, the best equipped weapon (or the best fighting organ) of each opponent is taken into account for determining the damage and any extra effects of the blow. If a recharged weapon with a non-trivial effect is in the equipment, it is preferred for combat. Otherwise combat involves the weapon with the highest raw damage dice (the same as displayed at bottommost status line). To determine the damage dealt, the outcome of the weapon's damage dice roll is multiplied by the melee damage bonus (summed from the equipped items of the attacker) minus the melee armor modifier of the defender. Regardless of the calculation, each attack inflicts at least 1 damage. The current leader's melee bonus, armor modifier and other detailed stats can be viewed via the `!` command. In ranged combat, the missile is assumed to be attacking the defender in melee, using itself as the weapon, but the ranged damage bonus and the ranged armor modifier are taken into account for calculations. You may propel any item in your equipment, inventory pack and on the ground (by default you are offered only the appropriate items; press `?` to cycle item menu modes). Only items of a few kinds inflict any damage, but some have other effects, beneficial, detrimental or mixed. Whenever the monster's or hero's hit points reach zero, the combatant dies. When the last hero dies, the scenario ends in defeat. On Winning and Dying -------------------- You win the scenario if you escape the spaceship alive or, in scenarios with no exit locations, if you eliminate all opposition. In the former case, your score is based on the gold and precious gems you've plundered. In the latter case, your score is based on the number of turns you spent overcoming your foes (the quicker the victory, the better; the slower the demise, the better). Bonus points, based on the number of heroes lost, are awarded if you win. When all your heroes fall, you are going to invariably see a new foolhardy party of adventurers clamoring to be led into the spaceship. They start their conquest from a new entrance, with no experience and no equipment, and new, undaunted enemies bar their way. Lead the new hopeful explorers to fame, wealth and glory! Allure-0.5.0.0/GameDefinition/TieKnot.hs0000644000000000000000000000503112555263417016070 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Here the knot of engine code pieces and the game-specific -- content definitions is tied, resulting in an executable game. module TieKnot ( tieKnot ) where import qualified Client.UI.Content.KeyKind as Content.KeyKind import qualified Content.CaveKind import qualified Content.ItemKind import qualified Content.ModeKind import qualified Content.PlaceKind import qualified Content.RuleKind import qualified Content.TileKind import Game.LambdaHack.Client import qualified Game.LambdaHack.Common.Kind as Kind import Game.LambdaHack.SampleImplementation.SampleMonadClient (executorCli) import Game.LambdaHack.SampleImplementation.SampleMonadServer (executorSer) import Game.LambdaHack.Server -- | Tie the LambdaHack engine client, server and frontend code -- with the game-specific content definitions, and run the game. tieKnot :: [String] -> IO () tieKnot args = do let -- Common content operations, created from content definitions. -- Evaluated fully to discover errors ASAP and free memory. !copsSlow = Kind.COps { cocave = Kind.createOps Content.CaveKind.cdefs , coitem = Kind.createOps Content.ItemKind.cdefs , comode = Kind.createOps Content.ModeKind.cdefs , coplace = Kind.createOps Content.PlaceKind.cdefs , corule = Kind.createOps Content.RuleKind.cdefs , cotile = Kind.createOps Content.TileKind.cdefs } !copsShared = speedupCOps False copsSlow -- Client content operations. copsClient = Content.KeyKind.standardKeys sdebugNxt <- debugArgs args -- Fire up the frontend with the engine fueled by content. -- The action monad types to be used are determined by the 'exeSer' -- and 'executorCli' calls. If other functions are used in their place -- the types are different and so the whole pattern of computation -- is different. Which of the frontends is run depends on the flags supplied -- when compiling the engine library. let exeServer executorUI executorAI = executorSer $ loopSer copsShared sdebugNxt executorUI executorAI -- Currently a single frontend is started by the server, -- instead of each client starting it's own. srtFrontend (executorCli . loopUI) (executorCli . loopAI) copsClient copsShared (sdebugCli sdebugNxt) exeServer Allure-0.5.0.0/GameDefinition/config.ui.default0000644000000000000000000000350012555263417017405 0ustar0000000000000000; Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski ; This file is a part of the computer game Allure of the Stars ; and is released under the terms of the GNU Affero General Public License. ; For license and copyright information, see the file LICENSE. ; ; This is a copy of the default UI settings config file ; that is embedded in the game binary. A user config file can override ; these options. Option names are case-sensitive and only ';' for comments ; is permitted. ; ; The game looks for the config file at the same path where saved games ; directory is located. E.g. on Linux the file is at ; ~/.Allure/config.ui.ini ; and on Windows it can be at ; C:\Documents And Settings\user\Application Data\Allure\config.ui.ini ; or at ; C:\Users\\AppData\Roaming\Allure\config.ui.ini ; or elsewhere. [extra_commands] ; A handy shorthand with Vi keys Macro_1 = ("comma", ([CmdItem], Macro "" ["g"])) ; Angband compatibility (accept target) Macro_2 = ("KP_Insert", ([CmdMeta], Macro "" ["Return"])) [hero_names] HeroName_0 = ("Haskell Alvin", "he") HeroName_1 = ("Alonzo Barkley", "he") HeroName_2 = ("Ines Galenti", "she") HeroName_3 = ("Ernst Abraham", "he") HeroName_4 = ("Samuel Saunders", "he") HeroName_5 = ("Roger Robin", "he") HeroName_6 = ("Christopher Flatt", "he") [ui] movementViKeys_hjklyubn = False movementLaptopKeys_uk8o79jl = True ; Monospace fonts that have fixed size regardless of boldness (on some OSes) font = "Terminus,DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace normal normal normal normal 14" ;font = "Terminus,DejaVu Sans Mono,Consolas,Courier New,Liberation Mono,Courier,FreeMono,Monospace normal normal normal normal 18" colorIsBold = True ; New historyMax takes effect after removal of savefiles. historyMax = 5000 maxFps = 30 noAnim = False runStopMsgs = False Allure-0.5.0.0/GameDefinition/Content/0000755000000000000000000000000012555263417015572 5ustar0000000000000000Allure-0.5.0.0/GameDefinition/Content/ItemKindBlast.hs0000644000000000000000000003470712555263417020633 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Blast definitions. module Content.ItemKindBlast ( blasts ) where import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind blasts :: [ItemKind] blasts = [burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, vulnerabilityBalm, hasteSpray, slownessSpray, eyeDrop, smellyDroplet, whiskeySpray] burningOil2, burningOil3, burningOil4, explosionBlast2, explosionBlast10, explosionBlast20, firecracker2, firecracker3, firecracker4, firecracker5, firecracker6, firecracker7, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, waste, glassPiece, smoke, boilingWater, glue, spark, mistAntiSlow, mistAntidote, mistStrength, mistWeakness, protectingBalm, vulnerabilityBalm, hasteSpray, slownessSpray, eyeDrop, smellyDroplet, whiskeySpray :: ItemKind -- * Parameterized immediate effect blasts burningOil :: Int -> ItemKind burningOil n = ItemKind { isymbol = '*' , iname = "burning oil" , ifreq = [(toGroupName $ "burning oil" <+> tshow n, 1)] , iflavour = zipFancy [BrYellow] , icount = intToDice (n * 5) , irarity = [(1, 1)] , iverbHit = "burn" , iweight = 1 , iaspects = [AddLight 2] , ieffects = [Burn 1, Paralyze 1] -- tripping on oil , ifeature = [ toVelocity (min 100 $ n * 7) , Fragile, Identified ] , idesc = "Sticky oil, burning brightly." , ikit = [] } burningOil2 = burningOil 2 burningOil3 = burningOil 3 burningOil4 = burningOil 4 explosionBlast :: Int -> ItemKind explosionBlast n = ItemKind { isymbol = '*' , iname = "blast" , ifreq = [(toGroupName $ "blast" <+> tshow n, 1)] , iflavour = zipPlain [BrRed] , icount = 15 -- strong, but few, so not always hits target , irarity = [(1, 1)] , iverbHit = "tear apart" , iweight = 1 , iaspects = [AddLight $ intToDice n] , ieffects = [RefillHP (- n `div` 2)] ++ [PushActor (ThrowMod (100 * (n `div` 5)) 50)] ++ [DropItem COrgan "temporary conditions" True | n >= 10] , ifeature = [Fragile, toLinger 20, Identified] , idesc = "" , ikit = [] } explosionBlast2 = explosionBlast 2 explosionBlast10 = explosionBlast 10 explosionBlast20 = explosionBlast 20 firecracker :: Int -> ItemKind firecracker n = ItemKind { isymbol = '*' , iname = "firecracker" , ifreq = [(toGroupName $ "firecracker" <+> tshow n, 1)] , iflavour = zipPlain [brightCol !! (n `mod` length brightCol)] , icount = intToDice (n `div` 6) + d (n `div` 2) , irarity = [(1, 1)] , iverbHit = "crack" , iweight = 1 , iaspects = [AddLight $ intToDice $ n `div` 2] , ieffects = [ RefillCalm (-1) | n >= 5 ] ++ [ DropBestWeapon | n >= 5] ++ [ OnSmash (Explode $ toGroupName $ "firecracker" <+> tshow (n - 1)) | n > 2 ] , ifeature = [ ToThrow $ ThrowMod (10 + 3 * n) (10 + 100 `div` n) , Fragile, Identified ] , idesc = "" , ikit = [] } firecracker7 = firecracker 7 firecracker6 = firecracker 6 firecracker5 = firecracker 5 firecracker4 = firecracker 4 firecracker3 = firecracker 3 firecracker2 = firecracker 2 -- * Assorted immediate effect blasts fragrance = ItemKind { isymbol = '\'' , iname = "fragrance" , ifreq = [("fragrance", 1)] , iflavour = zipFancy [Magenta] , icount = 20 , irarity = [(1, 1)] , iverbHit = "engulf" , iweight = 1 , iaspects = [] , ieffects = [Impress] -- Linger 10, because sometimes it takes 2 turns due to starting just -- before actor turn's end (e.g., via a necklace). , ifeature = [ ToThrow $ ThrowMod 28 10 -- 2 steps, one turn , Fragile, Identified ] , idesc = "" , ikit = [] } pheromone = ItemKind { isymbol = '\'' , iname = "musky whiff" , ifreq = [("pheromone", 1)] , iflavour = zipFancy [BrMagenta] , icount = 18 , irarity = [(1, 1)] , iverbHit = "tempt" , iweight = 1 , iaspects = [] , ieffects = [Impress, OverfillCalm (-20)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } mistCalming = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("calming mist", 1)] , iflavour = zipFancy [White] , icount = 19 , irarity = [(1, 1)] , iverbHit = "sooth" , iweight = 1 , iaspects = [] , ieffects = [RefillCalm 2] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } odorDistressing = ItemKind { isymbol = '\'' , iname = "distressing whiff" , ifreq = [("distressing odor", 1)] , iflavour = zipFancy [BrRed] , icount = 10 , irarity = [(1, 1)] , iverbHit = "distress" , iweight = 1 , iaspects = [] , ieffects = [OverfillCalm (-20)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } mistHealing = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("healing mist", 1)] , iflavour = zipFancy [White] , icount = 9 , irarity = [(1, 1)] , iverbHit = "revitalize" , iweight = 1 , iaspects = [AddLight 1] , ieffects = [RefillHP 2] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } mistHealing2 = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("healing mist 2", 1)] , iflavour = zipFancy [White] , icount = 8 , irarity = [(1, 1)] , iverbHit = "revitalize" , iweight = 1 , iaspects = [AddLight 2] , ieffects = [RefillHP 4] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } mistWounding = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("wounding mist", 1)] , iflavour = zipFancy [White] , icount = 7 , irarity = [(1, 1)] , iverbHit = "devitalize" , iweight = 1 , iaspects = [] , ieffects = [RefillHP (-2)] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } distortion = ItemKind { isymbol = 'v' , iname = "vortex" , ifreq = [("distortion", 1)] , iflavour = zipFancy [White] , icount = 6 , irarity = [(1, 1)] , iverbHit = "engulf" , iweight = 1 , iaspects = [] , ieffects = [Teleport $ 15 + d 10] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } waste = ItemKind { isymbol = '*' , iname = "waste" , ifreq = [("waste", 1)] , iflavour = zipPlain [Brown] , icount = 18 , irarity = [(1, 1)] , iverbHit = "splosh" , iweight = 50 , iaspects = [] , ieffects = [RefillHP (-1)] , ifeature = [ ToThrow $ ThrowMod 28 10 -- 2 steps, one turn , Fragile, Identified ] , idesc = "" , ikit = [] } glassPiece = ItemKind -- when blowing up windows { isymbol = '*' , iname = "glass piece" , ifreq = [("glass piece", 1)] , iflavour = zipPlain [BrBlue] , icount = 18 , irarity = [(1, 1)] , iverbHit = "cut" , iweight = 10 , iaspects = [] , ieffects = [Hurt (1 * d 1)] , ifeature = [toLinger 20, Fragile, Identified] , idesc = "" , ikit = [] } smoke = ItemKind -- when stuff burns out { isymbol = '\'' , iname = "smoke" , ifreq = [("smoke", 1)] , iflavour = zipPlain [BrBlack] , icount = 19 , irarity = [(1, 1)] , iverbHit = "choke" , iweight = 1 , iaspects = [] , ieffects = [] , ifeature = [ toVelocity 21, Fragile, Identified ] , idesc = "" , ikit = [] } boilingWater = ItemKind { isymbol = '*' , iname = "boiling water" , ifreq = [("boiling water", 1)] , iflavour = zipPlain [BrWhite] , icount = 21 , irarity = [(1, 1)] , iverbHit = "boil" , iweight = 5 , iaspects = [] , ieffects = [Burn 1] , ifeature = [toVelocity 50, Fragile, Identified] , idesc = "" , ikit = [] } glue = ItemKind { isymbol = '*' , iname = "sticky foam" , ifreq = [("glue", 1)] , iflavour = zipPlain [BrYellow] , icount = 20 , irarity = [(1, 1)] , iverbHit = "glue" , iweight = 20 , iaspects = [] , ieffects = [Paralyze (3 + d 3)] , ifeature = [toVelocity 40, Fragile, Identified] , idesc = "" , ikit = [] } spark = ItemKind { isymbol = '\'' , iname = "spark" , ifreq = [("spark", 1)] , iflavour = zipPlain [BrYellow] , icount = 17 , irarity = [(1, 1)] , iverbHit = "burn" , iweight = 1 , iaspects = [AddLight 4] , ieffects = [Burn 1] , ifeature = [Fragile, toLinger 10, Identified] , idesc = "" , ikit = [] } mistAntiSlow = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("anti-slow mist", 1)] , iflavour = zipPlain [BrRed] , icount = 7 , irarity = [(1, 1)] , iverbHit = "propel" , iweight = 1 , iaspects = [] , ieffects = [DropItem COrgan "slow 10" True] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } mistAntidote = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("antidote mist", 1)] , iflavour = zipPlain [BrBlue] , icount = 8 , irarity = [(1, 1)] , iverbHit = "cure" , iweight = 1 , iaspects = [] , ieffects = [DropItem COrgan "poisoned" True] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } -- * Assorted temporary condition blasts mistStrength = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("strength mist", 1)] , iflavour = zipFancy [Red] , icount = 6 , irarity = [(1, 1)] , iverbHit = "strengthen" , iweight = 1 , iaspects = [] , ieffects = [toOrganActorTurn "strengthened" (3 + d 3)] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } mistWeakness = ItemKind { isymbol = '\'' , iname = "mist" , ifreq = [("weakness mist", 1)] , iflavour = zipFancy [Blue] , icount = 5 , irarity = [(1, 1)] , iverbHit = "weaken" , iweight = 1 , iaspects = [] , ieffects = [toOrganGameTurn "weakened" (3 + d 3)] , ifeature = [ toVelocity 7 -- the slowest that gets anywhere (1 step only) , Fragile, Identified ] , idesc = "" , ikit = [] } protectingBalm = ItemKind { isymbol = '\'' , iname = "balm droplet" , ifreq = [("protecting balm", 1)] , iflavour = zipPlain [Brown] , icount = 13 , irarity = [(1, 1)] , iverbHit = "balm" , iweight = 1 , iaspects = [] , ieffects = [toOrganActorTurn "protected" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } vulnerabilityBalm = ItemKind { isymbol = '\'' , iname = "red paint" , ifreq = [("red paint", 1)] , iflavour = zipPlain [BrRed] , icount = 14 , irarity = [(1, 1)] , iverbHit = "paint" , iweight = 1 , iaspects = [] , ieffects = [toOrganGameTurn "painted red" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } hasteSpray = ItemKind { isymbol = '\'' , iname = "haste spray" , ifreq = [("haste spray", 1)] , iflavour = zipPlain [BrRed] , icount = 15 , irarity = [(1, 1)] , iverbHit = "haste" , iweight = 1 , iaspects = [] , ieffects = [toOrganActorTurn "fast 20" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } slownessSpray = ItemKind { isymbol = '\'' , iname = "slowness spray" , ifreq = [("slowness spray", 1)] , iflavour = zipPlain [BrBlue] , icount = 16 , irarity = [(1, 1)] , iverbHit = "slow" , iweight = 1 , iaspects = [] , ieffects = [toOrganGameTurn "slow 10" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } eyeDrop = ItemKind { isymbol = '\'' , iname = "eye drop" , ifreq = [("eye drop", 1)] , iflavour = zipPlain [BrGreen] , icount = 17 , irarity = [(1, 1)] , iverbHit = "cleanse" , iweight = 1 , iaspects = [] , ieffects = [toOrganActorTurn "far-sighted" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } smellyDroplet = ItemKind { isymbol = '\'' , iname = "smelly droplet" , ifreq = [("smelly droplet", 1)] , iflavour = zipPlain [Blue] , icount = 18 , irarity = [(1, 1)] , iverbHit = "sensitize" , iweight = 1 , iaspects = [] , ieffects = [toOrganActorTurn "keen-smelling" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } whiskeySpray = ItemKind { isymbol = '\'' , iname = "whiskey spray" , ifreq = [("whiskey spray", 1)] , iflavour = zipPlain [Brown] , icount = 19 , irarity = [(1, 1)] , iverbHit = "inebriate" , iweight = 1 , iaspects = [] , ieffects = [toOrganActorTurn "drunk" (3 + d 3)] , ifeature = [ toVelocity 13 -- the slowest that travels at least 2 steps , Fragile, Identified ] , idesc = "" , ikit = [] } Allure-0.5.0.0/GameDefinition/Content/ItemKindOrgan.hs0000644000000000000000000002716112555263417020630 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Organ definitions. module Content.ItemKindOrgan ( organs ) where import qualified Data.EnumMap.Strict as EM import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind organs :: [ItemKind] organs = [fist, foot, claw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, razor, thorn, boilingFissure, biogasFissure, medbotFissure, insectMortality, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, liveWire, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision6, vision8, vision10, vision12, vision14, vision16, nostril, sapientBrain, animalBrain, robotBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, biogasVent, medbotVent, wasteContainer, spotlight, bonusHP] fist, foot, claw, smallClaw, snout, smallJaw, jaw, largeJaw, horn, tentacle, razor, thorn, boilingFissure, biogasFissure, medbotFissure, insectMortality, beeSting, sting, venomTooth, venomFang, screechingBeak, largeTail, liveWire, armoredSkin, eye2, eye3, eye4, eye5, eye6, eye7, eye8, vision4, vision6, vision8, vision10, vision12, vision14, vision16, nostril, sapientBrain, animalBrain, robotBrain, speedGland2, speedGland4, speedGland6, speedGland8, speedGland10, scentGland, boilingVent, biogasVent, medbotVent, wasteContainer, spotlight, bonusHP :: ItemKind -- Weapons -- * Human weapon organs fist = ItemKind { isymbol = '%' , iname = "fist" , ifreq = [("fist", 100)] , iflavour = zipPlain [Red] , icount = 2 , irarity = [(1, 1)] , iverbHit = "punch" , iweight = 2000 , iaspects = [] , ieffects = [Hurt (4 * d 1)] , ifeature = [Durable, Identified] , idesc = "" , ikit = [] } foot = fist { iname = "foot" , ifreq = [("foot", 50)] , icount = 2 , iverbHit = "kick" , ieffects = [Hurt (4 * d 1)] , idesc = "" } -- * Universal weapon organs claw = fist { iname = "claw" , ifreq = [("claw", 50)] , icount = 2 -- even if more, only the fore claws used for fighting , iverbHit = "hook" , iaspects = [Timeout $ 4 + d 4] , ieffects = [Hurt (2 * d 1), Recharging (toOrganGameTurn "slow 10" 2)] , idesc = "" } smallClaw = fist { iname = "small claw" , ifreq = [("small claw", 50)] , icount = 2 , iverbHit = "slash" , ieffects = [Hurt (2 * d 1)] , idesc = "" } snout = fist { iname = "snout" , ifreq = [("snout", 10)] , iverbHit = "bite" , ieffects = [Hurt (2 * d 1)] , idesc = "" } smallJaw = fist { iname = "small jaw" , ifreq = [("small jaw", 20)] , icount = 1 , iverbHit = "rip" , ieffects = [Hurt (3 * d 1)] , idesc = "" } jaw = fist { iname = "jaw" , ifreq = [("jaw", 20)] , icount = 1 , iverbHit = "rip" , ieffects = [Hurt (5 * d 1)] , idesc = "" } largeJaw = fist { iname = "large jaw" , ifreq = [("large jaw", 100)] , icount = 1 , iverbHit = "crush" , ieffects = [Hurt (12 * d 1)] , idesc = "" } horn = fist { iname = "horn" , ifreq = [("horn", 20)] , icount = 2 , iverbHit = "impale" , ieffects = [Hurt (8 * d 1)] , idesc = "" } -- * Monster weapon organs tentacle = fist { iname = "tentacle" , ifreq = [("tentacle", 50)] , icount = 4 , iverbHit = "slap" , ieffects = [Hurt (4 * d 1)] , idesc = "" } -- * Special weapon organs razor = fist { iname = "razor" , ifreq = [("razor", 100)] , icount = 7 , iverbHit = "slice" , ieffects = [Hurt (2 * d 1)] , idesc = "" } thorn = fist { iname = "thorn" , ifreq = [("thorn", 100)] , icount = 2 + d 3 , iverbHit = "impale" , ieffects = [Hurt (2 * d 1)] , ifeature = [Identified] -- not Durable , idesc = "" } boilingFissure = fist { iname = "fissure" , ifreq = [("boiling fissure", 100)] , icount = 5 + d 5 , iverbHit = "hiss at" , ieffects = [Burn $ 1 * d 1] , ifeature = [Identified] -- not Durable , idesc = "" } biogasFissure = boilingFissure { iname = "fissure" , ifreq = [("biogas fissure", 100)] , icount = 2 + d 2 , ieffects = [Burn $ 1 * d 1, toOrganGameTurn "weakened" (2 + d 2)] } medbotFissure = boilingFissure { iname = "fissure" , ifreq = [("medbot fissure", 100)] , icount = 2 + d 2 , ieffects = [Burn $ 1 * d 1, RefillHP 6] } beeSting = fist { iname = "bee sting" , ifreq = [("bee sting", 100)] , icount = 1 , iverbHit = "sting" , iaspects = [AddArmorMelee 90, AddArmorRanged 90] , ieffects = [Burn $ 2 * d 1, Paralyze 3, RefillHP 5] , ifeature = [Identified] -- not Durable , idesc = "Painful, but beneficial." } sting = fist { iname = "sting" , ifreq = [("sting", 100)] , icount = 1 , iverbHit = "sting" , iaspects = [Timeout $ 1 + d 5] , ieffects = [Burn $ 2 * d 1, Recharging (Paralyze 2)] , idesc = "Painful, debilitating and harmful." } venomTooth = fist { iname = "venom tooth" , ifreq = [("venom tooth", 100)] , icount = 2 , iverbHit = "bite" , iaspects = [Timeout $ 5 + d 3] , ieffects = [ Hurt (2 * d 1) , Recharging (toOrganGameTurn "slow 10" (3 + d 3)) ] , idesc = "" } -- TODO: should also confer poison resistance, but current implementation -- is too costly (poison removal each turn) venomFang = fist { iname = "venom fang" , ifreq = [("venom fang", 100)] , icount = 2 , iverbHit = "bite" , iaspects = [Timeout $ 7 + d 5] , ieffects = [ Hurt (2 * d 1) , Recharging (toOrganNone "poisoned") ] , idesc = "" } screechingBeak = armoredSkin { iname = "screeching beak" , ifreq = [("screeching beak", 100)] , icount = 1 , iverbHit = "peck" , iaspects = [Timeout $ 5 + d 5] , ieffects = [ Recharging (Summon [("scavenger", 1)] $ 1 + dl 2) , Hurt (2 * d 1) ] , idesc = "" } largeTail = fist { iname = "large tail" , ifreq = [("large tail", 50)] , icount = 1 , iverbHit = "knock" , iaspects = [Timeout $ 1 + d 3] , ieffects = [Hurt (8 * d 1), Recharging (PushActor (ThrowMod 400 25))] , idesc = "" } liveWire = fist { iname = "live wire" , ifreq = [("live wire", 100)] , icount = 1 , iverbHit = "shock" , iaspects = [Timeout $ 3 + d 3] , ieffects = [ Hurt (1 * d 1) , Recharging (DropItem COrgan "temporary conditions" True) , Recharging $ RefillHP (-2) ] , idesc = "" } -- Non-weapons -- * Armor organs armoredSkin = ItemKind { isymbol = '%' , iname = "armored skin" , ifreq = [("armored skin", 100)] , iflavour = zipPlain [Red] , icount = 1 , irarity = [(1, 1)] , iverbHit = "bash" , iweight = 2000 , iaspects = [AddArmorMelee 30, AddArmorRanged 30] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [] } -- * Sense organs eye :: Int -> ItemKind eye n = armoredSkin { iname = "eye" , ifreq = [(toGroupName $ "eye" <+> tshow n, 100)] , icount = 2 , iverbHit = "glare at" , iaspects = [AddSight (intToDice n)] , idesc = "" } eye2 = eye 2 eye3 = eye 3 eye4 = eye 4 eye5 = eye 5 eye6 = eye 6 eye7 = eye 7 eye8 = eye 8 vision :: Int -> ItemKind vision n = armoredSkin { iname = "vision" , ifreq = [(toGroupName $ "vision" <+> tshow n, 100)] , icount = 1 , iverbHit = "visualize" , iaspects = [AddSight (intToDice n)] , idesc = "" } vision4 = vision 4 vision6 = vision 6 vision8 = vision 8 vision10 = vision 10 vision12 = vision 12 vision14 = vision 14 vision16 = vision 16 nostril = armoredSkin { iname = "nostril" , ifreq = [("nostril", 100)] , icount = 2 , iverbHit = "snuff" , iaspects = [AddSmell 1] -- times 2, from icount , idesc = "" } -- * Assorted insectMortality = fist { iname = "insect mortality" , ifreq = [("insect mortality", 100)] , icount = 1 , iverbHit = "age" , iaspects = [Periodic, Timeout $ 40 + d 10] , ieffects = [Recharging (RefillHP (-1))] , idesc = "" } sapientBrain = armoredSkin { iname = "sapient brain" , ifreq = [("sapient brain", 100)] , icount = 1 , iverbHit = "outbrain" , iaspects = [AddSkills unitSkills] , idesc = "" } animalBrain = armoredSkin { iname = "animal brain" , ifreq = [("animal brain", 100)] , icount = 1 , iverbHit = "blank" , iaspects = [let absNo = [AbDisplace, AbMoveItem, AbProject, AbApply] sk = EM.fromList $ zip absNo [-1, -1..] in AddSkills $ addSkills unitSkills sk] , idesc = "" } robotBrain = armoredSkin { iname = "robot brain" , ifreq = [("robot brain", 100)] , icount = 1 , iverbHit = "outcompute" , iaspects = [let absNo = [AbApply] sk = EM.fromList $ zip absNo [-1, -1..] in AddSkills $ addSkills unitSkills sk] , idesc = "" } speedGland :: Int -> ItemKind speedGland n = armoredSkin { iname = "speed gland" , ifreq = [(toGroupName $ "speed gland" <+> tshow n, 100)] , icount = 1 , iverbHit = "spit at" , iaspects = [ AddSpeed $ intToDice n , Periodic , Timeout $ intToDice $ 100 `div` n ] , ieffects = [Recharging (RefillHP 1)] , idesc = "" } speedGland2 = speedGland 2 speedGland4 = speedGland 4 speedGland6 = speedGland 6 speedGland8 = speedGland 8 speedGland10 = speedGland 10 scentGland = armoredSkin -- TODO: cone attack, 3m away, project? apply? { iname = "scent gland" , ifreq = [("scent gland", 100)] , icount = 1 , iverbHit = "spray at" , iaspects = [Periodic, Timeout $ 10 + d 2 |*| 5 ] , ieffects = [ Recharging (Explode "distressing odor") , Recharging ApplyPerfume ] , idesc = "" } boilingVent = armoredSkin { iname = "vent" , ifreq = [("boiling vent", 100)] , iflavour = zipPlain [BrBlue] , icount = 1 , iverbHit = "menace" , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5] , ieffects = [Recharging (Explode "boiling water")] , idesc = "" } biogasVent = armoredSkin { iname = "vent" , ifreq = [("biogas vent", 100)] , iflavour = zipPlain [BrGreen] , icount = 1 , iverbHit = "menace" , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5] , ieffects = [Recharging (Explode "weakness mist")] , idesc = "" } medbotVent = armoredSkin { iname = "vent" , ifreq = [("medbot vent", 100)] , iflavour = zipPlain [BrYellow] , icount = 1 , iverbHit = "menace" , iaspects = [Periodic, Timeout $ 2 + d 2 |*| 5] , ieffects = [Recharging (Explode "protecting balm")] , idesc = "" } wasteContainer = armoredSkin { iname = "waste container" , ifreq = [("waste container", 100)] , icount = 1 , iverbHit = "spill over" , iaspects = [Periodic, Timeout $ 5 + d 5 |*| 10] , ieffects = [ Recharging (Summon [("mobile animal", 1)] $ 1 + dl 2) , Recharging (RefillHP 1) , Recharging (Explode "waste") ] , idesc = "" } spotlight = armoredSkin { iname = "spotlight" , ifreq = [("spotlight", 100)] , icount = 1 , iverbHit = "blind" , iaspects = [AddLight 3] , idesc = "" } bonusHP = armoredSkin { iname = "bonus HP" , ifreq = [("bonus HP", 100)] , icount = 1 , iverbHit = "intimidate" , iweight = 0 , iaspects = [AddMaxHP 1] , idesc = "" } Allure-0.5.0.0/GameDefinition/Content/ItemKind.hs0000644000000000000000000011525412555263417017642 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Item and treasure definitions. module Content.ItemKind ( cdefs ) where import qualified Data.EnumMap.Strict as EM import Data.List import Content.ItemKindActor import Content.ItemKindBlast import Content.ItemKindOrgan import Content.ItemKindTemporary import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind cdefs :: ContentDef ItemKind cdefs = ContentDef { getSymbol = isymbol , getName = iname , getFreq = ifreq , validateSingle = validateSingleItemKind , validateAll = validateAllItemKind , content = items ++ organs ++ blasts ++ actors ++ temporaries } items :: [ItemKind] items = [dart, dart200, paralizingProj, harpoon, net, needle, jumpingPole, sharpeningTool, seeingItem, light1, light2, light3, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, constructionHooter, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, currency] dart, dart200, paralizingProj, harpoon, net, needle, jumpingPole, sharpeningTool, seeingItem, light1, light2, light3, gorget, necklace1, necklace2, necklace3, necklace4, necklace5, necklace6, necklace7, necklace8, necklace9, sightSharpening, ring1, ring2, ring3, ring4, ring5, ring6, ring7, ring8, potion1, potion2, potion3, potion4, potion5, potion6, potion7, potion8, potion9, flask1, flask2, flask3, flask4, flask5, flask6, flask7, flask8, flask9, flask10, flask11, flask12, flask13, flask14, constructionHooter, scroll1, scroll2, scroll3, scroll4, scroll5, scroll6, scroll7, scroll8, scroll9, scroll10, scroll11, armorLeather, armorMail, gloveFencing, gloveGauntlet, gloveJousting, buckler, shield, dagger, daggerDropBestWeapon, hammer, hammerParalyze, hammerSpark, sword, swordImpress, swordNullify, halberd, halberdPushActor, wand1, wand2, gem1, gem2, gem3, gem4, currency :: ItemKind necklace, ring, potion, flask, scroll, wand, gem :: ItemKind -- generic templates -- * Item group symbols, from Angband and variants symbolProjectile, _symbolLauncher, symbolLight, symbolTool, symbolGem, symbolGold, symbolNecklace, symbolRing, symbolPotion, symbolFlask, symbolScroll, symbolTorsoArmor, symbolMiscArmor, _symbolClothes, symbolShield, symbolPolearm, symbolEdged, symbolHafted, symbolWand, _symbolStaff, _symbolFood :: Char symbolProjectile = '{' _symbolLauncher = '}' symbolLight = '~' symbolTool = '~' symbolGem = '*' symbolGold = '$' symbolNecklace = '"' symbolRing = '=' symbolPotion = '!' -- concoction, bottle, jar, vial, canister symbolFlask = '!' symbolScroll = '?' -- book, note, tablet, remote, chip, card symbolTorsoArmor = '[' symbolMiscArmor = ']' _symbolClothes = '(' symbolShield = ')' symbolPolearm = '/' symbolEdged = '|' symbolHafted = '\\' symbolWand = '-' -- magical rod, transmitter, pistol, rifle _symbolStaff = '_' -- scanner _symbolFood = ',' -- too easy to miss? -- * Thrown weapons dart = ItemKind { isymbol = symbolProjectile , iname = "steak knife" , ifreq = [("useful", 100), ("any arrow", 100)] , iflavour = zipPlain [BrCyan] , icount = 4 * d 3 , irarity = [(1, 10), (10, 20)] , iverbHit = "nick" , iweight = 100 , iaspects = [AddHurtRanged (d 3 + dl 6 |*| 20)] , ieffects = [Hurt (2 * d 1)] , ifeature = [toVelocity 75, Identified] -- no fins, no special balance , idesc = "Not particularly well balanced, but with a laser-sharpened titanium tip and blade." , ikit = [] } dart200 = ItemKind { isymbol = symbolProjectile , iname = "billiard ball" , ifreq = [("useful", 100), ("any arrow", 50)] -- TODO: until arrows added , iflavour = zipPlain [BrWhite] , icount = 4 * d 3 , irarity = [(1, 20), (10, 10)] , iverbHit = "strike" , iweight = 300 , iaspects = [AddHurtRanged (d 3 + dl 6 |*| 20)] , ieffects = [Hurt (1 * d 1)] , ifeature = [toVelocity 150, Identified] , idesc = "Ideal shape, size and weight for throwing." , ikit = [] } -- * Exotic thrown weapons paralizingProj = ItemKind { isymbol = symbolProjectile , iname = "can" , ifreq = [("useful", 100), ("can of sticky foam", 1)] , iflavour = zipPlain [Magenta] , icount = dl 3 , irarity = [(5, 5), (10, 20)] , iverbHit = "glue" , iweight = 1500 , iaspects = [] , ieffects = [ NoEffect "of sticky foam", Paralyze (5 + d 7) , OnSmash (Explode "glue")] , ifeature = [toVelocity 50, Identified, Fragile] -- unwieldy , idesc = "A can of liquid, fast-setting, construction foam." , ikit = [] } harpoon = ItemKind { isymbol = symbolProjectile , iname = "harpoon" , ifreq = [("useful", 100)] , iflavour = zipPlain [Brown] , icount = dl 5 , irarity = [(5, 5), (10, 5)] , iverbHit = "hook" , iweight = 4000 , iaspects = [AddHurtRanged (d 2 + dl 5 |*| 20)] , ieffects = [Hurt (4 * d 1), PullActor (ThrowMod 200 50)] , ifeature = [Identified] , idesc = "A display piece harking back to the Earth's oceanic tourism hayday. The cruel, barbed head lodges in its victim so painfully that the weakest tug of the thin line sends the victim flying." , ikit = [] } net = ItemKind { isymbol = symbolProjectile , iname = "net" , ifreq = [("useful", 100)] , iflavour = zipPlain [White] , icount = dl 3 , irarity = [(3, 5), (10, 4)] , iverbHit = "entangle" , iweight = 1000 , iaspects = [] , ieffects = [ toOrganGameTurn "slow 10" (3 + d 3) , DropItem CEqp "torso armor" False ] , ifeature = [Identified] , idesc = "A large synthetic fibre net with weights affixed along the edges. Entangles armor and restricts movement." , ikit = [] } needle = ItemKind { isymbol = symbolProjectile , iname = "needle" , ifreq = [("needle", 1)] -- special , iflavour = zipPlain [BrBlue] , icount = 9 * d 3 , irarity = [(1, 1)] , iverbHit = "prick" , iweight = 1 , iaspects = [AddHurtRanged (d 3 + dl 3 |*| 10)] , ieffects = [Hurt (1 * d 1)] , ifeature = [toVelocity 200, Fragile] , idesc = "The hypodermic needle part of a micro-syringe. Without the payload, it flies far and penetrates deeply, causing intense pain on movement." , ikit = [] } -- * Assorted tools jumpingPole = ItemKind { isymbol = symbolTool , iname = "jumping pole" , ifreq = [("useful", 100)] , iflavour = zipPlain [White] , icount = 1 , irarity = [(1, 2)] , iverbHit = "prod" , iweight = 10000 , iaspects = [Timeout $ d 2 + 2 - dl 2 |*| 10] , ieffects = [Recharging (toOrganActorTurn "fast 20" 1)] , ifeature = [Durable, Applicable, Identified] , idesc = "Makes you vulnerable at take-off, but then you are free like a bird." , ikit = [] } sharpeningTool = ItemKind { isymbol = symbolTool , iname = "honing steel" , ifreq = [("useful", 100)] , iflavour = zipPlain [Blue] , icount = 1 , irarity = [(10, 10)] , iverbHit = "smack" , iweight = 400 , iaspects = [AddHurtMelee $ d 10 |*| 3] , ieffects = [] , ifeature = [EqpSlot EqpSlotAddHurtMelee "", Identified] , idesc = "Originally used for realigning the bent or buckled edges of kitchen knives in the local bars. Now it saves lives by letting you fix your weapons between or even during fights, without the need to set up camp, fish out tools and assemble a proper sharpening workshop." , ikit = [] } seeingItem = ItemKind { isymbol = '%' , iname = "visual sensor" , ifreq = [("useful", 100)] , iflavour = zipPlain [Red] , icount = 1 , irarity = [(1, 1)] , iverbHit = "gaze at" , iweight = 500 , iaspects = [ AddSight 10, AddMaxCalm 60, AddLight 2 , Periodic, Timeout $ 1 + d 2 ] , ieffects = [ Recharging (toOrganNone "poisoned") , Recharging (Summon [("mobile robot", 1)] 1) ] , ifeature = [Identified] , idesc = "A functioning visual sensor torn out from some giant robot. The circuitry is too big to serve just the basic signal processing. Watch out for the sharp edges and the seeping coolant liquid." , ikit = [] } -- * Lights light1 = ItemKind { isymbol = symbolLight , iname = "candle" , ifreq = [("useful", 100), ("light source", 100)] , iflavour = zipPlain [Brown] , icount = d 2 , irarity = [(1, 10)] , iverbHit = "scorch" , iweight = 500 , iaspects = [ AddLight 3 , AddSight (-2) ] , ieffects = [Burn 2] , ifeature = [ toVelocity 50 -- easy to break when throwing , Fragile, EqpSlot EqpSlotAddLight "", Identified ] , idesc = "A smoking, thick candle with an unsteady fire." , ikit = [] } light2 = ItemKind { isymbol = symbolLight , iname = "oil lamp" , ifreq = [("useful", 100), ("light source", 100)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(6, 7)] , iverbHit = "burn" , iweight = 1000 , iaspects = [AddLight 3, AddSight (-1)] , ieffects = [Burn 3, Paralyze 3, OnSmash (Explode "burning oil 3")] , ifeature = [ toVelocity 70 -- hard not to spill the oil while throwing , Fragile, EqpSlot EqpSlotAddLight "", Identified ] , idesc = "A sizable glass lamp filled with plant oil feeding a wick." , ikit = [] } light3 = ItemKind { isymbol = symbolLight , iname = "crank spotlight" , ifreq = [("useful", 100), ("light source", 100)] , iflavour = zipPlain [BrWhite] , icount = 1 , irarity = [(10, 5)] , iverbHit = "snag" , iweight = 2400 , iaspects = [AddLight 4, AddArmorRanged $ - d 3] -- noise and busy hands , ieffects = [] , ifeature = [ EqpSlot EqpSlotAddLight "", Identified ] , idesc = "Powerful, wide-beam spotlight, powered by a hand-crank. Requires noisy two-handed recharging every few minutes." , ikit = [] } -- * Periodic jewelry gorget = ItemKind { isymbol = symbolNecklace , iname = "Old Gorget" , ifreq = [("useful", 100)] , iflavour = zipFancy [BrCyan] , icount = 1 , irarity = [(4, 3), (10, 3)] -- weak, shallow , iverbHit = "whip" , iweight = 30 , iaspects = [ Unique , Periodic , Timeout $ 1 + d 2 , AddArmorMelee $ 2 + d 3 , AddArmorRanged $ 2 + d 3 ] , ieffects = [Recharging (RefillCalm 1)] , ifeature = [ Durable, Precious, EqpSlot EqpSlotPeriodic "" , Identified, toVelocity 50 ] -- not dense enough , idesc = "Highly ornamental, cold, large, steel medallion on a chain. Unlikely to offer much protection as an armor piece, but the old, worn engraving reassures you." , ikit = [] } necklace = ItemKind { isymbol = symbolNecklace , iname = "necklace" , ifreq = [("useful", 100)] , iflavour = zipFancy stdCol ++ zipPlain brightCol , icount = 1 , irarity = [(10, 2)] , iverbHit = "whip" , iweight = 30 , iaspects = [Periodic] , ieffects = [] , ifeature = [ Precious, EqpSlot EqpSlotPeriodic "" , toVelocity 50 ] -- not dense enough , idesc = "Tingling, rattling chain of flat encrusted links. Eccentric millionaires are known to hide their highly personalized body augmentation packs in such large jewelry pieces." , ikit = [] } necklace1 = necklace { ifreq = [("treasure", 100)] , irarity = [(3, 0), (4, 1), (10, 2)] -- prevents camping on lvl 3 , iaspects = [Unique, Timeout $ d 3 + 4 - dl 3 |*| 10] ++ iaspects necklace , ieffects = [NoEffect "of Trickle Life", Recharging (RefillHP 1)] , ifeature = Durable : ifeature necklace } necklace2 = necklace { ifreq = [("treasure", 100)] -- just too nasty to call it useful , irarity = [(1, 1)] , iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 10) : iaspects necklace , ieffects = [ Recharging Impress , Recharging (DropItem COrgan "temporary conditions" True) , Recharging (Summon [("mobile animal", 1)] $ 1 + dl 2) , Recharging (Explode "waste") ] } necklace3 = necklace { iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 10) : iaspects necklace , ieffects = [Recharging (Paralyze $ 5 + d 5 + dl 5)] } necklace4 = necklace { iaspects = (Timeout $ d 4 + 4 - dl 4 |*| 2) : iaspects necklace , ieffects = [Recharging (Teleport $ d 2 * 3)] } necklace5 = necklace { iaspects = (Timeout $ d 3 + 4 - dl 3 |*| 10) : iaspects necklace , ieffects = [Recharging (Teleport $ 14 + d 3 * 3)] } necklace6 = necklace { iaspects = (Timeout $ d 4 |*| 10) : iaspects necklace , ieffects = [Recharging (PushActor (ThrowMod 100 50))] } necklace7 = necklace -- TODO: teach AI to wear only for fight { ifreq = [("treasure", 100)] , iaspects = [ Unique, AddMaxHP $ 10 + d 10 , AddArmorMelee 20, AddArmorRanged 20 , Timeout $ d 2 + 5 - dl 3 ] ++ iaspects necklace , ieffects = [ NoEffect "of Overdrive" , Recharging (InsertMove $ 1 + d 2) , Recharging (RefillHP (-1)) , Recharging (RefillCalm (-1)) ] , ifeature = Durable : ifeature necklace } necklace8 = necklace { iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 5) : iaspects necklace , ieffects = [Recharging $ Explode "spark"] } necklace9 = necklace { iaspects = (Timeout $ d 3 + 3 - dl 3 |*| 5) : iaspects necklace , ieffects = [Recharging $ Explode "fragrance"] } -- * Non-periodic jewelry sightSharpening = ItemKind { isymbol = symbolRing , iname = "Autozoom Contact Lens" , ifreq = [("treasure", 100)] , iflavour = zipPlain [White] , icount = 1 , irarity = [(7, 3), (10, 3)] -- medium weak, medium shallow , iverbHit = "rap" , iweight = 50 , iaspects = [Unique, AddSight $ 1 + d 2, AddHurtMelee $ d 2 |*| 3] , ieffects = [] , ifeature = [ Precious, Identified, Durable , EqpSlot EqpSlotAddSight "" ] , idesc = "Zooms on any movement, distant or close. Requires some getting used to. Never needs to be taken off." , ikit = [] } -- Don't add standard effects to rings, because they go in and out -- of eqp and so activating them would require UI tedium: looking for -- them in eqp and inv or even activating a wrong item via letter by mistake. ring = ItemKind { isymbol = symbolRing , iname = "ring" , ifreq = [("useful", 100)] , iflavour = zipPlain stdCol ++ zipFancy darkCol , icount = 1 , irarity = [(10, 3)] , iverbHit = "knock" , iweight = 15 , iaspects = [] , ieffects = [Explode "blast 20"] , ifeature = [Precious, Identified] , idesc = "A sturdy ring with a softly shining eye. If it contains a body booster unit, beware of the side-effects." , ikit = [] } ring1 = ring { irarity = [(10, 2)] , iaspects = [AddSpeed $ 1 + d 2, AddMaxHP $ dl 7 - 7 - d 7] , ieffects = [Explode "distortion"] -- strong magic , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddSpeed ""] } ring2 = ring { irarity = [(10, 5)] , iaspects = [AddMaxHP $ 10 + dl 10, AddMaxCalm $ dl 5 - 20 - d 5] , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxHP ""] } ring3 = ring { irarity = [(10, 5)] , iaspects = [AddMaxCalm $ 29 + dl 10] , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddMaxCalm ""] , idesc = "Cold, solid to the touch, perfectly round, engraved with solemn, strangely comforting, worn out words." } ring4 = ring { irarity = [(3, 3), (10, 5)] , iaspects = [AddHurtMelee $ d 5 + dl 5 |*| 3, AddMaxHP $ dl 3 - 5 - d 3] , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddHurtMelee ""] } ring5 = ring -- by the time it's found, probably no space in eqp { irarity = [(5, 0), (10, 2)] , iaspects = [AddLight $ d 2] , ieffects = [Explode "distortion"] -- strong magic , ifeature = ifeature ring ++ [EqpSlot EqpSlotAddLight ""] , idesc = "A sturdy ring with a large, shining stone." } ring6 = ring { ifreq = [("treasure", 100)] , irarity = [(10, 2)] , iaspects = [ Unique, AddSpeed $ 3 + d 4 , AddMaxCalm $ - 20 - d 20, AddMaxHP $ - 20 - d 20 ] , ieffects = [NoEffect "of Rush"] -- no explosion, because Durable , ifeature = ifeature ring ++ [Durable, EqpSlot EqpSlotAddSpeed ""] } ring7 = ring { ifreq = [("useful", 100), ("ring of opportunity sniper", 1) ] , irarity = [(1, 1)] , iaspects = [AddSkills $ EM.fromList [(AbProject, 8)]] , ieffects = [ NoEffect "of opportunity sniper" , Explode "distortion" ] -- strong magic , ifeature = ifeature ring ++ [EqpSlot (EqpSlotAddSkills AbProject) ""] } ring8 = ring { ifreq = [("useful", 1), ("ring of opportunity grenadier", 1) ] , irarity = [(1, 1)] , iaspects = [AddSkills $ EM.fromList [(AbProject, 11)]] , ieffects = [ NoEffect "of opportunity grenadier" , Explode "distortion" ] -- strong magic , ifeature = ifeature ring ++ [EqpSlot (EqpSlotAddSkills AbProject) ""] } -- * Ordinary exploding consumables, often intended to be thrown potion = ItemKind { isymbol = symbolPotion , iname = "vial" , ifreq = [("useful", 100)] , iflavour = zipLiquid brightCol ++ zipPlain brightCol ++ zipFancy brightCol , icount = 1 , irarity = [(1, 12), (10, 9)] , iverbHit = "splash" , iweight = 200 , iaspects = [] , ieffects = [] , ifeature = [ toVelocity 50 -- oily, bad grip , Applicable, Fragile ] , idesc = "A vial of bright, frothing concoction." -- purely natural; no nano, no alien tech , ikit = [] } potion1 = potion { ieffects = [ NoEffect "of rose water", Impress, RefillCalm (-3) , OnSmash ApplyPerfume, OnSmash (Explode "fragrance") ] } potion2 = potion { ifreq = [("treasure", 100)] , irarity = [(6, 10), (10, 10)] , iaspects = [Unique] , ieffects = [ NoEffect "of Attraction", Impress, OverfillCalm (-20) , OnSmash (Explode "pheromone") ] } potion3 = potion { irarity = [(1, 10)] , ieffects = [ RefillHP 5, DropItem COrgan "poisoned" True , OnSmash (Explode "healing mist") ] } potion4 = potion { irarity = [(10, 10)] , ieffects = [ RefillHP 10, DropItem COrgan "poisoned" True , OnSmash (Explode "healing mist 2") ] } potion5 = potion { ieffects = [ OneOf [ OverfillHP 10, OverfillHP 5, Burn 5 , toOrganActorTurn "strengthened" (20 + d 5) ] , OnSmash (OneOf [ Explode "healing mist" , Explode "wounding mist" , Explode "fragrance" , Explode "smelly droplet" , Explode "blast 10" ]) ] } potion6 = potion { irarity = [(3, 3), (10, 6)] , ieffects = [ Impress , OneOf [ OverfillCalm (-60) , OverfillHP 20, OverfillHP 10, Burn 10 , toOrganActorTurn "fast 20" (20 + d 5) ] , OnSmash (OneOf [ Explode "healing mist 2" , Explode "calming mist" , Explode "distressing odor" , Explode "eye drop" , Explode "blast 20" ]) ] } potion7 = potion { irarity = [(1, 15), (10, 5)] , ieffects = [ DropItem COrgan "poisoned" True , OnSmash (Explode "antidote mist") ] } potion8 = potion { irarity = [(1, 5), (10, 15)] , ieffects = [ DropItem COrgan "temporary conditions" True , OnSmash (Explode "blast 10") ] } potion9 = potion { ifreq = [("treasure", 100)] , irarity = [(10, 5)] , iaspects = [Unique] , ieffects = [ NoEffect "of Love", OverfillHP 60 , Impress, OverfillCalm (-60) , OnSmash (Explode "healing mist 2") , OnSmash (Explode "pheromone") ] } -- * Exploding consumables with temporary aspects, can be thrown -- TODO: dip projectiles in those -- TODO: add flavour and realism as in, e.g., "flask of whiskey", -- which is more flavourful and believable than "flask of strength" flask = ItemKind { isymbol = symbolFlask , iname = "flask" , ifreq = [("useful", 100), ("flask", 100)] , iflavour = zipLiquid darkCol ++ zipPlain darkCol ++ zipFancy darkCol , icount = 1 , irarity = [(1, 9), (10, 6)] , iverbHit = "splash" , iweight = 500 , iaspects = [] , ieffects = [] , ifeature = [ toVelocity 50 -- oily, bad grip , Applicable, Fragile ] , idesc = "A flask of oily liquid of a suspect color." , ikit = [] } flask1 = flask { irarity = [(10, 5)] , ieffects = [ NoEffect "of strength brew" , toOrganActorTurn "strengthened" (20 + d 5) , toOrganNone "regenerating" , OnSmash (Explode "strength mist") ] } flask2 = flask { ieffects = [ NoEffect "of weakness brew" , toOrganGameTurn "weakened" (20 + d 5) , OnSmash (Explode "weakness mist") ] } flask3 = flask { ieffects = [ NoEffect "of protecting balm" , toOrganActorTurn "protected" (20 + d 5) , OnSmash (Explode "protecting balm") ] } flask4 = flask { ieffects = [ NoEffect "of red paint" , toOrganGameTurn "painted red" (20 + d 5) , OnSmash (Explode "red paint") ] } flask5 = flask { irarity = [(10, 5)] , ieffects = [ NoEffect "of haste brew" , toOrganActorTurn "fast 20" (20 + d 5) , OnSmash (Explode "haste spray") ] } flask6 = flask { ieffects = [ NoEffect "of lethargy brew" , toOrganGameTurn "slow 10" (20 + d 5) , toOrganNone "regenerating" , RefillCalm 3 , OnSmash (Explode "slowness spray") ] } flask7 = flask -- sight can be reduced from Calm, drunk, etc. { irarity = [(10, 7)] , ieffects = [ NoEffect "of eye drops" , toOrganActorTurn "far-sighted" (20 + d 5) , OnSmash (Explode "blast 10") ] } flask8 = flask { irarity = [(10, 3)] , ieffects = [ NoEffect "of smelly concoction" , toOrganActorTurn "keen-smelling" (20 + d 5) , OnSmash (Explode "blast 10") ] } flask9 = flask { ieffects = [ NoEffect "of bait cocktail" , toOrganActorTurn "drunk" (5 + d 5) , OnSmash (Summon [("mobile animal", 1)] $ 1 + dl 2) , OnSmash (Explode "waste") ] } flask10 = flask { ieffects = [ NoEffect "of whiskey" , toOrganActorTurn "drunk" (20 + d 5) , Impress, Burn 2, RefillHP 4 , OnSmash (Explode "whiskey spray") ] } flask11 = flask { irarity = [(1, 20), (10, 10)] , ieffects = [ NoEffect "of regeneration brew" , toOrganNone "regenerating" , OnSmash (Explode "healing mist") ] } flask12 = flask -- but not flask of Calm depletion, since Calm reduced often { ieffects = [ NoEffect "of poison" , toOrganNone "poisoned" , OnSmash (Explode "wounding mist") ] } flask13 = flask { irarity = [(10, 5)] , ieffects = [ NoEffect "of slow resistance" , toOrganNone "slow resistant" , OnSmash (Explode "anti-slow mist") ] } flask14 = flask { irarity = [(10, 5)] , ieffects = [ NoEffect "of poison resistance" , toOrganNone "poison resistant" , OnSmash (Explode "antidote mist") ] } -- * Non-exploding consumables, not specifically designed for throwing constructionHooter = scroll { iname = "construction hooter" , ifreq = [("useful", 1), ("construction hooter", 1)] -- extremely rare , iflavour = zipPlain [BrRed] , irarity = [(1, 1)] , iaspects = [] , ieffects = [Summon [("construction robot", 1)] $ 1 + dl 2] , ifeature = ifeature scroll ++ [Identified] , idesc = "The single-use electronic overdrive hooter that construction robots use to warn about danger and call help in extreme emergency." , ikit = [] } scroll = ItemKind { isymbol = symbolScroll , iname = "chip" , ifreq = [("useful", 100), ("any scroll", 100)] , iflavour = zipFancy stdCol ++ zipPlain darkCol -- arcane and old , icount = 1 , irarity = [(1, 15), (10, 12)] , iverbHit = "thump" , iweight = 20 , iaspects = [] , ieffects = [] , ifeature = [ toVelocity 25 -- too little , Applicable ] , idesc = "A generic, diposable chip, capable of a one-time holo-display. Some of these also contain a one-time password authorizing a particular spaceship's infrastructure transition. It is unknown how the infrastructure might respond after so many years." , ikit = [] } scroll1 = scroll { ifreq = [("treasure", 100)] , irarity = [(5, 10), (10, 10)] -- mixed blessing, so available early , iaspects = [Unique] , ieffects = [ NoEffect "of Reckless Beacon" , CallFriend 1, Summon standardSummon (2 + d 2) ] } scroll2 = scroll { irarity = [] , ieffects = [] } scroll3 = scroll { irarity = [(1, 5), (10, 3)] , ieffects = [Ascend 1] } scroll4 = scroll { ieffects = [OneOf [ Teleport 5, RefillCalm 5, RefillCalm (-5) , InsertMove 5, Paralyze 10 ]] } scroll5 = scroll { irarity = [(10, 15)] , ieffects = [ Impress , OneOf [ Teleport 20, Ascend (-1), Ascend 1 , Summon standardSummon 2, CallFriend 1 , RefillCalm 5, OverfillCalm (-60) , CreateItem CGround "useful" TimerNone ] ] } scroll6 = scroll { ieffects = [Teleport 5] } scroll7 = scroll { ieffects = [Teleport 20] } scroll8 = scroll { irarity = [(10, 3)] , ieffects = [InsertMove $ 1 + d 2 + dl 2] } scroll9 = scroll -- TODO: remove Calm when server can tell if anything IDed { irarity = [(1, 15), (10, 10)] , ieffects = [ NoEffect "of scientific explanation" , Identify, OverfillCalm 3 ] } scroll10 = scroll -- TODO: firecracker only if an item really polymorphed? -- But currently server can't tell. { irarity = [(10, 10)] , ieffects = [ NoEffect "molecular reconfiguration" , PolyItem, Explode "firecracker 7" ] } scroll11 = scroll { ifreq = [("treasure", 100)] , irarity = [(6, 10), (10, 10)] , iaspects = [Unique] , ieffects = [NoEffect "of Prisoner Release", CallFriend 1] } standardSummon :: Freqs ItemKind standardSummon = [ ("mobile alien", 20) , ("mobile animal", 50) , ("mobile robot", 30) ] -- * Armor armorLeather = ItemKind { isymbol = symbolTorsoArmor , iname = "spacesuit breastplate" , ifreq = [("useful", 100)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(1, 9), (10, 3)] , iverbHit = "thud" , iweight = 7000 , iaspects = [ AddHurtMelee (-3) , AddArmorMelee $ 1 + d 2 + dl 2 |*| 5 , AddArmorRanged $ 1 + d 2 + dl 2 |*| 5 ] , ieffects = [] , ifeature = [ toVelocity 30 -- unwieldy to throw and blunt , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ] , idesc = "A hard-shell torso segment cut from a disposed off spacesuit." , ikit = [] } armorMail = armorLeather { iname = "bulletproof vest" , iflavour = zipPlain [Cyan] , irarity = [(6, 9), (10, 3)] , iweight = 12000 , iaspects = [ AddHurtMelee (-3) , AddArmorMelee $ 2 + d 2 + dl 3 |*| 5 , AddArmorRanged $ 2 + d 2 + dl 3 |*| 5 ] , idesc = "A civilian bulletproof vest. Discourages foes from attacking your torso, making it harder for them to land a blow." } gloveFencing = ItemKind { isymbol = symbolMiscArmor , iname = "construction glove" , ifreq = [("useful", 100)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(5, 9), (10, 9)] , iverbHit = "flap" , iweight = 100 , iaspects = [ AddHurtMelee $ (d 2 + dl 10) |*| 3 , AddArmorRanged $ d 2 |*| 5 ] , ieffects = [] , ifeature = [ toVelocity 30 -- flaps and flutters , Durable, EqpSlot EqpSlotAddArmorRanged "", Identified ] , idesc = "A flexible construction glove from rough leather ensuring a good grip. Also, quite effective in deflecting or even catching slow projectiles." , ikit = [] } gloveGauntlet = gloveFencing { iname = "spacesuit glove" , iflavour = zipPlain [BrCyan] , irarity = [(1, 9), (10, 3)] , iweight = 300 , iaspects = [ AddArmorMelee $ 1 + dl 2 |*| 5 , AddArmorRanged $ 1 + dl 2 |*| 5 ] , idesc = "A piece of a hull maintenance spacesuit, padded and reinforced with carbon fibre." } gloveJousting = gloveFencing { iname = "Welding Handgear" , iflavour = zipFancy [BrRed] , irarity = [(1, 3), (10, 3)] , iweight = 500 , iaspects = [ Unique , AddHurtMelee $ dl 4 - 6 |*| 3 , AddArmorMelee $ 2 + dl 2 |*| 5 , AddArmorRanged $ 2 + dl 2 |*| 5 ] , idesc = "Rigid, bulky handgear embedding a welding equipment, complete with an affixed small shield and a darkened visor. Awe-inspiring." } -- * Shields -- Shield doesn't protect against ranged attacks to prevent -- micromanagement: walking with shield, melee without. buckler = ItemKind { isymbol = symbolShield , iname = "buckler" , ifreq = [("useful", 100)] , iflavour = zipPlain [Blue] , icount = 1 , irarity = [(4, 6)] , iverbHit = "bash" , iweight = 2000 , iaspects = [ AddArmorMelee 40 , AddHurtMelee (-30) , Timeout $ d 3 + 3 - dl 3 |*| 2 ] , ieffects = [ Hurt (1 * d 1) -- to display xdy everywhre in Hurt , Recharging (PushActor (ThrowMod 200 50)) ] , ifeature = [ toVelocity 40 -- unwieldy to throw , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ] , idesc = "Heavy and unwieldy arm protection made from an outer airlock panel. Absorbs a percentage of melee damage, both dealt and sustained. Too small to intercept projectiles with." , ikit = [] } shield = buckler { iname = "shield" , irarity = [(8, 3)] , iflavour = zipPlain [Green] , iweight = 3000 , iaspects = [ AddArmorMelee 80 , AddHurtMelee (-70) , Timeout $ d 6 + 6 - dl 6 |*| 2 ] , ieffects = [Hurt (1 * d 1), Recharging (PushActor (ThrowMod 400 50))] , ifeature = [ toVelocity 30 -- unwieldy to throw , Durable, EqpSlot EqpSlotAddArmorMelee "", Identified ] , idesc = "Large and unwieldy rectangle made of anti-meteorite ceramic sheet. Absorbs a percentage of melee damage, both dealt and sustained. Too heavy to intercept projectiles with." } -- * Weapons dagger = ItemKind { isymbol = symbolEdged , iname = "cleaver" , ifreq = [("useful", 100), ("starting weapon", 100)] , iflavour = zipPlain [BrCyan] , icount = 1 , irarity = [(1, 20)] , iverbHit = "stab" , iweight = 1000 , iaspects = [ AddHurtMelee $ d 3 + dl 3 |*| 3 , AddArmorMelee $ d 2 |*| 5 , AddHurtRanged (-60) ] -- as powerful as a dart , ieffects = [Hurt (6 * d 1)] , ifeature = [ toVelocity 40 -- ensuring it hits with the tip costs speed , Durable, EqpSlot EqpSlotWeapon "", Identified ] , idesc = "A heavy professional kitchen blade. Will do fine cutting any kind of meat and bone, as well as parrying blows. Does not penetrate deeply, but is hard to block. Especially useful in conjunction with a larger weapon." , ikit = [] } daggerDropBestWeapon = dagger { iname = "Double Dagger" , ifreq = [("treasure", 20)] , irarity = [(1, 2), (10, 4)] -- The timeout has to be small, so that the player can count on the effect -- occuring consistently in any longer fight. Otherwise, the effect will be -- absent in some important fights, leading to the feeling of bad luck, -- but will manifest sometimes in fights where it doesn't matter, -- leading to the feeling of wasted power. -- If the effect is very powerful and so the timeout has to be significant, -- let's make it really large, for the effect to occur only once in a fight: -- as soon as the item is equipped, or just on the first strike. , iaspects = [Unique, Timeout $ d 3 + 4 - dl 3 |*| 2] , ieffects = ieffects dagger ++ [Recharging DropBestWeapon, Recharging $ RefillCalm (-3)] , idesc = "A knife with a forked blade that a focused fencer can use to catch and twist an opponent's weapon occasionally." } hammer = ItemKind { isymbol = symbolHafted , iname = "demolition hammer" , ifreq = [("useful", 100), ("starting weapon", 100)] , iflavour = zipPlain [BrMagenta] , icount = 1 , irarity = [(5, 15)] , iverbHit = "club" , iweight = 1500 , iaspects = [ AddHurtMelee $ d 2 + dl 2 |*| 3 , AddHurtRanged (-80) ] -- as powerful as a dart , ieffects = [Hurt (8 * d 1)] , ifeature = [ toVelocity 20 -- ensuring it hits with the sharp tip costs , Durable, EqpSlot EqpSlotWeapon "", Identified ] , idesc = "A hammer on a long handle used for construction work. It may not cause grave wounds, but neither does it ricochet or glance off armor. Great sidearm for opportunistic blows against armored foes." , ikit = [] } hammerParalyze = hammer { iname = "Concussion Hammer" , ifreq = [("treasure", 20)] , irarity = [(5, 2), (10, 4)] , iaspects = [Unique, Timeout $ d 2 + 3 - dl 2 |*| 2] , ieffects = ieffects hammer ++ [Recharging $ Paralyze 5] } hammerSpark = hammer { iname = "Grand Smithhammer" , ifreq = [("treasure", 20)] , irarity = [(5, 2), (10, 4)] , iaspects = [Unique, Timeout $ d 4 + 4 - dl 4 |*| 2] , ieffects = ieffects hammer ++ [Recharging $ Explode "spark"] } sword = ItemKind { isymbol = symbolPolearm , iname = "sharpened pipe" , ifreq = [("useful", 100), ("starting weapon", 100)] , iflavour = zipPlain [BrBlue] , icount = 1 , irarity = [(4, 1), (5, 15)] , iverbHit = "slash" , iweight = 2000 , iaspects = [] , ieffects = [Hurt (10 * d 1)] , ifeature = [ toVelocity 5 -- ensuring it hits with the tip costs speed , Durable, EqpSlot EqpSlotWeapon "", Identified ] , idesc = "A makeshift weapon of simple design, but great potential. Hard to master, though." , ikit = [] } swordImpress = sword { isymbol = symbolEdged , iname = "Master's Sword" , ifreq = [("treasure", 20)] , irarity = [(5, 1), (10, 4)] , iaspects = [Unique, Timeout $ d 4 + 5 - dl 4 |*| 2] , ieffects = ieffects sword ++ [Recharging Impress] , idesc = "An old, dull, but well-balance blade, lending itself to impressive shows of fencing skill." } swordNullify = sword { isymbol = symbolEdged , iname = "Gutting Sword" , ifreq = [("treasure", 20)] , irarity = [(5, 1), (10, 4)] , iaspects = [Unique, Timeout $ d 4 + 5 - dl 4 |*| 2] , ieffects = ieffects sword ++ [ Recharging $ DropItem COrgan "temporary conditions" True , Recharging $ RefillHP (-2) ] , idesc = "Cold, thin, ancient blade that pierces deeply and sends its victim into abrupt, sobering shock." } halberd = ItemKind { isymbol = symbolPolearm , iname = "pole cleaver" , ifreq = [("useful", 100), ("starting weapon", 1)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(7, 1), (10, 10)] , iverbHit = "impale" , iweight = 3000 , iaspects = [AddArmorMelee $ 1 + dl 3 |*| 5] , ieffects = [Hurt (12 * d 1)] , ifeature = [ toVelocity 5 -- not balanced , Durable, EqpSlot EqpSlotWeapon "", Identified ] , idesc = "An improvised but deadly weapon made of a long, sharp kitchen knife glued and bound to a long pole." , ikit = [] } halberdPushActor = halberd { iname = "Swiss Halberd" , ifreq = [("treasure", 20)] , irarity = [(7, 1), (10, 4)] , iaspects = [Unique, Timeout $ d 5 + 5 - dl 5 |*| 2] , ieffects = ieffects halberd ++ [Recharging (PushActor (ThrowMod 400 25))] , idesc = "A perfect replica made for a reenactor troupe, missing only some sharpening. Versatile, with great reach and leverage. Foes are held at a distance." } -- * Wands wand = ItemKind { isymbol = symbolWand , iname = "injector" , ifreq = [("useful", 100)] , iflavour = zipFancy brightCol , icount = 1 , irarity = [] -- TODO: add charges, etc. , iverbHit = "club" , iweight = 300 , iaspects = [AddLight 1, AddSpeed (-1)] -- pulsing with power, distracts , ieffects = [] , ifeature = [ toVelocity 125 -- sufficiently advanced tech , Applicable, Durable ] , idesc = "Buzzing with dazzling light that shines even through appendages that handle it." , ikit = [] } wand1 = wand { ieffects = [] -- TODO: emit a cone of sound shrapnel that makes enemy cover his ears and so drop '{' } wand2 = wand { ieffects = [] } -- * Treasure gem = ItemKind { isymbol = symbolGem , iname = "gem" , ifreq = [("treasure", 100), ("gem", 100)] , iflavour = zipPlain $ delete BrYellow brightCol -- natural, so not fancy , icount = 1 , irarity = [] , iverbHit = "tap" , iweight = 50 , iaspects = [AddLight 1, AddSpeed (-1)] -- reflects strongly, distracts; so it glows in the dark, -- is visible on dark floor, but not too tempting to wear , ieffects = [] , ifeature = [Precious] , idesc = "Precious, though useless. Worth around 100 gold grains." , ikit = [] } gem1 = gem { irarity = [(3 * 10/12, 0), (10, 12)] } gem2 = gem { irarity = [(5 * 10/12, 0), (10, 14)] } gem3 = gem { irarity = [(7 * 10/12, 0), (10, 16)] } gem4 = gem { iname = "stimpack" , iflavour = zipPlain [BrYellow] , irarity = [(1, 40), (10, 40)] , iaspects = [] , ieffects = [NoEffect "of youth", OverfillCalm 5, OverfillHP 15] , ifeature = [Identified, Applicable, Precious] -- TODO: only heal humans , idesc = "Calms, heals, invigorates and rejuvenates at the same time. No side-effects. As valuable as precious gems, at 100 gold grains each." } currency = ItemKind { isymbol = symbolGold , iname = "gold grain" , ifreq = [("treasure", 100), ("currency", 100)] , iflavour = zipPlain [BrYellow] , icount = 10 + d 20 + dl 20 , irarity = [(1, 25), (10, 10)] , iverbHit = "tap" , iweight = 1 , iaspects = [] , ieffects = [] , ifeature = [Identified, Precious] , idesc = "Reliably valuable in every civilized place." , ikit = [] } Allure-0.5.0.0/GameDefinition/Content/ModeKind.hs0000644000000000000000000003424212555263417017625 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Game mode definitions. module Content.ModeKind ( cdefs ) where import qualified Data.IntMap.Strict as IM import Content.ModeKindPlayer import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind cdefs :: ContentDef ModeKind cdefs = ContentDef { getSymbol = msymbol , getName = mname , getFreq = mfreq , validateSingle = validateSingleModeKind , validateAll = validateAllModeKind , content = [campaign, raid, skirmish, ambush, battle, battleSurvival, safari, safariSurvival, pvp, coop, defense, screensaver] } campaign, raid, skirmish, ambush, battle, battleSurvival, safari, safariSurvival, pvp, coop, defense, screensaver :: ModeKind campaign = ModeKind { msymbol = 'c' , mname = "campaign" , mfreq = [("campaign", 1)] , mroster = rosterCampaign , mcaves = cavesCampaign , mdesc = "You got stranded looting the blasted bridge of a once luxurious cruise liner. Your current plan is to fight through, gathering your spoils, to the shuttle airlock somewhere among the giant spaceship's uppermost decks. There are animal cries down below and ominous silence up above." } raid = ModeKind { msymbol = 'r' , mname = "raid" , mfreq = [("raid", 1)] , mroster = rosterRaid , mcaves = cavesRaid , mdesc = "The Triton City sewers need purging. The first person to break through to the other end will be paid 100 gold grains. Please don't fight." } skirmish = ModeKind { msymbol = 'k' , mname = "skirmish" , mfreq = [("skirmish", 1)] , mroster = rosterSkirmish , mcaves = cavesSkirmish , mdesc = "You cheated. Come alone to the woody biosphere behind the saloon at noon, if you dare. The winner takes all the spoils, including the keys and the papers of the decrepit giant spaceship." } ambush = ModeKind { msymbol = 'm' , mname = "ambush" , mfreq = [("ambush", 1)] , mroster = rosterAmbush , mcaves = cavesAmbush , mdesc = "Conveniently, on the path to the Triton's spaceport, passengers can relax in a shady park." } battle = ModeKind { msymbol = 'b' , mname = "battle" , mfreq = [("battle", 1)] , mroster = rosterBattle , mcaves = cavesBattle , mdesc = "Not even the unexplained ruin of the largest and tightest security Neptune's moon spaceport will prevent you from claiming your prize." } battleSurvival = ModeKind { msymbol = 'i' , mname = "battle survival" , mfreq = [("battle survival", 1)] , mroster = rosterBattleSurvival , mcaves = cavesBattle , mdesc = "Odds are stacked for those that breathe mathematics." } safari = ModeKind { msymbol = 'f' , mname = "safari" , mfreq = [("safari", 1)] , mroster = rosterSafari , mcaves = cavesSafari , mdesc = "In this simulation you'll discover the joys of hunting the most exquisite of Earth's flora and fauna, both animal and semi-intelligent (exit at the uppermost level)." } safariSurvival = ModeKind { msymbol = 'u' , mname = "safari survival" , mfreq = [("safari survival", 1)] , mroster = rosterSafariSurvival , mcaves = cavesSafari , mdesc = "In this simulation you'll discover the joys of being hunted among the most exquisite of Earth's flora and fauna, both animal and semi-intelligent." } pvp = ModeKind { msymbol = 'v' , mname = "PvP" , mfreq = [("PvP", 1)] , mroster = rosterPvP , mcaves = cavesSkirmish , mdesc = "(Not usable right now.) This is a fight to the death between two human-controlled teams." } coop = ModeKind { msymbol = 'o' , mname = "Coop" , mfreq = [("Coop", 1)] , mroster = rosterCoop , mcaves = cavesCampaign , mdesc = "(This mode is intended solely for automated testing.)" } defense = ModeKind { msymbol = 'e' , mname = "defense" , mfreq = [("defense", 1)] , mroster = rosterDefense , mcaves = cavesCampaign , mdesc = "Don't let the half-witted humans derail your operation and flee, like the puny, naked, tentacle-less beasts that they are!" } screensaver = safari { mname = "safari screensaver" , mfreq = [("starting", 1)] , mroster = rosterSafari { rosterList = (head (rosterList rosterSafari)) -- changing leader by client needed, because of TFollow -- changing level by client enabled for UI {fleaderMode = LeaderAI $ AutoLeader False False} : tail (rosterList rosterSafari) } } rosterCampaign, rosterRaid, rosterSkirmish, rosterAmbush, rosterBattle, rosterBattleSurvival, rosterSafari, rosterSafariSurvival, rosterPvP, rosterCoop, rosterDefense :: Roster rosterCampaign = Roster { rosterList = [ playerHero , playerMonster , playerAnimal , playerRobot ] , rosterEnemy = [ ("Spacefarer Crew", "Alien Hierarchy") , ("Spacefarer Crew", "Animal Kingdom") , ("Spacefarer Crew", "Robot Anarchy") ] , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom") , ("Alien Hierarchy", "Robot Anarchy") , ("Robot Anarchy", "Animal Kingdom") ] } rosterRaid = Roster { rosterList = [ playerHero { fname = "Spacefarer Crew" , fhiCondPoly = hiRaid , fentryLevel = 4 , finitialActors = 1 } , playerAntiHero { fname = "Red Collars" , fhiCondPoly = hiRaid , fentryLevel = 4 , finitialActors = 1 } , playerAnimal { fentryLevel = 4 , finitialActors = 1 } , playerRobot { fentryLevel = 4 , finitialActors = 1 } ] , rosterEnemy = [ ("Spacefarer Crew", "Animal Kingdom") , ("Spacefarer Crew", "Robot Anarchy") , ("Red Collars", "Animal Kingdom") , ("Red Collars", "Robot Anarchy") ] , rosterAlly = [("Robot Anarchy", "Animal Kingdom")] } rosterSkirmish = Roster { rosterList = [ playerHero { fname = "Spacefarer Crew" , fhiCondPoly = hiDweller , fentryLevel = 4 } , playerAntiHero { fname = "Red Collars" , fhiCondPoly = hiDweller , fentryLevel = 4 } , playerHorror ] , rosterEnemy = [ ("Spacefarer Crew", "Red Collars") , ("Spacefarer Crew", "Horror Den") , ("Red Collars", "Horror Den") ] , rosterAlly = [] } rosterAmbush = rosterSkirmish { rosterList = [ playerSniper { fname = "Spacefarer Crew" , fhiCondPoly = hiDweller , fentryLevel = 7 , finitialActors = 4 } , playerAntiSniper { fname = "Red Collars" , fhiCondPoly = hiDweller , fentryLevel = 7 , finitialActors = 4 } , playerHorror {fentryLevel = 7} ] } rosterBattle = Roster { rosterList = [ playerSoldier { fhiCondPoly = hiDweller , fentryLevel = 7 , finitialActors = 5 } , playerMobileMonster { fentryLevel = 7 , finitialActors = 35 , fneverEmpty = True } , playerMobileAnimal { fentryLevel = 7 , finitialActors = 20 , fneverEmpty = True } , playerMobileRobot { fentryLevel = 7 , finitialActors = 15 , fneverEmpty = True } ] , rosterEnemy = [ ("Armed Spacefarer Crew", "Alien Hierarchy") , ("Armed Spacefarer Crew", "Animal Kingdom") , ("Armed Spacefarer Crew", "Robot Anarchy") ] , rosterAlly = [ ("Alien Hierarchy", "Animal Kingdom") , ("Alien Hierarchy", "Robot Anarchy") , ("Robot Anarchy", "Animal Kingdom") ] } rosterBattleSurvival = rosterBattle { rosterList = [ playerSoldier { fhiCondPoly = hiDweller , fentryLevel = 7 , finitialActors = 5 , fleaderMode = LeaderAI $ AutoLeader True False , fhasUI = False } , playerMobileMonster { fentryLevel = 7 , finitialActors = 35 , fneverEmpty = True } , playerMobileAnimal { fentryLevel = 7 , finitialActors = 20 , fneverEmpty = True } , playerMobileRobot { fentryLevel = 7 , finitialActors = 15 , fneverEmpty = True , fhasUI = True } ] } playerMonsterTourist, playerHunamConvict, playerAnimalMagnificent, playerAnimalExquisite :: Player Dice playerMonsterTourist = playerAntiMonster { fname = "Alien Tourist Office" , fcanEscape = True , fneverEmpty = True -- no spawning -- Follow-the-guide, as tourists do. , ftactic = TFollow , fentryLevel = 4 , finitialActors = 15 , fleaderMode = LeaderUI $ AutoLeader False False } playerHunamConvict = playerCivilian { fname = "Hunam Convict Pack" , fentryLevel = 4 } playerAnimalMagnificent = playerMobileAnimal { fname = "Animal Magnificent Specimen Variety" , fneverEmpty = True , fentryLevel = 7 , finitialActors = 10 , fleaderMode = -- move away from stairs LeaderAI $ AutoLeader True False } playerAnimalExquisite = playerMobileAnimal { fname = "Animal Exquisite Herds and Packs" , fneverEmpty = True , fentryLevel = 10 , finitialActors = 30 } rosterSafari = Roster { rosterList = [ playerMonsterTourist , playerHunamConvict , playerAnimalMagnificent , playerAnimalExquisite ] , rosterEnemy = [ ( "Alien Tourist Office", "Hunam Convict Pack") , ( "Alien Tourist Office" , "Animal Magnificent Specimen Variety" ) , ( "Alien Tourist Office" , "Animal Exquisite Herds and Packs" ) ] , rosterAlly = [ ( "Animal Magnificent Specimen Variety" , "Animal Exquisite Herds and Packs" ) , ( "Animal Magnificent Specimen Variety" , "Hunam Convict Pack" ) , ( "Hunam Convict Pack" , "Animal Exquisite Herds and Packs" ) ] } rosterSafariSurvival = rosterSafari { rosterList = [ playerMonsterTourist { fleaderMode = LeaderAI $ AutoLeader True False , fhasUI = False } , playerHunamConvict , playerAnimalMagnificent { fleaderMode = LeaderUI $ AutoLeader False False , fhasUI = True } , playerAnimalExquisite ] } rosterPvP = Roster { rosterList = [ playerHero { fname = "Red" , fhiCondPoly = hiDweller , fentryLevel = 4 } , playerHero { fname = "Blue" , fhiCondPoly = hiDweller , fentryLevel = 4 } , playerHorror ] , rosterEnemy = [ ("Red", "Blue") , ("Red", "Horror Den") , ("Blue", "Horror Den") ] , rosterAlly = [] } rosterCoop = Roster { rosterList = [ playerAntiHero { fname = "Coral" } , playerAntiHero { fname = "Amber" , fleaderMode = LeaderNull } , playerAnimal { fhasUI = True } , playerAnimal , playerMonster { fname = "Alien Hierarchy" , finitialActors = 3 } , playerMonster { fname = "Leaderless Alien Hierarchy" , finitialActors = 1 , fleaderMode = LeaderNull } , playerRobot ] , rosterEnemy = [ ("Coral", "Alien Hierarchy") , ("Amber", "Alien Hierarchy") ] , rosterAlly = [ ("Coral", "Amber") ] } rosterDefense = rosterCampaign { rosterList = [ playerAntiHero , playerAntiMonster , playerAnimal , playerRobot ] } cavesCampaign, cavesRaid, cavesSkirmish, cavesAmbush, cavesBattle, cavesSafari :: Caves cavesCampaign = IM.fromList $ [(1, ("shallow random 1", Nothing))] ++ [(2, ("shallow random 2", Nothing))] ++ [(3, ("caveBridge", Nothing))] ++ [(4, ("caveNoise", Nothing))] ++ zip [5..9] (repeat ("campaign random", Nothing)) ++ [(10, ("caveEmpty", Just False))] ++ [(11, ("campaign random", Nothing))] ++ [(12, ("caveNoise", Nothing))] cavesRaid = IM.fromList [(4, ("caveRogueLit", Just True))] cavesSkirmish = IM.fromList [(4, ("caveSkirmish", Nothing))] cavesAmbush = IM.fromList [(7, ("caveAmbush", Nothing))] cavesBattle = IM.fromList [(7, ("caveBattle", Nothing))] cavesSafari = IM.fromList [ (4, ("caveSafari1", Nothing)) , (7, ("caveSafari2", Nothing)) , (10, ("caveSafari3", Just False)) ] Allure-0.5.0.0/GameDefinition/Content/CaveKind.hs0000644000000000000000000002214412555263417017615 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Cave layouts. module Content.CaveKind ( cdefs ) where import Data.Ratio import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.CaveKind cdefs :: ContentDef CaveKind cdefs = ContentDef { getSymbol = csymbol , getName = cname , getFreq = cfreq , validateSingle = validateSingleCaveKind , validateAll = validateAllCaveKind , content = [rogue, arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, rogueLit, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena] } rogue, arena, empty, noise, battle, skirmish, ambush, safari1, safari2, safari3, rogueLit, bridge, shallow2rogue, shallow2arena, shallow2empty, shallow1arena :: CaveKind rogue = CaveKind { csymbol = 'R' , cname = "Storage area" , cfreq = [("campaign random", 100), ("caveRogue", 1)] , cxsize = fst normalLevelBound + 1 , cysize = snd normalLevelBound + 1 , cgrid = DiceXY (3 * d 2) (d 2 + 2) , cminPlaceSize = DiceXY (2 * d 2 + 2) 4 , cmaxPlaceSize = DiceXY 15 10 , cdarkChance = d 54 + dl 20 , cnightChance = 51 -- always night , cauxConnects = 1%3 , cmaxVoid = 1%6 , cminStairDist = 30 , cdoorChance = 1%2 , copenChance = 1%10 , chidden = 8 , cactorCoeff = 150 -- the maze requires time to explore , cactorFreq = [("alien", 50), ("animal", 25), ("robot", 25)] , citemNum = 10 * d 2 , citemFreq = [("useful", 50), ("treasure", 50)] , cplaceFreq = [("rogue", 100)] , cpassable = False , cdefTile = "fillerWall" , cdarkCorTile = "floorCorridorDark" , clitCorTile = "floorCorridorLit" , cfillerTile = "fillerWall" , couterFenceTile = "basic outer fence" , clegendDarkTile = "legendDark" , clegendLitTile = "legendLit" } arena = rogue { csymbol = 'A' , cname = "Recreational deck" , cfreq = [("campaign random", 50), ("caveArena", 1)] , cgrid = DiceXY (2 * d 2) (2 * d 2) , cminPlaceSize = DiceXY (2 * d 2 + 3) 4 , cdarkChance = d 100 - dl 50 -- Trails provide enough light for fun stealth. Light is not too deadly, -- because not many obstructions, so foes visible from far away. , cnightChance = d 50 + dl 50 , cmaxVoid = 1%4 , chidden = 1000 , cactorCoeff = 100 , cactorFreq = [("alien", 25), ("animal", 70), ("robot", 5)] , citemNum = 9 * d 2 -- few rooms , cpassable = True , cdefTile = "arenaSet" , cdarkCorTile = "trailLit" -- let trails give off light , clitCorTile = "trailLit" } empty = rogue { csymbol = 'E' , cname = "Construction site" , cfreq = [("campaign random", 50), ("caveEmpty", 1)] , cgrid = DiceXY (d 2 + 1) 1 , cminPlaceSize = DiceXY 10 10 , cmaxPlaceSize = DiceXY 24 15 , cdarkChance = d 80 + dl 80 , cnightChance = 0 -- always day , cauxConnects = 1 , cmaxVoid = 1%2 , cminStairDist = 50 , chidden = 1000 , cactorCoeff = 80 , cactorFreq = [("alien", 25), ("animal", 5), ("robot", 70)] , citemNum = 7 * d 2 -- few rooms , cpassable = True , cdefTile = "emptySet" , cdarkCorTile = "floorArenaDark" , clitCorTile = "floorArenaLit" } noise = rogue { csymbol = 'N' , cname = "Machine rooms" , cfreq = [("caveNoise", 1)] , cgrid = DiceXY (2 + d 2) 3 , cminPlaceSize = DiceXY 12 5 , cmaxPlaceSize = DiceXY 24 15 , cdarkChance = 0 -- few rooms, so all lit -- Light is deadly, because nowhere to hide and pillars enable spawning -- very close to heroes, so deep down light should be rare. , cnightChance = dl 300 , cauxConnects = 0 , cmaxVoid = 0 , chidden = 1000 , cactorCoeff = 160 -- the maze requires time to explore , cactorFreq = [("alien", 70), ("animal", 15), ("robot", 15)] , citemNum = 12 * d 2 -- an incentive to explore the labyrinth , cpassable = True , cplaceFreq = [("noise", 100)] , cdefTile = "noiseSet" , cdarkCorTile = "floorArenaDark" , clitCorTile = "floorArenaLit" } battle = rogue -- few lights and many solids, to help the less numerous heroes { csymbol = 'B' , cname = "Ravaged spaceport" , cfreq = [("caveBattle", 1)] , cgrid = DiceXY (2 * d 2 + 1) 3 , cminPlaceSize = DiceXY 4 4 , cmaxPlaceSize = DiceXY 9 7 , cdarkChance = 0 , cnightChance = 51 -- always night , cmaxVoid = 0 , cdoorChance = 2%10 , copenChance = 9%10 , chidden = 1000 , cactorFreq = [] , citemNum = 20 * d 2 , citemFreq = [("useful", 100), ("light source", 200)] , cplaceFreq = [("battle", 50), ("rogue", 50)] , cpassable = True , cdefTile = "battleSet" , cdarkCorTile = "trailLit" -- let trails give off light , clitCorTile = "trailLit" } skirmish = rogue -- many random solid tiles, to break LOS, since it's a day { csymbol = 'S' , cname = "Woodland biosphere" , cfreq = [("caveSkirmish", 1)] , cgrid = DiceXY (2 * d 2 + 2) (d 2 + 2) , cminPlaceSize = DiceXY 3 3 , cmaxPlaceSize = DiceXY 7 5 , cdarkChance = 100 , cnightChance = 0 , cdoorChance = 1 , copenChance = 0 , chidden = 1000 , cactorFreq = [] , citemNum = 20 * d 2 , citemFreq = [("useful", 100)] , cplaceFreq = [("skirmish", 60), ("rogue", 40)] , cpassable = True , cdefTile = "skirmishSet" , cdarkCorTile = "floorArenaLit" , clitCorTile = "floorArenaLit" } ambush = rogue -- lots of lights, to give a chance to snipe { csymbol = 'M' , cname = "Public garden" , cfreq = [("caveAmbush", 1)] , cgrid = DiceXY (2 * d 2 + 3) (d 2 + 2) , cminPlaceSize = DiceXY 3 3 , cmaxPlaceSize = DiceXY 5 5 , cdarkChance = 0 , cnightChance = 51 -- always night , cauxConnects = 1 , cdoorChance = 1%10 , copenChance = 9%10 , chidden = 1000 , cactorFreq = [] , citemNum = 22 * d 2 , citemFreq = [("useful", 100)] , cplaceFreq = [("ambush", 100)] , cpassable = True , cdefTile = "ambushSet" , cdarkCorTile = "trailLit" -- let trails give off light , clitCorTile = "trailLit" } safari1 = ambush {cfreq = [("caveSafari1", 1)]} safari2 = battle {cfreq = [("caveSafari2", 1)]} safari3 = skirmish {cfreq = [("caveSafari3", 1)]} rogueLit = rogue { csymbol = 'S' , cname = "Triton City Sewers" , cfreq = [("caveRogueLit", 1)] , cdarkChance = 0 , cmaxVoid = 1%10 , cactorCoeff = 1000 -- deep level with no eqp, so slow spawning , cactorFreq = [("animal", 50), ("robot", 50)] , citemNum = 30 * d 2 -- just one level, hard enemies, treasure , citemFreq = [("useful", 33), ("gem", 33), ("currency", 33)] , cdarkCorTile = "emergency walkway" , clitCorTile = "emergency walkway" } bridge = rogueLit { csymbol = 'B' , cname = "Captain's bridge" , cfreq = [("caveBridge", 1)] , cgrid = DiceXY (d 2 + 1) 2 , cminPlaceSize = DiceXY 10 7 , cmaxPlaceSize = DiceXY 40 14 , cactorFreq = [] -- safe, nothing spawns , citemNum = 15 * d 2 -- lure them in with loot , citemFreq = filter ((/= "treasure") . fst) $ citemFreq rogue } shallow2rogue = rogue { cfreq = [("shallow random 2", 50)] , cactorCoeff = cactorCoeff rogue `div` 2 , cactorFreq = filter ((/= "alien") . fst) $ cactorFreq rogue , citemFreq = filter ((/= "treasure") . fst) $ citemFreq rogue } shallow2arena = arena { cfreq = [("shallow random 2", 100)] , cnightChance = 0 -- safe and easy , cactorCoeff = cactorCoeff arena `div` 2 , cactorFreq = filter ((/= "alien") . fst) $ cactorFreq empty , citemFreq = filter ((/= "treasure") . fst) $ citemFreq empty } shallow2empty = empty { cfreq = [("shallow random 2", 20)] , cactorFreq = filter ((/= "alien") . fst) $ cactorFreq empty , cactorCoeff = cactorCoeff empty `div` 2 , citemFreq = filter ((/= "treasure") . fst) $ citemFreq empty } shallow1arena = shallow2empty -- TODO: replace some rooms with oriels? { cname = "Outermost deck" , cfreq = [("shallow random 1", 100)] , cminPlaceSize = DiceXY (2 * d 2 + 3) 3 , cactorCoeff = 3 -- mostly immobile actors anyway , cactorFreq = [("animal", 8), ("robot", 2), ("immobile robot", 90)] -- The medbot faucets on lvl 1 act like HP resets. They are needed to avoid -- cascading failure, if the particular starting conditions were -- very hard. The items are not reset, even if the are bad, which provides -- enough of a continuity. The faucets on lvl 1 are not OP and can't be -- abused, because they spawn less and less often and they don't heal over -- max HP. , couterFenceTile = "oriels fence" } Allure-0.5.0.0/GameDefinition/Content/ItemKindActor.hs0000644000000000000000000006352412555263417020635 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Actor (or rather actor body trunk) definitions. module Content.ItemKindActor ( actors ) where import qualified Data.EnumMap.Strict as EM import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ItemKind actors :: [ItemKind] actors = [warrior, warrior2, warrior3, warrior4, soldier, sniper, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, medbotFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, cleanerRobot] warrior, warrior2, warrior3, warrior4, soldier, sniper, civilian, civilian2, civilian3, civilian4, civilian5, eye, fastEye, nose, elbow, torsor, goldenJackal, griffonVulture, skunk, armadillo, gilaMonster, rattlesnake, komodoDragon, hyena, alligator, rhinoceros, beeSwarm, hornetSwarm, thornbush, razorwireFence, electricFence, activeFence, steamFaucet, biogasFaucet, medbotFaucet, surveillanceDrone, shepherdDrone, huntingDrone, homeRobot, wasteRobot, lightRobot, heavyRobot, cleanerRobot :: ItemKind -- * Hunams warrior = ItemKind { isymbol = '@' , iname = "mercenary" -- modified if in hero faction , ifreq = [("hero", 100), ("civilian", 100), ("mobile", 1)] , iflavour = zipPlain [BrBlack] -- modified if in hero faction , icount = 1 , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 80 -- partially from clothes and assumed first aid -- also possibly from artificial skin , AddMaxCalm 60, AddSpeed 20 , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1)] ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("fist", COrgan), ("foot", COrgan), ("eye 5", COrgan) , ("sapient brain", COrgan) ] } warrior2 = warrior { iname = "pilot" } warrior3 = warrior { iname = "engineer" } warrior4 = warrior { iname = "doctor" } soldier = warrior { iname = "soldier" , ifreq = [("soldier", 100), ("mobile", 1)] , ikit = ikit warrior ++ [("starting weapon", CEqp)] } sniper = warrior { iname = "sniper" , ifreq = [("sniper", 100), ("mobile", 1)] , ikit = ikit warrior ++ [ ("ring of opportunity sniper", CEqp) , ("any arrow", CSha), ("any arrow", CInv) , ("any arrow", CInv), ("any arrow", CInv) , ("flask", CInv), ("light source", CSha) , ("light source", CInv), ("light source", CInv) ] } civilian = warrior { iname = "clerk" , ifreq = [("civilian", 100), ("mobile", 1)] } civilian2 = civilian { iname = "hairdresser" } civilian3 = civilian { iname = "lawyer" } civilian4 = civilian { iname = "peddler" } civilian5 = civilian { iname = "tax collector" } -- * Aliens eye = ItemKind { isymbol = 'w' , iname = "beckoning walker" , ifreq = [("alien", 100), ("horror", 100), ("mobile alien", 100)] , iflavour = zipFancy [BrRed] , icount = 1 , irarity = [(4, 6), (10, 10)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 20 , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1)] ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Walks with a stately dignity. You read death in the slow beckoning gestures of its revolting upper appendages." , ikit = [ ("foot", COrgan), ("tentacle", COrgan) , ("eye 5", COrgan) , ("sapient brain", COrgan) ] } fastEye = ItemKind { isymbol = 'b' , iname = "crawling biter" , ifreq = [("alien", 100), ("horror", 100), ("mobile alien", 100)] , iflavour = zipFancy [BrBlue] , icount = 1 , irarity = [(4, 3), (10, 10)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 5, AddMaxCalm 60, AddSpeed 30 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "It bites as blindingly fast as it runs. Or rolls? Or crawls? Also, cuts and pierces." , ikit = [ ("tentacle", COrgan), ("jaw", COrgan) , ("eye 4", COrgan), ("speed gland 10", COrgan) , ("sapient brain", COrgan) ] } nose = ItemKind -- depends solely on smell { isymbol = 'h' , iname = "tentacled horror" , ifreq = [("alien", 100), ("horror", 100), ("mobile alien", 100)] , iflavour = zipFancy [BrGreen] , icount = 1 , irarity = [(4, 5), (10, 9)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 30, AddMaxCalm 30, AddSpeed 18 , AddSkills $ EM.fromList [(AbProject, -1)] ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "A blind, slimy mass of clawing, stinging and burning. You'd think it's powerless, but as soon as it touches your trembling body, it's always one step ahead." , ikit = [ ("nostril", COrgan), ("small claw", COrgan) , ("tentacle", COrgan), ("tentacle", COrgan) , ("thorn", COrgan), ("sting", COrgan) , ("sapient brain", COrgan) ] } elbow = ItemKind { isymbol = 's' , iname = "creepy shooter" , ifreq = [("alien", 100), ("horror", 100), ("mobile alien", 100)] , iflavour = zipFancy [BrMagenta] , icount = 1 , irarity = [(6, 1), (10, 9)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 12, AddMaxCalm 90, AddSpeed 21 , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1), (AbMelee, -1)] ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "It moves in sudden jerks and never makes a noise. Speaks in hard objects hurled at deadly speeds." , ikit = [ ("speed gland 4", COrgan) , ("eye 7", COrgan) , ("any arrow", CSha), ("any arrow", CInv) , ("any arrow", CInv), ("any arrow", CInv) , ("sapient brain", COrgan) ] } torsor = ItemKind { isymbol = 'M' , iname = "The Maker of Contact" , ifreq = [("alien", 100), ("mobile", 1)] , iflavour = zipFancy [BrCyan] , icount = 1 , irarity = [(11 * 10/12, 0), (10, 1000)] -- unique , iverbHit = "thud" , iweight = 80000 , iaspects = [ Unique, AddMaxHP 300, AddMaxCalm 100, AddSpeed 6 , AddSkills $ EM.fromList [(AbProject, 2), (AbApply, 1), (AbTrigger, -1)] ] -- can't switch levels, a miniboss , ieffects = [] , ifeature = [Durable, Identified] , idesc = "The mind, the heart behind it all. Warmth and sympathy pour out through the graceful undulation of tentacles, sharp claws, snapping jaw, grinding teeth and tensing fangs." , ikit = [ ("tentacle", COrgan), ("claw", COrgan), ("large jaw", COrgan) , ("venom tooth", COrgan), ("venom fang", COrgan) , ("eye 5", COrgan), ("speed gland 4", COrgan) , ("gem", CInv), ("gem", CInv), ("gem", CInv), ("gem", CInv) , ("sapient brain", COrgan) ] } -- * Animals -- They need rather strong melee, because they don't use items. -- Unless/until they level up. goldenJackal = ItemKind -- basically a much smaller and slower hyena { isymbol = 'j' , iname = "golden jackal" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 50)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 13000 , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 22 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("small jaw", COrgan), ("eye 5", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ] } griffonVulture = ItemKind { isymbol = 'v' , iname = "griffon vulture" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 30)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 13000 , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 20 , AddSkills $ EM.singleton AbAlter (-1) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("screeching beak", COrgan) -- in reality it grunts and hisses , ("small claw", COrgan), ("eye 6", COrgan) , ("animal brain", COrgan) ] } skunk = ItemKind { isymbol = 's' , iname = "hog-nosed skunk" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [White] , icount = 1 , irarity = [(1, 5), (10, 3)] , iverbHit = "thud" , iweight = 4000 , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20 , AddSkills $ EM.singleton AbAlter (-1) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("scent gland", COrgan) , ("small claw", COrgan), ("snout", COrgan) , ("nostril", COrgan), ("eye 2", COrgan) , ("animal brain", COrgan) ] } armadillo = ItemKind { isymbol = 'a' , iname = "giant armadillo" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(1, 5)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 20, AddMaxCalm 30, AddSpeed 17 , AddSkills $ EM.singleton AbAlter (-1) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("claw", COrgan), ("snout", COrgan), ("armored skin", COrgan) , ("nostril", COrgan), ("eye 2", COrgan) , ("animal brain", COrgan) ] } gilaMonster = ItemKind { isymbol = 'g' , iname = "Gila monster" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [Magenta] , icount = 1 , irarity = [(2, 5), (10, 3)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 12, AddMaxCalm 60, AddSpeed 15 , AddSkills $ EM.singleton AbAlter (-1) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("venom tooth", COrgan), ("small claw", COrgan) , ("eye 2", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ] } rattlesnake = ItemKind { isymbol = 's' , iname = "rattlesnake" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(4, 1), (10, 7)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 25, AddMaxCalm 60, AddSpeed 15 , AddSkills $ EM.singleton AbAlter (-1) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("venom fang", COrgan) , ("eye 3", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ] } komodoDragon = ItemKind -- bad hearing; regeneration makes it very powerful { isymbol = 'k' , iname = "Komodo dragon" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [Blue] , icount = 1 , irarity = [(7, 0), (10, 10)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 16 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("large tail", COrgan), ("jaw", COrgan), ("claw", COrgan) , ("speed gland 4", COrgan), ("armored skin", COrgan) , ("eye 2", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ] } hyena = ItemKind { isymbol = 'h' , iname = "spotted hyena" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100), ("scavenger", 20)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(4, 1), (10, 8)] , iverbHit = "thud" , iweight = 60000 , iaspects = [ AddMaxHP 20, AddMaxCalm 60, AddSpeed 30 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("jaw", COrgan), ("eye 5", COrgan), ("nostril", COrgan) , ("animal brain", COrgan) ] } alligator = ItemKind { isymbol = 'a' , iname = "alligator" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [Blue] , icount = 1 , irarity = [(6, 1), (10, 9)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 15 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("large jaw", COrgan), ("large tail", COrgan) , ("small claw", COrgan) , ("armored skin", COrgan), ("eye 5", COrgan) , ("animal brain", COrgan) ] } rhinoceros = ItemKind { isymbol = 'R' , iname = "The Maddened Rhinoceros" , ifreq = [("animal", 100), ("mobile", 1)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(1 * 10/12, 1000000), (2 * 10/12, 0)] -- unique , iverbHit = "thud" , iweight = 80000 , iaspects = [ Unique, AddMaxHP 90, AddMaxCalm 60, AddSpeed 25 , AddSkills $ EM.singleton AbTrigger (-1) ] -- can't switch levels, a miniboss , ieffects = [] , ifeature = [Durable, Identified] , idesc = "The last of its kind. Blind with rage. Charges at deadly speed." , ikit = [ ("armored skin", COrgan), ("eye 2", COrgan) , ("horn", COrgan), ("snout", COrgan) , ("animal brain", COrgan) ] } -- * Non-animal animals beeSwarm = ItemKind { isymbol = 'b' , iname = "bee swarm" , ifreq = [("animal", 100), ("horror", 100)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(1, 2), (10, 4)] , iverbHit = "thud" , iweight = 1000 , iaspects = [ AddMaxHP 8, AddMaxCalm 60, AddSpeed 30 , AddSkills $ EM.singleton AbAlter (-1) ] -- armor in sting , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("bee sting", COrgan), ("vision 4", COrgan) , ("insect mortality", COrgan), ("animal brain", COrgan) ] } hornetSwarm = ItemKind { isymbol = 'h' , iname = "hornet swarm" , ifreq = [("animal", 100), ("horror", 100), ("mobile animal", 100)] , iflavour = zipPlain [Magenta] , icount = 1 , irarity = [(5, 1), (10, 8)] , iverbHit = "thud" , iweight = 1000 , iaspects = [ AddMaxHP 8, AddMaxCalm 60, AddSpeed 30 , AddSkills $ EM.singleton AbAlter (-1) , AddArmorMelee 80, AddArmorRanged 80 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [ ("sting", COrgan), ("vision 4", COrgan) , ("insect mortality", COrgan), ("animal brain", COrgan) ] } thornbush = ItemKind { isymbol = 't' , iname = "thornbush" , ifreq = [("animal", 50)] , iflavour = zipPlain [Brown] , icount = 1 , irarity = [(1, 3)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20 , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "" , ikit = [("thorn", COrgan), ("armored skin", COrgan)] } -- * Robots razorwireFence = ItemKind { isymbol = 'f' , iname = "razorwire fence" , ifreq = [("robot", 50), ("immobile robot", 50)] , iflavour = zipPlain [Cyan] , icount = 1 , irarity = [(3 * 10/12, 0), (4, 2)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20 , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) , AddArmorMelee 50, AddArmorRanged 50 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Must have been bought by previous ship owners to contain the wild animal infestation." , ikit = [("razor", COrgan)] } electricFence = ItemKind { isymbol = 'f' , iname = "electric fence" , ifreq = [("robot", 50), ("immobile robot", 50)] , iflavour = zipPlain [Blue] , icount = 1 , irarity = [(3 * 10/12, 0), (4, 2)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 40 , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) , AddArmorMelee 50, AddArmorRanged 50 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Marginally intelligent electric shepherd. Originally used in the spaceship's dairy farm and the zoo level." , ikit = [("live wire", COrgan)] } activeFence = ItemKind { isymbol = 'f' , iname = "active fence" , ifreq = [("robot", 50), ("immobile robot", 100)] , iflavour = zipPlain [Red] , icount = 1 , irarity = [(3 * 10/12, 0), (4, 1)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 20, AddMaxCalm 999, AddSpeed 20 , AddSkills $ EM.fromList [(AbWait, 1), (AbProject, 3)] , AddArmorMelee 50, AddArmorRanged 50 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Makeshift, mostly non-lethal, autonomous perimeter defense outpost." , ikit = [ ("vision 6", COrgan) , ("needle", CInv), ("can of sticky foam", CInv) ] } steamFaucet = ItemKind { isymbol = 'f' , iname = "steam faucet" , ifreq = [("robot", 50), ("immobile robot", 50)] , iflavour = zipPlain [BrWhite] , icount = 1 , irarity = [(5, 2)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 10, AddMaxCalm 999, AddSpeed 10 , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) , AddArmorMelee 80, AddArmorRanged 80 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "A cracked valve on one of the superheated water pipes spreading radially outward from the tokamak level." , ikit = [("boiling vent", COrgan), ("boiling fissure", COrgan)] } biogasFaucet = ItemKind { isymbol = 'f' , iname = "biogas faucet" , ifreq = [("robot", 50), ("immobile robot", 100)] , iflavour = zipPlain [BrGreen] , icount = 1 , irarity = [(5, 2)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3 , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "An emergency pressure-release vent on a smelly biogas pipe." , ikit = [("biogas vent", COrgan), ("biogas fissure", COrgan)] } medbotFaucet = ItemKind { isymbol = 'f' , iname = "nano medbot faucet" , ifreq = [("robot", 50), ("immobile robot", 400)] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(5, 2)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 30, AddMaxCalm 999, AddSpeed 20, AddLight 3 , AddSkills $ EM.fromList (zip [AbWait, AbMelee] [1, 1..]) ] , ieffects = [] , ifeature = [Durable, Identified] -- TODO: only heal humans , idesc = "A faucet of a malfunctioning nano medical robot dispenser. Let's hope the medbots are still effective." , ikit = [("medbot vent", COrgan), ("medbot fissure", COrgan)] } surveillanceDrone = ItemKind { isymbol = 'd' , iname = "surveillance drone" , ifreq = [("robot", 100), ("horror", 100), ("mobile robot", 100)] , iflavour = zipPlain [Blue] , icount = 1 , irarity = [] -- TODO: too boring , iverbHit = "thud" , iweight = 1000 , iaspects = [ AddMaxHP 3, AddMaxCalm 90, AddSpeed 30 , AddSkills $ EM.fromList $ zip [AbDisplace, AbMoveItem, AbProject, AbMelee] [-1, -1..] , AddArmorMelee 80, AddArmorRanged 80 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "A video camera in each room would violate privacy of passengers, hence surveillance drones. Programmed to be easy to fend off, they keep a respectful distance." , ikit = [ ("vision 14", COrgan), ("robot brain", COrgan) ] } shepherdDrone = ItemKind { isymbol = 'd' , iname = "shepherd drone" , ifreq = [("robot", 100), ("horror", 100), ("mobile robot", 100)] , iflavour = zipPlain [BrRed] , icount = 1 , irarity = [(1, 7)] , iverbHit = "thud" , iweight = 1000 , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 30 , AddSkills $ EM.fromList $ zip [AbDisplace, AbMoveItem, AbProject] [-1, -1..] , AddArmorMelee 80, AddArmorRanged 80 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "A shabby drone for bringing cows home." , ikit = [ ("eye 4", COrgan), ("live wire", COrgan) , ("robot brain", COrgan) ] } huntingDrone = ItemKind { isymbol = 'd' , iname = "hunting drone" , ifreq = [("robot", 100), ("horror", 100), ("mobile robot", 100)] , iflavour = zipPlain [Green] , icount = 1 , irarity = [(3, 0), (5, 2), (10, 4)] , iverbHit = "thud" , iweight = 500 , iaspects = [ AddMaxHP 3, AddMaxCalm 60, AddSpeed 40 , AddSkills $ EM.fromList $ zip [AbDisplace, AbMoveItem, AbMelee] [-1, -1..] , AddArmorMelee 80, AddArmorRanged 80 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Originally designed for hunting down and putting to sleep stray animals. The sleeping agent has long since dried up." , ikit = [ ("eye 5", COrgan), ("needle", CInv) , ("robot brain", COrgan) ] } homeRobot = ItemKind { isymbol = 'r' , iname = "feral home robot" -- TODO: name another 'deranged', tertiary imperative: survival , ifreq = [("robot", 100), ("horror", 100), ("mobile robot", 100)] , iflavour = zipPlain [Magenta] , icount = 1 , irarity = [(1, 20), (10, 6)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 10, AddMaxCalm 30, AddSpeed 20 , AddSkills $ EM.singleton AbProject (-1) ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Once a timid household robot, now sufficiently adapted to survive in the deadly environment." , ikit = [ ("fist", COrgan), ("eye 2", COrgan), ("nostril", COrgan) , ("robot brain", COrgan) ] } wasteRobot = ItemKind { isymbol = 'r' , iname = "waste disposal robot" , ifreq = [ ("robot", 100), ("horror", 100), ("mobile robot", 100) , ("construction robot", 1) ] , iflavour = zipPlain [Green] , icount = 1 , irarity = [(1, 10), (10, 6)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 15, AddMaxCalm 30, AddSpeed 15 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "You are not in its database, hence you are waste." , ikit = [ ("jaw", COrgan), ("tentacle", COrgan) , ("waste container", COrgan), ("armored skin", COrgan) , ("eye 2", COrgan), ("nostril", COrgan) , ("robot brain", COrgan) ] } lightRobot = ItemKind { isymbol = 'r' , iname = "decoration robot" , ifreq = [ ("robot", 100), ("horror", 100), ("mobile robot", 100) , ("construction robot", 1) ] , iflavour = zipPlain [BrYellow] , icount = 1 , irarity = [(3, 1), (10, 10)] , iverbHit = "thud" , iweight = 80000 , iaspects = [ AddMaxHP 15, AddMaxCalm 60, AddSpeed 30 , AddSkills $ EM.singleton AbProject 2 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Interior and exterior decoration robot. Strongly fancies deep reds recently." , ikit = [ ("claw", COrgan), ("tentacle", COrgan), ("spotlight", COrgan) , ("armored skin", COrgan), ("eye 5", COrgan) , ("robot brain", COrgan) ] } heavyRobot = ItemKind { isymbol = 'r' , iname = "construction robot" , ifreq = [ ("robot", 100), ("horror", 100), ("mobile robot", 100) , ("construction robot", 100) ] , iflavour = zipPlain [BrRed] , icount = 1 , irarity = [(6, 0), (10, 10)] , iverbHit = "thud" , iweight = 800000 , iaspects = [ AddMaxHP 41, AddMaxCalm 60, AddSpeed 20 , AddSkills $ EM.singleton AbProject 2 ] , ieffects = [] , ifeature = [Durable, Identified] , idesc = "Heavy multi-purpose construction robot. Excels at discharging, dismantling and demolition." , ikit = [ ("large jaw", COrgan), ("small claw", COrgan), ("spotlight", COrgan) , ("construction hooter", CInv) , ("armored skin", COrgan), ("eye 4", COrgan) , ("robot brain", COrgan) ] } cleanerRobot = ItemKind { isymbol = 'C' , iname = "The Void Cleaner Robot" , ifreq = [("robot", 100), ("mobile", 1)] , iflavour = zipPlain [BrGreen] , icount = 1 , irarity = [(9 * 10/12, 0), (10 * 10/12, 1000), (11 * 10/12, 0)] -- unique, appears at 10 of 12 , iverbHit = "thud" , iweight = 80000 , iaspects = [ Unique, AddMaxHP 120, AddMaxCalm 60, AddSpeed 18 , AddSkills $ EM.singleton AbTrigger (-1) ] -- can't switch levels, a miniboss , ieffects = [] , ifeature = [Durable, Identified] , idesc = "A waste disposal robot repaired with parts from a heavy construction robot, including a scaled up goal matrix. The cosmic void is now the only acceptable model of cleanliness." , ikit = [ ("waste container", COrgan), ("boiling vent", COrgan) , ("armored skin", COrgan), ("live wire", COrgan) , ("jaw", COrgan), ("claw", COrgan) , ("eye 2", COrgan), ("nostril", COrgan), ("spotlight", COrgan) , ("currency", CInv), ("currency", CInv), ("currency", CInv) , ("robot brain", COrgan) ] } Allure-0.5.0.0/GameDefinition/Content/RuleKind.hs0000644000000000000000000000601312555263417017643 0ustar0000000000000000{-# LANGUAGE TemplateHaskell #-} -- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Game rules and assorted game setup data. module Content.RuleKind ( cdefs ) where import Language.Haskell.TH.Syntax import System.FilePath -- Cabal import qualified Paths_Allure as Self (getDataFileName, version) import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Content.RuleKind cdefs :: ContentDef RuleKind cdefs = ContentDef { getSymbol = rsymbol , getName = rname , getFreq = rfreq , validateSingle = validateSingleRuleKind , validateAll = validateAllRuleKind , content = [standard] } standard :: RuleKind standard = RuleKind { rsymbol = 's' , rname = "standard Allure of the Stars ruleset" , rfreq = [("standard", 100)] -- Check whether one position is accessible from another. -- Precondition: the two positions are next to each other -- and the target tile is walkable. -- TODO: in the future check flying for chasms, swimming for water, etc. , raccessible = Nothing , raccessibleDoor = Nothing , rtitle = "Allure of the Stars" , rpathsDataFile = Self.getDataFileName , rpathsVersion = Self.version -- The strings containing the default configuration file -- included from config.ui.default. , rcfgUIName = "config.ui" , rcfgUIDefault = $(do let path = "GameDefinition" "config.ui" <.> "default" qAddDependentFile path x <- qRunIO (readFile path) lift x) -- ASCII art for the Main Menu. Only pure 7-bit ASCII characters are -- allowed. The picture should be exactly 24 rows by 80 columns, -- plus an extra frame (of any characters) that is ignored. -- For a different screen size, the picture is centered and the outermost -- rows and columns cloned. When displayed in the Main Menu screen, -- it's overwritten with the game version string and keybinding strings. -- The game version string begins and ends with a space and is placed -- in the very bottom right corner. The keybindings overwrite places -- marked with 25 left curly brace signs '{' in a row. The sign is forbidden -- everywhere else. A specific number of such places with 25 left braces -- are required, at most one per row, and all are overwritten -- with text that is flushed left and padded with spaces. -- The Main Menu is displayed dull white on black. -- TODO: Show highlighted keybinding in inverse video or bright white on grey -- background. The spaces that pad keybindings are not highlighted. , rmainMenuArt = $(do let path = "GameDefinition/MainMenu.ascii" qAddDependentFile path x <- qRunIO (readFile path) lift x) , rfirstDeathEnds = False , rfovMode = Digital , rwriteSaveClips = 500 , rleadLevelClips = 100 , rscoresFile = "scores" , rsavePrefix = "save" , rnearby = 20 } Allure-0.5.0.0/GameDefinition/Content/PlaceKind.hs0000644000000000000000000001764312555263417017773 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Room, hall and passage definitions. module Content.PlaceKind ( cdefs ) where import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Content.PlaceKind cdefs :: ContentDef PlaceKind cdefs = ContentDef { getSymbol = psymbol , getName = pname , getFreq = pfreq , validateSingle = validateSinglePlaceKind , validateAll = validateAllPlaceKind , content = [rect, ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnadeWide, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, maze, maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells] } rect, ruin, collapsed, collapsed2, collapsed3, collapsed4, pillar, pillar2, pillar3, pillar4, colonnade, colonnade2, colonnade3, colonnade4, colonnadeWide, lampPost, lampPost2, lampPost3, lampPost4, treeShade, treeShade2, treeShade3, oval, ovalFloor, ovalSquare, maze, maze2, maze3, mazeBig, mazeBig2, mazeBig3, cells :: PlaceKind rect = PlaceKind -- Valid for any nonempty area, hence low frequency. { psymbol = 'r' , pname = "room" , pfreq = [("rogue", 70), ("ambush", 8), ("noise", 80)] , prarity = [(1, 10), (10, 8)] , pcover = CStretch , pfence = FWall , ptopLeft = ["."] , poverride = [] } ruin = PlaceKind { psymbol = 'R' , pname = "ruin" , pfreq = [("ambush", 17), ("battle", 100), ("noise", 40)] , prarity = [(1, 10), (10, 20)] , pcover = CStretch , pfence = FWall , ptopLeft = ["X"] , poverride = [] } collapsed = PlaceKind { psymbol = 'c' , pname = "collapsed cavern" , pfreq = [("noise", 1)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch , pfence = FNone , ptopLeft = ["#"] , poverride = [('#', "doorlessWallOver_#")] } collapsed2 = collapsed { pfreq = [("noise", 100), ("battle", 50)] , ptopLeft = [ "XX#" , "X##" ] } collapsed3 = collapsed { pfreq = [("noise", 200), ("battle", 50)] , ptopLeft = [ "XXX#" , "X###" ] } collapsed4 = collapsed { pfreq = [("noise", 400), ("battle", 200)] , ptopLeft = [ "XXX#" , "XXX#" , "X###" ] } pillar = PlaceKind { psymbol = 'p' , pname = "pillar room" , pfreq = [("rogue", 1000), ("noise", 50)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch , pfence = FWall -- Larger rooms require support pillars. , ptopLeft = [ "...." , ".O.." , "...." , "...." ] , poverride = [] } pillar2 = pillar { prarity = [(1, 5), (10, 5)] , ptopLeft = [ ".#.." , "#..." , "...." , "...." ] } pillar3 = pillar { prarity = [(1, 5), (10, 5)] , ptopLeft = [ "#..." , "..#." , ".#.." , "...." ] } pillar4 = pillar { prarity = [(10, 7)] , ptopLeft = [ "&.#." , "...." , "#..." , "...." ] } colonnade = PlaceKind { psymbol = 'c' , pname = "colonnade" , pfreq = [("rogue", 70), ("noise", 2000)] , prarity = [(1, 10), (10, 10)] , pcover = CAlternate , pfence = FFloor , ptopLeft = [ ".#" , "#." ] , poverride = [] } colonnade2 = colonnade { prarity = [(1, 2), (10, 4)] , pfence = FGround , ptopLeft = [ ".." , ".O" ] } colonnade3 = colonnade { prarity = [(1, 4), (10, 6)] , ptopLeft = [ "#.." , "..#" ] } colonnade4 = colonnade { ptopLeft = [ "#." , ".." , ".#" ] } colonnadeWide = colonnade { prarity = [(1, 3), (10, 3)] , pfence = FWall , ptopLeft = [ ".." , ".#" ] } lampPost = PlaceKind { psymbol = 'l' , pname = "lamp post" , pfreq = [("ambush", 30), ("battle", 10)] , prarity = [(1, 10), (10, 10)] , pcover = CVerbatim , pfence = FNone , ptopLeft = [ "X.X" , ".O." , "X.X" ] , poverride = [('O', "lampPostOver_O")] } lampPost2 = lampPost { ptopLeft = [ "..." , ".O." , "..." ] } lampPost3 = lampPost { ptopLeft = [ "XX.XX" , "X...X" , "..O.." , "X...X" , "XX.XX" ] } lampPost4 = lampPost { ptopLeft = [ "X...X" , "....." , "..O.." , "....." , "X...X" ] } treeShade = PlaceKind { psymbol = 't' , pname = "tree shade" , pfreq = [("skirmish", 100)] , prarity = [(1, 10), (10, 10)] , pcover = CVerbatim , pfence = FNone , ptopLeft = [ "sss" , "XOs" , "XXs" ] , poverride = [('O', "treeShadeOver_O"), ('s', "treeShadeOver_s")] } treeShade2 = treeShade { ptopLeft = [ "sss" , "XOs" , "Xss" ] } treeShade3 = treeShade { ptopLeft = [ "sss" , "sOs" , "XXs" ] } oval = PlaceKind { psymbol = 'o' , pname = "oval room" , pfreq = [("rogue", 1000)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch , pfence = FWall , ptopLeft = [ "####." , "##..." , "#...." , "#...." , "....." ] , poverride = [] } ovalFloor = oval -- Without outer solid fence, visible from outside. { pfreq = [("rogue", 10000)] , pfence = FGround , ptopLeft = [ "XXXX+#" , "XX###." , "X##..." , "X#...." , "+#...." , "#....." ] } ovalSquare = ovalFloor { pfreq = [("rogue", 3000)] , ptopLeft = [ "X###+" , "##..." , "#...." , "#...." , "+...." ] } maze = PlaceKind { psymbol = 'm' , pname = "maze" , pfreq = [("rogue", 20)] , prarity = [(1, 10), (10, 10)] , pcover = CStretch , pfence = FNone , ptopLeft = [ "#.#.##" , "##.#.." , "#.##.#" , "#.#.#." ] , poverride = [] } maze2 = maze { ptopLeft = [ "###.##" , ".###.." , "..#..#" , ".#..#." ] } maze3 = maze { ptopLeft = [ "###.##" , ".##.#." , "..##.#" , ".#..#." ] } mazeBig = maze { pfreq = [("rogue", 1000)] , ptopLeft = [ "#.#.##" , ".#.#.." , "#.&.##" , ".#.#.." , "#.#..#" , "#.#.#." ] } mazeBig2 = mazeBig { ptopLeft = [ "##..##" , "#.##.." , ".#.###" , ".##.#." , "#.#&.#" , "#.#.#." ] } mazeBig3 = mazeBig { ptopLeft = [ "##..##" , "#.###." , ".#...#" , ".#.##." , "##.#.#" , "#.#.#." ] } cells = PlaceKind { psymbol = '#' , pname = "cells" , pfreq = [("rogue", 100), ("noise", 100)] , prarity = [(1, 10), (10, 10)] , pcover = CReflect , pfence = FWall , ptopLeft = [ "..#" , "..#" , "##." ] , poverride = [] } -- TODO: obtain all the rest as places nested within places. -- 3 places are enough, with 1 or 2 tiles between places, -- on all sides, only vertical, only horizontal, Allure-0.5.0.0/GameDefinition/Content/TileKind.hs0000644000000000000000000002156112555263417017636 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Terrain tile definitions. module Content.TileKind ( cdefs ) where import Control.Arrow (first) import Data.Maybe import qualified Data.Text as T import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.ContentDef import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import qualified Game.LambdaHack.Content.ItemKind as IK import Game.LambdaHack.Content.TileKind cdefs :: ContentDef TileKind cdefs = ContentDef { getSymbol = tsymbol , getName = tname , getFreq = tfreq , validateSingle = validateSingleTileKind , validateAll = validateAllTileKind , content = [wall, wallCache, hardRock, doorlessWall, oriel, pillar, lampPost, burningBush, bush, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorArenaShade, floorRedLit, floorBlueLit, floorGreenLit] ++ map makeDarkColor [floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit] } wall, wallCache, hardRock, doorlessWall, oriel, pillar, lampPost, burningBush, bush, tree, wallSuspect, doorClosed, doorOpen, stairsUp, stairsDown, escapeUp, escapeDown, liftUp, lift, liftDown, unknown, floorCorridorLit, floorActorLit, floorItemLit, floorActorItemLit, floorArenaShade, floorRedLit, floorBlueLit, floorGreenLit :: TileKind oriel = TileKind { tsymbol = '\'' , tname = "oriel" , tfreq = [("oriels fence", 4)] , tcolor = White , tcolor2 = Black , tfeature = [Dark, Impenetrable] } wall = TileKind { tsymbol = '#' , tname = "granite wall" , tfreq = [ ("fillerWall", 1), ("legendLit", 100), ("legendDark", 100) , ("cachable", 70) , ("noiseSet", 100), ("battleSet", 250) ] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [HideAs "suspect wall"] } hardRock = TileKind { tsymbol = '#' , tname = "outer hull" , tfreq = [("basic outer fence", 100), ("oriels fence", 96)] , tcolor = BrBlack , tcolor2 = BrBlack , tfeature = [Impenetrable] } doorlessWall = TileKind { tsymbol = '#' , tname = "granite wall" , tfreq = [("doorlessWallOver_#", 100)] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [] } pillar = TileKind { tsymbol = 'O' , tname = "rock" , tfreq = [ ("legendLit", 100), ("legendDark", 100) , ("skirmishSet", 5) ] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [] } wallCache = TileKind { tsymbol = '&' , tname = "cache" , tfreq = [ ("cachable", 30) , ("legendLit", 100), ("legendDark", 100) ] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [ Cause $ IK.CreateItem CGround "useful" IK.TimerNone , ChangeTo "cachable" ] } lampPost = TileKind { tsymbol = 'O' , tname = "lamp post" , tfreq = [("lampPostOver_O", 90)] , tcolor = BrYellow , tcolor2 = Brown , tfeature = [] } burningBush = TileKind { tsymbol = 'O' , tname = "burning bush" , tfreq = [("lampPostOver_O", 10), ("ambushSet", 3), ("battleSet", 2)] , tcolor = BrRed , tcolor2 = Red , tfeature = [] } bush = TileKind { tsymbol = 'O' , tname = "bush" , tfreq = [("ambushSet", 100) ] , tcolor = Green , tcolor2 = BrBlack , tfeature = [Dark] } tree = TileKind { tsymbol = 'O' , tname = "tree" , tfreq = [("skirmishSet", 14), ("battleSet", 20), ("treeShadeOver_O", 1)] , tcolor = BrGreen , tcolor2 = Green , tfeature = [] } wallSuspect = TileKind { tsymbol = '#' , tname = "moldy wall" , tfreq = [("suspect wall", 1)] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [Suspect, RevealAs "closed door"] } doorClosed = TileKind { tsymbol = '+' , tname = "closed door" , tfreq = [("legendLit", 100), ("legendDark", 100), ("closed door", 1)] , tcolor = Brown , tcolor2 = BrBlack , tfeature = [OpenTo "open door", HideAs "suspect wall"] } doorOpen = TileKind { tsymbol = '\'' , tname = "open door" , tfreq = [("legendLit", 100), ("legendDark", 100), ("open door", 1)] , tcolor = Brown , tcolor2 = BrBlack , tfeature = [Walkable, Clear, NoItem, NoActor, CloseTo "closed door"] } stairsUp = TileKind { tsymbol = '<' , tname = "staircase up" , tfreq = [] -- TODO: [("legendLit", 100), ("legendDark", 100)] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend 1] } stairsDown = TileKind { tsymbol = '>' , tname = "staircase down" , tfreq = [] -- TODO: [("legendLit", 100), ("legendDark", 100)] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend (-1)] } escapeUp = TileKind { tsymbol = '<' , tname = "airlock to the shuttle" , tfreq = [("legendLit", 100), ("legendDark", 100)] , tcolor = BrYellow , tcolor2 = BrYellow , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Escape 1] } escapeDown = TileKind { tsymbol = '>' , tname = "airlock to the shuttle" , tfreq = [("legendLit", 100), ("legendDark", 100)] , tcolor = BrYellow , tcolor2 = BrYellow , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Escape (-1)] } liftUp = TileKind { tsymbol = '<' , tname = "lift up" , tfreq = [("legendLit", 100), ("legendDark", 100)] , tcolor = BrCyan , tcolor2 = BrCyan , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend 1] } lift = TileKind { tsymbol = '<' , tname = "lift" , tfreq = [("legendLit", 100), ("legendDark", 100)] , tcolor = BrBlue , tcolor2 = BrBlue , tfeature = [ Walkable, Clear, NoItem, NoActor , Cause $ IK.Ascend 1 , Cause $ IK.Ascend (-1) ] } liftDown = TileKind { tsymbol = '>' , tname = "lift down" , tfreq = [("legendLit", 100), ("legendDark", 100)] , tcolor = BrCyan , tcolor2 = BrCyan , tfeature = [Walkable, Clear, NoItem, NoActor, Cause $ IK.Ascend (-1)] } unknown = TileKind { tsymbol = ' ' , tname = "unknown space" , tfreq = [("unknown space", 1)] , tcolor = defFG , tcolor2 = defFG , tfeature = [Dark] } floorCorridorLit = TileKind { tsymbol = '.' , tname = "floor" , tfreq = [ ("floorCorridorLit", 1), ("floorArenaLit", 1) , ("arenaSet", 1), ("emptySet", 1), ("noiseSet", 50) , ("battleSet", 1000), ("skirmishSet", 100) , ("ambushSet", 1000) ] , tcolor = BrWhite , tcolor2 = defFG , tfeature = [Walkable, Clear] } floorActorLit = floorCorridorLit { tfreq = [("floorActorLit", 1)] , tfeature = OftenActor : tfeature floorCorridorLit } floorItemLit = floorCorridorLit { tfreq = [] , tfeature = OftenItem : tfeature floorCorridorLit } floorActorItemLit = floorItemLit { tfreq = [("legendLit", 100)] , tfeature = OftenActor : tfeature floorItemLit } floorArenaShade = floorActorLit { tname = "floor" -- TODO: "shaded ground" , tfreq = [("treeShadeOver_s", 1)] , tcolor2 = BrBlack , tfeature = Dark : tfeature floorActorLit -- no OftenItem } floorRedLit = floorCorridorLit { tname = "emergency walkway" , tfreq = [("emergency walkway", 1), ("trailLit", 20)] , tcolor = BrRed , tcolor2 = Red , tfeature = Trail : tfeature floorCorridorLit } floorBlueLit = floorRedLit { tname = "transport route" , tfreq = [("trailLit", 100)] , tcolor = BrBlue , tcolor2 = Blue } floorGreenLit = floorRedLit { tname = "greenery trail" , tfreq = [("trailLit", 100)] , tcolor = BrGreen , tcolor2 = Green } makeDark :: TileKind -> TileKind makeDark k = let darkText :: GroupName TileKind -> GroupName TileKind darkText t = maybe t (toGroupName . (<> "Dark")) $ T.stripSuffix "Lit" $ tshow t darkFrequency = map (first darkText) $ tfreq k darkFeat (OpenTo t) = Just $ OpenTo $ darkText t darkFeat (CloseTo t) = Just $ CloseTo $ darkText t darkFeat (ChangeTo t) = Just $ ChangeTo $ darkText t darkFeat (HideAs t) = Just $ HideAs $ darkText t darkFeat (RevealAs t) = Just $ RevealAs $ darkText t darkFeat OftenItem = Nothing -- items not common in the dark darkFeat feat = Just feat in k { tfreq = darkFrequency , tfeature = Dark : mapMaybe darkFeat (tfeature k) } makeDarkColor :: TileKind -> TileKind makeDarkColor k = (makeDark k) { tcolor = BrYellow , tcolor2 = BrBlack } Allure-0.5.0.0/GameDefinition/Content/ItemKindTemporary.hs0000644000000000000000000000624512555263417021544 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Temporary aspect pseudo-item definitions. module Content.ItemKindTemporary ( temporaries ) where import Data.Text (Text) import Game.LambdaHack.Common.Color import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Flavour import Game.LambdaHack.Common.Misc import Game.LambdaHack.Common.Msg import Game.LambdaHack.Content.ItemKind temporaries :: [ItemKind] temporaries = [tmpStrengthened, tmpWeakened, tmpProtected, tmpVulnerable, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant] tmpStrengthened, tmpWeakened, tmpProtected, tmpVulnerable, tmpFast20, tmpSlow10, tmpFarSighted, tmpKeenSmelling, tmpDrunk, tmpRegenerating, tmpPoisoned, tmpSlow10Resistant, tmpPoisonResistant :: ItemKind -- The @name@ is be used in item description, so it should be an adjective -- describing the temporary set of aspects. tmpAs :: Text -> [Aspect Dice] -> ItemKind tmpAs name aspects = ItemKind { isymbol = '+' , iname = name , ifreq = [(toGroupName name, 1), ("temporary conditions", 1)] , iflavour = zipPlain [BrWhite] , icount = 1 , irarity = [(1, 1)] , iverbHit = "affect" , iweight = 0 , iaspects = [Periodic, Timeout 0] -- activates and vanishes soon, -- depending on initial timer setting ++ aspects , ieffects = let tmp = Temporary $ "be no longer" <+> name in [Recharging tmp, OnSmash tmp] , ifeature = [Identified] , idesc = "" , ikit = [] } tmpStrengthened = tmpAs "strengthened" [AddHurtMelee 20] tmpWeakened = tmpAs "weakened" [AddHurtMelee (-20)] tmpProtected = tmpAs "protected" [ AddArmorMelee 30 , AddArmorRanged 30 ] tmpVulnerable = tmpAs "painted red" [ AddArmorMelee (-30) , AddArmorRanged (-30) ] tmpFast20 = tmpAs "fast 20" [AddSpeed 20] tmpSlow10 = tmpAs "slow 10" [AddSpeed (-10)] tmpFarSighted = tmpAs "far-sighted" [AddSight 5] tmpKeenSmelling = tmpAs "keen-smelling" [AddSmell 2] tmpDrunk = tmpAs "drunk" [ AddHurtMelee 30 -- fury , AddArmorMelee (-20) , AddArmorRanged (-20) , AddSight (-7) ] tmpRegenerating = let tmp = tmpAs "regenerating" [] in tmp { icount = 7 + d 5 , ieffects = Recharging (RefillHP 1) : ieffects tmp } tmpPoisoned = let tmp = tmpAs "poisoned" [] in tmp { icount = 7 + d 5 , ieffects = Recharging (RefillHP (-1)) : ieffects tmp } tmpSlow10Resistant = let tmp = tmpAs "slow resistant" [] in tmp { icount = 7 + d 5 , ieffects = Recharging (DropItem COrgan "slow 10" True) : ieffects tmp } tmpPoisonResistant = let tmp = tmpAs "poison resistant" [] in tmp { icount = 7 + d 5 , ieffects = Recharging (DropItem COrgan "poisoned" True) : ieffects tmp } Allure-0.5.0.0/GameDefinition/Content/ModeKindPlayer.hs0000644000000000000000000001247612555263417021007 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | Basic players definitions. module Content.ModeKindPlayer ( playerHero, playerSoldier, playerSniper , playerAntiHero, playerAntiSniper, playerCivilian , playerMonster, playerMobileMonster, playerAntiMonster , playerAnimal, playerMobileAnimal , playerRobot, playerMobileRobot , playerHorror , hiHero, hiDweller, hiRaid ) where import Data.List import Game.LambdaHack.Common.Ability import Game.LambdaHack.Common.Dice import Game.LambdaHack.Common.Misc import Game.LambdaHack.Content.ModeKind playerHero, playerSoldier, playerSniper, playerAntiHero, playerAntiSniper, playerCivilian, playerMonster, playerMobileMonster, playerAntiMonster, playerAnimal, playerMobileAnimal, playerRobot, playerMobileRobot, playerHorror :: Player Dice playerHero = Player { fname = "Spacefarer Crew" , fgroup = "hero" , fskillsOther = meleeAdjacent , fcanEscape = True , fneverEmpty = True , fhiCondPoly = hiHero , fhasNumbers = True , fhasGender = True , ftactic = TExplore , fentryLevel = 3 , finitialActors = 3 , fleaderMode = LeaderUI $ AutoLeader False False , fhasUI = True } playerSoldier = playerHero { fname = "Armed Spacefarer Crew" , fgroup = "soldier" } playerSniper = playerHero { fname = "Sniper Adventurer Party" , fgroup = "sniper" } playerAntiHero = playerHero { fleaderMode = LeaderAI $ AutoLeader True False , fhasUI = False } playerAntiSniper = playerSniper { fleaderMode = LeaderAI $ AutoLeader True False , fhasUI = False } playerCivilian = Player { fname = "Civilian Crowd" , fgroup = "civilian" , fskillsOther = zeroSkills -- not coordinated by any leadership , fcanEscape = False , fneverEmpty = True , fhiCondPoly = hiDweller , fhasNumbers = False , fhasGender = True , ftactic = TPatrol , fentryLevel = 1 , finitialActors = d 2 + 1 , fleaderMode = LeaderNull -- unorganized , fhasUI = False } playerMonster = Player { fname = "Alien Hierarchy" , fgroup = "alien" , fskillsOther = zeroSkills , fcanEscape = False , fneverEmpty = False , fhiCondPoly = hiDweller , fhasNumbers = False , fhasGender = False , ftactic = TExplore , fentryLevel = 4 , finitialActors = 0 , fleaderMode = -- No point changing leader on level, since all move and they -- don't follow the leader. LeaderAI $ AutoLeader True True , fhasUI = False } playerMobileMonster = playerMonster playerAntiMonster = playerMonster { fhasUI = True , fleaderMode = LeaderUI $ AutoLeader True True } playerAnimal = Player { fname = "Animal Kingdom" , fgroup = "animal" , fskillsOther = zeroSkills , fcanEscape = False , fneverEmpty = False , fhiCondPoly = hiDweller , fhasNumbers = False , fhasGender = False , ftactic = TRoam -- can't pick up, so no point exploring , fentryLevel = 3 , finitialActors = 2 + d 2 -- many, because no spawning , fleaderMode = LeaderNull , fhasUI = False } playerMobileAnimal = playerAnimal { fgroup = "mobile animal" } playerRobot = Player { fname = "Robot Anarchy" , fgroup = "robot" , fskillsOther = zeroSkills , fcanEscape = False , fneverEmpty = False , fhiCondPoly = hiDweller , fhasNumbers = False , fhasGender = False , ftactic = TRoam -- TODO:TFollow -- coordinated via net, follow alien leader , fentryLevel = 3 , finitialActors = 2 + d 2 -- many, because no spawning , fleaderMode = LeaderNull , fhasUI = False } playerMobileRobot = playerRobot { fgroup = "mobile robot" } -- | A special player, for summoned actors that don't belong to any -- of the main players of a given game. E.g., animals summoned during -- a duel game between two hero players land in the horror faction. -- In every game, either all factions for which summoning items exist -- should be present or a horror player should be added to host them. -- Actors that can be summoned should have "horror" in their @ifreq@ set. playerHorror = Player { fname = "Horror Den" , fgroup = "horror" , fskillsOther = zeroSkills , fcanEscape = False , fneverEmpty = False , fhiCondPoly = [] , fhasNumbers = False , fhasGender = False , ftactic = TPatrol -- disoriented , fentryLevel = 4 , finitialActors = 0 , fleaderMode = LeaderNull , fhasUI = False } victoryOutcomes :: [Outcome] victoryOutcomes = [Conquer, Escape] hiHero, hiDweller, hiRaid :: HiCondPoly -- Heroes rejoice in loot. hiHero = [ ( [(HiLoot, 1)] , [minBound..maxBound] ) , ( [(HiConst, 1000), (HiLoss, -100)] , victoryOutcomes ) ] -- Spawners or skirmishers get no points from loot, but try to kill -- all opponents fast or at least hold up for long. hiDweller = [ ( [(HiConst, 1000)] -- no loot , victoryOutcomes ) , ( [(HiConst, 1000), (HiLoss, -10)] , victoryOutcomes ) , ( [(HiBlitz, -100)] , victoryOutcomes ) , ( [(HiSurvival, 100)] , [minBound..maxBound] \\ victoryOutcomes ) ] hiRaid = [ ( [(HiLoot, 1)] , [minBound..maxBound] ) , ( [(HiConst, 100)] , victoryOutcomes ) ] Allure-0.5.0.0/GameDefinition/Client/0000755000000000000000000000000012555263417015376 5ustar0000000000000000Allure-0.5.0.0/GameDefinition/Client/UI/0000755000000000000000000000000012555263417015713 5ustar0000000000000000Allure-0.5.0.0/GameDefinition/Client/UI/Content/0000755000000000000000000000000012555263417017325 5ustar0000000000000000Allure-0.5.0.0/GameDefinition/Client/UI/Content/KeyKind.hs0000644000000000000000000002311512555263417021221 0ustar0000000000000000-- Copyright (c) 2008--2011 Andres Loeh, 2010--2015 Mikolaj Konarski -- This file is a part of the computer game Allure of the Stars -- and is released under the terms of the GNU Affero General Public License. -- For license and copyright information, see the file LICENSE. -- -- | The default game key-command mapping to be used for UI. Can be overridden -- via macros in the config file. module Client.UI.Content.KeyKind ( standardKeys ) where import Control.Arrow (first) import qualified Game.LambdaHack.Client.Key as K import Game.LambdaHack.Client.UI.Content.KeyKind import Game.LambdaHack.Client.UI.HumanCmd import Game.LambdaHack.Common.Misc import qualified Game.LambdaHack.Content.ItemKind as IK import qualified Game.LambdaHack.Content.TileKind as TK standardKeys :: KeyKind standardKeys = KeyKind { rhumanCommands = map (first K.mkKM) -- All commands are defined here, except some movement and leader picking -- commands. All commands are shown on help screens except debug commands -- and macros with empty descriptions. -- The order below determines the order on the help screens. -- Remember to put commands that show information (e.g., enter targeting -- mode) first. -- Main Menu, which apart of these includes a few extra commands [ ("CTRL-x", ([CmdMenu], GameExit)) , ("CTRL-r", ([CmdMenu], GameRestart "raid")) , ("CTRL-k", ([CmdMenu], GameRestart "skirmish")) , ("CTRL-m", ([CmdMenu], GameRestart "ambush")) , ("CTRL-b", ([CmdMenu], GameRestart "battle")) , ("CTRL-c", ([CmdMenu], GameRestart "campaign")) , ("CTRL-i", ([CmdDebug], GameRestart "battle survival")) , ("CTRL-f", ([CmdDebug], GameRestart "safari")) , ("CTRL-u", ([CmdDebug], GameRestart "safari survival")) , ("CTRL-e", ([CmdDebug], GameRestart "defense")) , ("CTRL-d", ([CmdMenu], GameDifficultyCycle)) -- Movement and terrain alteration , ("less", ([CmdMove, CmdMinimal], TriggerTile [ TriggerFeature { verb = "ascend" , object = "a level" , feature = TK.Cause (IK.Ascend 1) } , TriggerFeature { verb = "escape" , object = "spaceship" , feature = TK.Cause (IK.Escape 1) } ])) , ("CTRL-less", ([CmdMove], TriggerTile [ TriggerFeature { verb = "ascend" , object = "10 levels" , feature = TK.Cause (IK.Ascend 10) } ])) , ("greater", ([CmdMove, CmdMinimal], TriggerTile [ TriggerFeature { verb = "descend" , object = "a level" , feature = TK.Cause (IK.Ascend (-1)) } , TriggerFeature { verb = "escape" , object = "spaceship" , feature = TK.Cause (IK.Escape (-1)) } ])) , ("CTRL-greater", ([CmdMove], TriggerTile [ TriggerFeature { verb = "descend" , object = "10 levels" , feature = TK.Cause (IK.Ascend (-10)) } ])) , ("semicolon", ( [CmdMove] , Macro "go to crosshair for 100 steps" ["CTRL-semicolon", "CTRL-period", "V"] )) , ("colon", ( [CmdMove] , Macro "run selected to crosshair for 100 steps" ["CTRL-colon", "CTRL-period", "V"] )) , ("x", ( [CmdMove] , Macro "explore the closest unknown spot" [ "CTRL-question" -- no semicolon , "CTRL-period", "V" ] )) , ("X", ( [CmdMove] , Macro "autoexplore 100 times" ["'", "CTRL-question", "CTRL-period", "'", "V"] )) , ("CTRL-X", ( [CmdMove] , Macro "autoexplore 25 times" ["'", "CTRL-question", "CTRL-period", "'", "CTRL-V"] )) , ("R", ([CmdMove], Macro "rest (wait 100 times)" ["KP_Begin", "V"])) , ("CTRL-R", ([CmdMove], Macro "rest (wait 25 times)" ["KP_Begin", "CTRL-V"])) , ("c", ([CmdMove, CmdMinimal], AlterDir [ AlterFeature { verb = "close" , object = "door" , feature = TK.CloseTo "closed door" } ])) -- Item use -- -- For later: -- ApplyItem {verb = "eat", object = "food", symbol = ','} -- ApplyItem {verb = "apply", object = "emitter", symbol = '_'} -- ApplyItem {verb = "use", object = "tool", symbol = '~'} -- , ("E", ([CmdItem, CmdMinimal], DescribeItem $ MStore CEqp)) , ("P", ([CmdItem], DescribeItem $ MStore CInv)) , ("S", ([CmdItem], DescribeItem $ MStore CSha)) , ("A", ([CmdItem], DescribeItem MOwned)) , ("G", ([CmdItem], DescribeItem $ MStore CGround)) , ("@", ([CmdItem], DescribeItem $ MStore COrgan)) , ("exclam", ([CmdItem], DescribeItem MStats)) , ("g", ([CmdItem, CmdMinimal], MoveItem [CGround] CEqp (Just "get") "items" True)) , ("d", ([CmdItem], MoveItem [CEqp, CInv, CSha] CGround Nothing "items" False)) , ("e", ([CmdItem], MoveItem [CGround, CInv, CSha] CEqp Nothing "items" False)) , ("p", ([CmdItem], MoveItem [CGround, CEqp, CSha] CInv Nothing "items into inventory" False)) , ("s", ([CmdItem], MoveItem [CGround, CInv, CEqp] CSha Nothing "and share items" False)) , ("a", ([CmdItem, CmdMinimal], Apply [ ApplyItem { verb = "apply" , object = "consumable" , symbol = ' ' } , ApplyItem { verb = "quaff" , object = "drink" , symbol = '!' } , ApplyItem { verb = "read" , object = "chip" , symbol = '?' } ])) , ("q", ([CmdItem], Apply [ApplyItem { verb = "quaff" , object = "drink" , symbol = '!' }])) , ("r", ([CmdItem], Apply [ApplyItem { verb = "read" , object = "chip" , symbol = '?' }])) , ("f", ([CmdItem, CmdMinimal], Project [ApplyItem { verb = "fling" , object = "projectile" , symbol = ' ' }])) , ("t", ([CmdItem], Project [ ApplyItem { verb = "throw" , object = "missile" , symbol = '}' } , ApplyItem { verb = "throw" , object = "missile" , symbol = '{' } ])) -- , ("z", ([CmdItem], Project [ApplyItem { verb = "zap" -- , object = "mechanism" -- , symbol = '-' }])) -- Targeting , ("KP_Multiply", ([CmdTgt], TgtEnemy)) , ("backslash", ([CmdTgt], Macro "" ["KP_Multiply"])) , ("KP_Divide", ([CmdTgt], TgtFloor)) , ("bar", ([CmdTgt], Macro "" ["KP_Divide"])) , ("plus", ([CmdTgt, CmdMinimal], EpsIncr True)) , ("minus", ([CmdTgt], EpsIncr False)) , ("CTRL-question", ([CmdTgt], CursorUnknown)) , ("CTRL-I", ([CmdTgt], CursorItem)) , ("CTRL-braceleft", ([CmdTgt], CursorStair True)) , ("CTRL-braceright", ([CmdTgt], CursorStair False)) , ("BackSpace", ([CmdTgt], TgtClear)) -- Automation , ("equal", ([CmdAuto], SelectActor)) , ("underscore", ([CmdAuto], SelectNone)) , ("v", ([CmdAuto], Repeat 1)) , ("V", ([CmdAuto], Repeat 100)) , ("CTRL-v", ([CmdAuto], Repeat 1000)) , ("CTRL-V", ([CmdAuto], Repeat 25)) , ("apostrophe", ([CmdAuto], Record)) , ("CTRL-T", ([CmdAuto], Tactic)) , ("CTRL-A", ([CmdAuto], Automate)) -- Assorted , ("question", ([CmdMeta], Help)) , ("D", ([CmdMeta, CmdMinimal], History)) , ("T", ([CmdMeta, CmdMinimal], MarkSuspect)) , ("Z", ([CmdMeta], MarkVision)) , ("C", ([CmdMeta], MarkSmell)) , ("Tab", ([CmdMeta], MemberCycle)) , ("ISO_Left_Tab", ([CmdMeta, CmdMinimal], MemberBack)) , ("space", ([CmdMeta], Clear)) , ("Escape", ([CmdMeta, CmdMinimal], Cancel)) , ("Return", ([CmdMeta, CmdTgt], Accept)) -- Mouse , ("LeftButtonPress", ([CmdMouse], macroLeftButtonPress)) , ("SHIFT-LeftButtonPress", ([CmdMouse], macroShiftLeftButtonPress)) , ("MiddleButtonPress", ([CmdMouse], CursorPointerEnemy)) , ("SHIFT-MiddleButtonPress", ([CmdMouse], CursorPointerFloor)) , ("CTRL-MiddleButtonPress", ([CmdInternal], Macro "" ["SHIFT-MiddleButtonPress"])) , ("RightButtonPress", ([CmdMouse], TgtPointerEnemy)) -- Debug and others not to display in help screens , ("CTRL-S", ([CmdDebug], GameSave)) , ("CTRL-semicolon", ([CmdInternal], MoveOnceToCursor)) , ("CTRL-colon", ([CmdInternal], RunOnceToCursor)) , ("CTRL-period", ([CmdInternal], ContinueToCursor)) , ("CTRL-comma", ([CmdInternal], RunOnceAhead)) , ("CTRL-LeftButtonPress", ([CmdInternal], Macro "" ["SHIFT-LeftButtonPress"])) , ("CTRL-MiddleButtonPress", ([CmdInternal], Macro "" ["SHIFT-MiddleButtonPress"])) , ("ALT-space", ([CmdInternal], StopIfTgtMode)) , ("ALT-minus", ([CmdInternal], SelectWithPointer)) ] } Allure-0.5.0.0/test/0000755000000000000000000000000012555263417012255 5ustar0000000000000000Allure-0.5.0.0/test/test.hs0000644000000000000000000000106412555263417013571 0ustar0000000000000000import TieKnot main :: IO () main = tieKnot $ tail $ words "dist/build/LambdaHack/LambdaHack --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 6 --automateAll --keepAutomated --gameMode campaign --setDungeonRng 42 --setMainRng 42" -- tieKnot $ tail $ words "dist/build/LambdaHack/LambdaHack --dbgMsgSer --savePrefix test --newGame 2 --noDelay --noAnim --maxFps 100000 --frontendNull --benchmark --stopAfter 6 --automateAll --keepAutomated --gameMode battle --setDungeonRng 42 --setMainRng 42"