diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index e49f673..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,15 +0,0 @@
-# Object files:
-*.o
-
-# Binaries:
-SilverMUDClient
-SilverMUDServer
-SilverMUDClientDebug
-SilverMUDServerDebug
-
-# Profiling Artifacts:
-gmon.out
-
-# LSP whatnot:
-.cache
-compile_commands.json
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index be3f7b2..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,661 +0,0 @@
- 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
-.
diff --git a/Makefile b/Makefile
deleted file mode 100644
index c3323ca..0000000
--- a/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-# Compiler and linker flags needed to link to the needed libraries:
-CFLAGS = `pkg-config --cflags guile-3.0`
-LDFLAGS= -lpthread -lncurses -lgnutls `pkg-config --libs guile-3.0`
-
-# Files needed to compile the client:
-clientsrc = $(wildcard src/*.c) src/client/SilverMUDClient.c
-clientobj = $(clientsrc:.c=.o)
-
-# Files needed to compile the server:
-serversrc = $(wildcard src/*.c) src/server/SilverMUDServer.c
-serverobj = $(serversrc:.c=.o)
-
-# Default target: Compile the client and server with aggressive optimizations and a big stack of warnings:
-all: CFLAGS += -Wall -Wextra -Ofast
-all: SilverMUDClient SilverMUDServer
-
-
-# Debug target: Compile the client and server with profiling, debug information, debug optimization, and the
-# preprocessor flag "debug" set.
-debug: CFLAGS += -Wall -Wextra -pg -ggdb -Og -D debug
-debug: SilverMUDClientDebug SilverMUDServerDebug
-
-SilverMUDClient: $(clientobj)
- cc $^ $(LDFLAGS) -o $@
-
-SilverMUDServer: $(serverobj)
- cc $^ $(LDFLAGS) -o $@
-
-SilverMUDClientDebug: $(clientobj)
- cc -pg $^ $(LDFLAGS) -o $@
-
-SilverMUDServerDebug: $(serverobj)
- cc -pg $^ $(LDFLAGS) -o $@
-
-# Start from a clean slate:
-.PHONY: clean
-clean:
- rm -f $(clientobj) $(serverobj) SilverMUDClient SilverMUDServer SilverMUDClientDebug SilverMUDServerDebug gmon.out
-
diff --git a/README.org b/README.org
deleted file mode 100644
index a22c9a8..0000000
--- a/README.org
+++ /dev/null
@@ -1,111 +0,0 @@
-#+LATEX_HEADER: \RequirePackage[left=0.3in,top=0.3in,right=0.3in,bottom=0.3in, a4paper]{geometry}
-* SilverMUD: The Hackable Terminal-Top Roleplaying Game.
-SilverMUD is a tool for creating engaging and communal stories, all over the
-world through the internet. It's designed to give a gamemaster the same power
-to improvise that they have at the table, through simple programming and
-easy-to-understand structures.
-
-* Player's Guide
-** Running The Client
-*** How To Connect To A Server:
-#+begin_example
-SilverMUDClient -i
-#+end_example
-To connect to a server, use the command-line option =-i=, and the IP address of
-the server
-#+begin_example
-SilverMUDClient -i -p
-#+end_example
-If the server admin is hosting the server on a port other than the
-default port of 5000, you can use the =-p= option with the number of the port.
-
-If the connection is successful, you will be placed in the server's login
-area. Type =/join =, where player name is a name of your choosing,
-and you will be placed in the spawn area, ready to play.
-
-*** Other Launch Options:
-
-** The Basic Commands
-SilverMUD is played through a set of very simple commands. To use a command,
-type a forward-slash (/) followed immediately by the command name. The command
-can be upper or lower-case.
-
-| Command | Arguments | Effect |
-|---------+------------------------------------------+---------------------------------------------------------|
-| JOIN | Character Name | Logs you into the server with the given character name. |
-| MOVE | Path Name/Path Number | Moves you down the given path. |
-| LOOK | None | Describes the current area. |
-| STAT | None | Displays your current status and character sheet. |
-| SPEC | Core Stat Name | Allows you to apply spec points to a given stat. |
-| TRY | Core Stat Name/Skill Name, Object Number | Attempt to use the given stat or skill on the object. |
-| TALK | Character Name | Begins a conversation with another player. |
-| SHOUT | None | Messages the current area, ignoring any conversations. |
-
-* Gamemaster's Guide
-** Running the Server:
-
-* Developer's Guide
-** Build Prerequisites:
-SilverMUD has the following dependencies:
-- GnuTLS
-- ncurses
-- GNU Guile
-
-** C Style Guide:
-These rules attempt to make the program as visually clear as possible, while
-some rules may be made based on my own personal tastes.
-
-For the purposes of this guide, we will use this terminology:
-- () :: These are parentheses.
-- [] :: These are brackets.
-- {} :: These are braces.
-
-*** Formatting:
-**** Casing:
-- Variables :: Variables should be in camelCase, with the exception being
- variables used to store SCM values, in which case, they should in be
- snake_case.
-
-- Types :: User defined types should be in PascalCase.
-
-**** Control Statements:
-- A space should be between the keyword and the condition. This is to make
- control statements visually distinct from function calls.
-
-- Opening braces should be on the line after the control statement, and closing
- braces on the line after the last statement, on it's own. This is to make the
- scope of the control statement easily identifiable.
-
-- else and else if should always be on a new line, not the same line as an if
- statement's closing brace. This is to more easily distinguish the seperate
- blocks.
-
-- Control statements should never omit braces and do single statements. This is
- mostly personal preference, but I do think it makes things more clear.
-
-*** Naming:
-**** Rule 0: NEVER USE i AND j!
-Never use the variable names i and j. These are easy to confuse, and often make
-nested loops awful to read. Name these more descriptively.
-For example:
-- If you are using a variable to index an array, name the variable index.
-- If you are indexing multiple arrays, name it "array name + Index".
-- If you are using it to count something, call it count, or "name of the
- thing you are counting + count".
-
-**** Rule 1: No one letter variable names, unless in a mathematical function.
-You should never use one letter variable names. They're needlessly obtuse and
-you will not remember their meaning upon re-reading of the source code. The
-exception to this is when you are writing a function which replicates a
-mathematical formula or function with commonly accepted notation. However, you
-should consider if it would be better to break mathematical convention for
-clarity inside the program, such as when the variable names are the first letter
-of a word or the mathematical notation uses many similar looking variables.
-
-**** Rule 2: Prefer to use full words in variable and function names:
-You should always prefer to use full words in variable and function names. It
-makes the source code much easier to read, like a sentence. Ideally, if you want
-to shorten the name, use synonyms or rephrasing before you resort to removing
-letters.
-
-*** Comments:
diff --git a/scheme/basic-functions.scm b/scheme/basic-functions.scm
deleted file mode 100644
index 74923d3..0000000
--- a/scheme/basic-functions.scm
+++ /dev/null
@@ -1,9 +0,0 @@
-(define (create-two-way-path from-path-description to-path-description from-area to-area arealist)
- (begin
- (create-path from-path-description from-area to-area arealist)
- (create-path to-path-description to-area from-area arealist)))
-
-;; Send a quick message to everyone in the game as the server:
-(define (shout message)
- "Send a quick message to everyone in the game as the server."
- (message-everyone "SERVER" message output-queue))
diff --git a/src/areadata.c b/src/areadata.c
deleted file mode 100644
index 50a61b9..0000000
--- a/src/areadata.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// areadata.c: Implements functions for playerAreas and playerPaths in SilverMUD:
-// Barra Ó Catháin, 2022.
-#include
-#include "areadata.h"
-#include "playerdata.h"
-#include "linkedlist.h"
-
-// ====================
-// -=[ Area/Paths: ]=-:
-// ====================
-
-// Create an area given a name and description:
-playerArea * createArea(char * nameString, char * descriptionString)
-{
- // Allocate and zero memory for the new area:
- playerArea * createdArea = calloc(1, sizeof(playerArea));
-
- // Copy the strings into the newly created area:
- strncpy(createdArea->areaName, nameString, 32 - 1);
- strncpy(createdArea->areaDescription, descriptionString, MAX - 36);
-
- // Properly null-terminate the strings:
- createdArea->areaName[31] = '\0';
- createdArea->areaDescription[MAX - 36] = '\0';
-
- // Create a list for the paths in the area:
- createdArea->pathList = createList(PATH);
-
- // Return the pointer:
- return createdArea;
-}
-
-// Create a path between two areas given two areas and two strings:
-int createPath(playerArea * fromArea, playerArea * toArea, char * fromDescription, char * toDescription)
-{
- // Allocate the new paths:
- playerPath * fromPath = malloc(sizeof(playerPath));
- playerPath * toPath = malloc(sizeof(playerPath));
-
- // Setup the from path:
- strncpy(fromPath->pathName, fromDescription, 32 - 1);
- fromPath->pathName[31] = '\0';
- fromPath->areaToJoin = toArea;
-
- // Setup the to path:
- strncpy(toPath->pathName, toDescription, 32 - 1);
- toPath->pathName[31] = '\0';
- toPath->areaToJoin = fromArea;
-
- // Add to the lists:
- addToList(fromArea->pathList, fromPath, PATH);
- addToList(toArea->pathList, toPath, PATH);
-
- return 0;
-}
-
-// Create a one-way path between two areas given two areas and a string:
-int createOneWayPath(playerArea * fromArea, playerArea * toArea, char * description)
-{
- // Allocate the new paths:
- playerPath * path = calloc(1, sizeof(playerPath));
-
- // Setup the path:
- strncpy(path->pathName, description, 32 - 1);
- path->pathName[31] = '\0';
- path->areaToJoin = toArea;
-
- // Add to the list:
- addToList(fromArea->pathList, path, PATH);
-
- return 0;
-}
diff --git a/src/areadata.h b/src/areadata.h
deleted file mode 100644
index ef58b36..0000000
--- a/src/areadata.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// areadata.h: Contains data structures and functions for playerAreas and playerPaths in SilverMUD:
-// Barra Ó Catháin, 2022.
-#ifndef AREADATA_H
-#define AREADATA_H
-#include "constants.h"
-
-// ====================
-// -=[ Area/Paths: ]=-:
-// ====================
-
-// Let the compiler know that we're going to define these types:
-typedef struct playerPath playerPath;
-typedef struct playerArea playerArea;
-typedef struct list list;
-
-// A path, which contains a name, and a pointer to the area which the player will travel to:
-struct playerPath
-{
- char pathName[32];
- playerArea * areaToJoin;
-};
-
-// An area, containing a list of paths exiting from the area, and a name and description of the area:
-struct playerArea
-{
- list * pathList;
- char areaName[32];
- char areaDescription[MAX - 35];
-};
-
-// Create an area given a name and description, returning a pointer to the new area:
-playerArea * createArea(char * nameString, char * descriptionString);
-
-// Create a path between two areas given two areas and two strings, adding it to the both area's list of paths:
-int createPath(playerArea * fromArea, playerArea * toArea, char * fromDescription, char * toDescription);
-
-// Create a one-way path between two areas given two areas and a string, adding it to the first area's list of paths:
-int createOneWayPath(playerArea * fromArea, playerArea * toArea, char * description);
-
-// TO BE IMPLEMENTED:
-/* int saveAreaList(areaNode * listToSave); */
-
-/* int savePathList(pathNode * listToSave); */
-
-/* int loadAreaList(areaNode * listToLoad); */
-
-/* int loadPathList(pathNode * listToLoad); */
-
-#endif
diff --git a/src/client/SilverMUDClient.c b/src/client/SilverMUDClient.c
deleted file mode 100644
index c2cf663..0000000
--- a/src/client/SilverMUDClient.c
+++ /dev/null
@@ -1,382 +0,0 @@
-// Silverkin Industries Comm-Link Client, Public Demonstration Sample Alpha 0.5.
-// PROJECT CODENAME: WHAT DO I PAY YOU FOR? | Level-3 Clearance.
-// Barry Kane, 2021
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "../queue.h"
-#include "../constants.h"
-#include "../playerdata.h"
-#include "../texteffects.h"
-#include "../inputoutput.h"
-
-// A struct for bundling all needed parameters for a thread so we can pass them using a void pointer:
-typedef struct threadparameters
-{
- gnutls_session_t tlsSession;
- FILE * loggingStream;
- bool loggingFlag;
- WINDOW * window;
- int characterDelay;
- char * prompt;
-} threadparameters;
-
-// Use sockaddr as a type:
-typedef struct sockaddr sockaddr;
-
-// A globally available exit boolean:
-bool shouldExit = false;
-
-// A function for managing the sending thread:
-void * messageSender(void * parameters)
-{
- threadparameters * threadParameters = parameters;
- gnutls_session_t tlsSession = threadParameters->tlsSession;
- FILE * loggingStream = threadParameters->loggingStream;
- bool loggingFlag = threadParameters->loggingFlag;
- WINDOW * window = threadParameters->window;
- char * prompt = threadParameters->prompt;
- userMessage sendBuffer;
-
- // Repeatedly get input from the user, place it in a userMessage, and send it to the server:
- while (!shouldExit)
- {
- usleep(200000);
- // Clear the window:
- waddstr(window, "\n\n\n");
-
- // Print the prompt:
- waddstr(window, prompt);
-
- if (wgetnstr(window, sendBuffer.messageContent, MAX) == ERR)
- {
- // Quit if there's any funny business with getting input:
- pthread_exit(NULL);
- }
-
- // Ignore empty messages:
- if (sendBuffer.messageContent[0] == '\n')
- {
- continue;
- }
-
- // Send the message to the log if logging is enabled:
- if (loggingFlag == true)
- {
- fputs(sendBuffer.messageContent, loggingStream);
- fputs("\n", loggingStream);
- fflush(loggingStream);
- }
-
- // Send the message off to the server:
- messageSend(tlsSession, &sendBuffer);
- memset(&sendBuffer, 0, sizeof(char) * MAX);
- }
-
- // Rejoin the main thread:
- pthread_exit(NULL);
-}
-
-// A function for managing the receiving thread:
-void * messageReceiver(void * parameters)
-{
- threadparameters * threadParameters = parameters;
- gnutls_session_t tlsSession = threadParameters->tlsSession;
- FILE * loggingStream = threadParameters->loggingStream;
- int characterDelay = threadParameters->characterDelay;
- bool loggingFlag = threadParameters->loggingFlag;
- WINDOW * window = threadParameters->window;
-
- int returnValue = 0;
- userMessage receiveBuffer;
- bool serverMessage = false;
- int screenWidth = getmaxx(threadParameters->window);
-
- // Repeatedly take messages from the server and print them to the chat log window:
- while (!shouldExit)
- {
- // Get the next message:
- returnValue = messageReceive(tlsSession, &receiveBuffer);
-
- // Check we haven't been disconnected:
- if (returnValue == -10 || returnValue == 0)
- {
- shouldExit = true;
- }
-
- // Check if it's a server message:
- else if (receiveBuffer.senderName[0] == '\0')
- {
- // Check if the server wants to change the prompt:
- if (receiveBuffer.senderName[1] != '\0')
- {
- strncpy(threadParameters->prompt, &receiveBuffer.senderName[1], 63);
- threadParameters->prompt[63] = '\0';
- }
-
- // Check if it's a command to disconnect:
- if (receiveBuffer.messageContent[0] == '\0')
- {
- shouldExit = true;
- pthread_exit(NULL);
- }
-
- // Fit the string to the screen:
- wrapString(receiveBuffer.messageContent, strlen(receiveBuffer.messageContent) - 1, screenWidth);
-
- // If it's the first server message in a block, begin a block of server messages:
- if (serverMessage == false)
- {
- slowPrintNcurses("\n --====<>====--", characterDelay, window, true);
- serverMessage = true;
- }
-
- // Print the message:
- slowPrintNcurses("\n", characterDelay, window, true);
- slowPrintNcurses(receiveBuffer.messageContent, characterDelay,
- window, false);
- slowPrintNcurses("\n", characterDelay, window, true);
- }
- // It's a user message:
- else
- {
- // Fit the string to the screen:
- wrapString(receiveBuffer.messageContent, strlen(receiveBuffer.messageContent) - 1,
- screenWidth - strlen(receiveBuffer.senderName) - 2);
-
- // If the user has requested logging, insert the message into the file:
- if (loggingFlag == true)
- {
- fputs(receiveBuffer.senderName, loggingStream);
- fputs(": ", loggingStream);
- fputs(receiveBuffer.messageContent, loggingStream);
- fflush(loggingStream);
- }
-
- // If we're in a block of server messages, end it:
- if (serverMessage == true)
- {
- slowPrintNcurses("\n --====<>====-- \n", characterDelay, window, true);
- serverMessage = false;
- }
-
- // Print the message:
- slowPrintNcurses(receiveBuffer.senderName, characterDelay, window, true);
- slowPrintNcurses(": ", characterDelay, window, true);
- slowPrintNcurses(receiveBuffer.messageContent, characterDelay, window, false);
- }
- }
- // Exit the thread if shouldExit is true:
- pthread_exit(NULL);
-}
-
-int main(int argc, char ** argv)
-{
- int socketFileDesc;
- struct sockaddr_in serverAddress;
- pthread_t sendingThread;
- pthread_t receivingThread;
- int port = 5000;
- int currentopt = 0;
- int characterDelay = 4000;
- char chatLogPath[PATH_MAX + 1];
- char gameLogPath[PATH_MAX + 1];
- char ipAddress[32] = "127.0.0.1";
- FILE * chatLog = NULL, * gameLog = NULL;
- bool chatLogging = false, gameLogging = false;
-
- // Print welcome message:
- slowPrint("\n--==== \033[33;40mSILVERKIN INDUSTRIES\033[0m COMM-LINK CLIENT ====--\nVersion Alpha 0.5\n", 5000);
-
- // Parse command-line options:
- while ((currentopt = getopt(argc, argv, "i:c:g:p:d:")) != -1)
- {
- switch (currentopt)
- {
- case 'i':
- {
- memcpy(ipAddress, optarg, 32);
- break;
- }
- case 'c':
- {
- memcpy(chatLogPath, optarg, PATH_MAX + 1);
- chatLog = fopen(chatLogPath, "a+");
- if (chatLog == NULL)
- {
- chatLogging = false;
- }
- else
- {
- chatLogging = true;
- }
- break;
- }
- case 'g':
- {
- memcpy(gameLogPath, optarg, PATH_MAX + 1);
- gameLog = fopen(gameLogPath, "a+");
- if (gameLog == NULL)
- {
- gameLogging = false;
- }
- else
- {
- gameLogging = true;
- }
- break;
- }
- case 'p':
- {
- port = atoi(optarg);
- break;
- }
- case 'd':
- {
- characterDelay = atoi(optarg);
- break;
- }
- case '?':
- {
- return 1;
- break;
- }
- }
- }
-
- // Give me a socket, and make sure it's working:
- socketFileDesc = socket(AF_INET, SOCK_STREAM, 0);
- if (socketFileDesc == -1)
- {
- printf("Socket creation failed.\n");
- exit(EXIT_FAILURE);
- }
- else
- {
- slowPrint("Socket successfully created.\n", characterDelay);
- }
-
- // Set our IP address and port. Default to localhost for testing:
- serverAddress.sin_family = AF_INET;
- serverAddress.sin_addr.s_addr = inet_addr(ipAddress);
- serverAddress.sin_port = htons(port);
-
- // Connect the server and client sockets, Kronk:
- if (connect(socketFileDesc, (sockaddr*)&serverAddress, sizeof(serverAddress)) != 0)
- {
- slowPrint("Connection with the Silverkin Industries Comm-Link Server Failed:\nPlease contact your service representative.\n", characterDelay);
- exit(0);
- }
-
- // Setup a GnuTLS session and initialize it:
- gnutls_session_t tlsSession = NULL;
- if (gnutls_init(&tlsSession, GNUTLS_CLIENT) < 0)
- {
- exit(EXIT_FAILURE);
- }
-
- // Setup the private credentials for our GnuTLS session:
- gnutls_anon_client_credentials_t clientkey = NULL;
- gnutls_anon_allocate_client_credentials(&clientkey);
- gnutls_credentials_set(tlsSession, GNUTLS_CRD_ANON, &clientkey);
-
- // Bind the open socket to the TLS session:
- gnutls_transport_set_int(tlsSession, socketFileDesc);
- gnutls_priority_set_direct(tlsSession, "PERFORMANCE:+ANON-ECDH:+ANON-DH", NULL);
-
- // Use the default for the GnuTLS handshake timeout:
- gnutls_handshake_set_timeout(tlsSession, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
-
- // Repeatedly attempt to handshake unless we encounter a fatal error:
- int returnValue = -1;
- do
- {
- returnValue = gnutls_handshake(tlsSession);
- }
- while (returnValue < 0 && gnutls_error_is_fatal(returnValue) == 0);
-
- // Setup Ncurses:
- initscr();
-
- // Create two pointers to structs to pass arguments to the threads:
- threadparameters * logArea;
- threadparameters * messageArea;
-
- logArea = malloc(sizeof(*logArea));
- messageArea = malloc(sizeof(*messageArea));
-
- // Make the windows for the structs, and pass the socket descriptor:
- logArea->window = newwin(LINES - 5, COLS - 2, 1, 1);
- logArea->tlsSession = tlsSession;
- logArea->loggingFlag = chatLogging;
- logArea->characterDelay = characterDelay;
-
- if (chatLog != NULL)
- {
- logArea->loggingStream = chatLog;
- }
- messageArea->window = newwin(3, COLS - 2, LINES - 4, 1);
- messageArea->tlsSession = tlsSession;
- messageArea->loggingFlag = gameLogging;
-
- // Set the appropriate log pointers:
- if (gameLog != NULL)
- {
- messageArea->loggingStream = gameLog;
- }
-
- // Set up the string to hold the current "prompt" that the server has sent:
- messageArea->prompt = calloc(32, sizeof(char));
- strcpy(messageArea->prompt, " Login > ");
- logArea->prompt = messageArea->prompt;
-
- // Set the two windows to scroll:
- scrollok(logArea->window, true);
- scrollok(messageArea->window, true);
-
- // Run a thread to send messages, and use another to recieve:
- pthread_create(&sendingThread, NULL, messageSender, messageArea);
- pthread_create(&receivingThread, NULL, messageReceiver, logArea);
-
- // Wait for /EXIT:
- pthread_join(receivingThread, NULL);
-
- // Close the threads:
- pthread_cancel(sendingThread);
-
- // Close the session and socket:
- gnutls_bye(tlsSession, GNUTLS_SHUT_WR);
- close(socketFileDesc);
-
- // Free the structs:
- free(logArea);
- free(messageArea);
-
- // Close the log files:
- if (gameLog != NULL)
- {
- fclose(gameLog);
- }
- if (chatLog != NULL)
- {
- fclose(chatLog);
- }
-
- // Unsetup Ncurses:
- endwin();
-
- // Say goodbye:
- slowPrint("\nThank you for choosing Silverkin Industries, valued customer!\n", characterDelay);
-}
-
diff --git a/src/constants.h b/src/constants.h
deleted file mode 100644
index bb598d8..0000000
--- a/src/constants.h
+++ /dev/null
@@ -1,9 +0,0 @@
-// Constants.h: Contains configurable constants for SilverMUD.
-// Barry Kane, 2022.
-#ifndef CONSTANTS_H
-#define CONSTANTS_H
-#define PORT 5000
-#define MAX 2048
-#define PLAYERCOUNT 64
-#define MAXQUEUELENGTH 2048
-#endif
diff --git a/src/gamelogic.c b/src/gamelogic.c
deleted file mode 100644
index 3195147..0000000
--- a/src/gamelogic.c
+++ /dev/null
@@ -1,968 +0,0 @@
-// gamelogic.c: Contains function definitons for dealing with the game's logic.
-// Barry Kane, 2022.
-#include
-#include
-#include
-#include
-#include
-#include
-#include "queue.h"
-#include "constants.h"
-#include "gamelogic.h"
-#include "playerdata.h"
-#include "linkedlist.h"
-#include "inputoutput.h"
-
-// =======================
-// -=[ Main Game Loop ]=-:
-// =======================
-
-// Thread function which runs the main game loop, given the needed parameters:
-void * gameLogicHandler(void * parameters)
-{
- gameLogicParameters * threadParameters = parameters;
- inputMessage * currentInput = NULL;
- queue * commandQueue = createQueue();
- scm_init_guile();
- while (true)
- {
- // Evaluate remaining commands:
- while (commandQueue->itemCount != 0)
- {
- evaluateNextCommand(threadParameters, commandQueue);
- }
-
- // Wait if there is nothing to do:
- if (threadParameters->inputQueue->itemCount == 0)
- {
- pthread_cond_wait(&threadParameters->inputQueue->condition, &threadParameters->inputQueue->mutex);
- }
-
- // Check for new messages and pop them off the queue:
- if (threadParameters->inputQueue->itemCount != 0)
- {
- while (threadParameters->inputQueue->lock == true);
- threadParameters->inputQueue->lock = true;
- currentInput = peekQueue(threadParameters->inputQueue)->data.inputMessage;
- userInputSanatize(currentInput->content->messageContent, MAX);
- // A slash as the first character means the message is a user command:
- if (currentInput->content->messageContent[0] == '/')
- {
- queueMessagedCommand(commandQueue, currentInput);
- }
-
- else if (!(currentInput->sender->currentArea == getFromList(threadParameters->areaList, 0)->area) &&
- currentInput->content->messageContent[0] != '\n')
- {
- // Copy the correct name into the sender name field:
- strncpy(currentInput->content->senderName, currentInput->sender->playerName, 32);
- currentInput->content->senderName[31] = '\0';
-
- if(currentInput->sender->talkingWith == NULL)
- {
- // Allocate an array of playerInfo to store the current players in the area for the output message:
- playerInfo ** recipients = calloc(PLAYERCOUNT, sizeof(playerInfo*));
-
- // Initialize them all to NULL:
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- recipients[index] = NULL;
- }
-
- // Get the players in the current area and add them to our array:
- int recipientIndex = 0;
- for (int playerIndex = 0; playerIndex < *threadParameters->playerCount; playerIndex++)
- {
- if (threadParameters->connectedPlayers[playerIndex].currentArea == currentInput->sender->currentArea)
- {
- recipients[recipientIndex] = &threadParameters->connectedPlayers[playerIndex];
- recipientIndex++;
- }
- }
-
- // Create the outputMessage for the queue:
- outputMessage * newOutputMessage = createTargetedOutputMessage(currentInput->content, recipients, recipientIndex);
-
- // Push the message onto the queue:
- pushQueue(threadParameters->outputQueue, newOutputMessage, OUTPUT_MESSAGE);
-
- // Free the array;
- free(recipients);
- }
- else
- {
- // Allocate an array of two playerInfo to store the pointers to the players in the conversation:
- playerInfo ** recipients = calloc(2, (sizeof(playerInfo*)));
-
- // Find which player is first in the player list:
- bool senderIsFirst = false;
-
- for(int playerIndex = 0; playerIndex < *threadParameters->playerCount; playerIndex++)
- {
- if(&threadParameters->connectedPlayers[playerIndex] == currentInput->sender)
- {
- senderIsFirst = true;
- break;
- }
- if(&threadParameters->connectedPlayers[playerIndex] == currentInput->sender->talkingWith)
- {
- senderIsFirst = false;
- break;
- }
- }
-
- // Set the proper recipients:
- recipients[0] = (senderIsFirst) ? currentInput->sender : currentInput->sender->talkingWith;
- recipients[1] = (senderIsFirst) ? currentInput->sender->talkingWith : currentInput->sender;
-
- // There's only one recipient:
- int recipientIndex = 2;
-
- // Create the outputMessage for the queue:
- outputMessage * newOutputMessage = createTargetedOutputMessage(currentInput->content, recipients, recipientIndex);
-
- // Push the message onto the queue:
- pushQueue(threadParameters->outputQueue, newOutputMessage, OUTPUT_MESSAGE);
-
- // Free the array;
- free(recipients);
- }
- }
- memset(currentInput, 0, sizeof(inputMessage));
- currentInput = NULL;
- threadParameters->inputQueue->lock = false;
- popQueue(threadParameters->inputQueue);
- }
- }
- pthread_exit(NULL);
-}
-
-// Evaluate the next commandEvent in a queue:
-void queueMessagedCommand(queue * queue, inputMessage * messageToQueue)
-{
- // Prepare the new commandEvent:
- commandEvent * newCommand = calloc(1, sizeof(commandEvent));
- newCommand->command = calloc(16, sizeof(char));
- newCommand->arguments = calloc(MAX, sizeof(char));
- newCommand->caller = messageToQueue->sender;
-
- // Seperate the command from it's arguments:
- strtok(messageToQueue->content->messageContent, " ");
-
- // Copy the command and arguments to the new commandEvent:
- memcpy(newCommand->command, &messageToQueue->content->messageContent[1], 16);
- memcpy(newCommand->arguments, &messageToQueue->content->messageContent[strlen(newCommand->command) + 2],
- MAX - (strlen(newCommand->command) + 2));
-
-
- // Ensure the arguments are safe to parse, without adding newlines:
- userNameSanatize(newCommand->command, 16);
- newCommand->command[15] = '\0';
-
- userNameSanatize(newCommand->arguments, MAX);
- newCommand->arguments[MAX - 1] = '\0';
-
- // Lowercase the command for easier comparison:
- for (char * character = newCommand->command; *character; ++character)
- {
- *character = tolower(*character);
- }
-
- pushQueue(queue, newCommand, COMMAND);
-}
-
-// Enqueue a command to a queue:
-void queueCommand(queue * queue, char * command, char * arguments, int commandLength, int argumentsLength,
- playerInfo * callingPlayer)
-{
- // Prepare the new commandEvent:
- commandEvent * newCommand = calloc(1, sizeof(commandEvent));
- newCommand->command = calloc(16, sizeof(char));
- newCommand->arguments = calloc(MAX, sizeof(char));
- newCommand->caller = callingPlayer;
-
- // Copy the command and arguments:
- strncpy(newCommand->command, command, commandLength);
- if (argumentsLength > 0)
- {
- strncpy(newCommand->arguments, arguments, argumentsLength);
- }
- // Ensure the arguments are safe to parse, without adding newlines:
- userNameSanatize(newCommand->command, 16);
-
- pushQueue(queue, newCommand, COMMAND);
-}
-
-// Evaluate the next commandEvent in a queue:
-int evaluateNextCommand(gameLogicParameters * parameters, queue * queue)
-{
- commandEvent * currentCommand = peekQueue(queue)->data.command;
- while (queue->lock);
- queue->lock = true;
- if (currentCommand == NULL)
- {
- return -1;
- }
-
- // Switch to the relevant command based on the hash:
- switch (hashCommand(currentCommand->command, strlen(currentCommand->command)))
- {
- // Look command: Returns the description of the current area and paths:
- case 5626697:
- {
- char formattedString[64];
- userMessage * lookMessage = calloc(1, sizeof(userMessage));
- lookMessage->senderName[0] = '\0';
- strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaName, 33);
- strncat(lookMessage->messageContent, "\n", 2);
- strncat(lookMessage->messageContent, currentCommand->caller->currentArea->areaDescription, MAX - 35);
-
- // Allocate an outputMessage for the queue:
- outputMessage * lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
-
- //queueTargetedOutputMessage(parameters->outputQueue, lookMessage, ¤tCommand->caller, 1);
- memset(lookMessage, 0, sizeof(userMessage));
-
- // Loop through the paths and send the appropriate amount of messages:
- int charCount = 13;
- strncat(lookMessage->messageContent, "You can go:", 13);
-
- if (currentCommand->caller->currentArea->pathList->itemCount > 0)
- {
- for(size_t index = 0; index < currentCommand->caller->currentArea->pathList->itemCount; index++)
- {
- if ((charCount + 64) >= MAX)
- {
- lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
-
- memset(lookMessage, 0, sizeof(userMessage));
- charCount = 0;
- }
- snprintf(formattedString, 64, "\n\t%ld. %s", index + 1,
- getFromList(currentCommand->caller->currentArea->pathList, index)->path->pathName);
- strncat(lookMessage->messageContent, formattedString, 64);
- charCount += 64;
- }
- // Allocate another outputMessage for the queue:
- lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
- }
-
- // Clear the message:
- memset(lookMessage, 0, sizeof(userMessage));
- if(currentCommand->caller->currentArea != getFromList(parameters->areaList, 0)->area)
- {
- // Show the players in the area:
- charCount = 23;
- strncat(lookMessage->messageContent, "These players are here:", 24);
-
- int playerNumber = 1;
- for(int index = 0; index < *(parameters->playerCount); index++)
- {
- if (parameters->connectedPlayers[index].currentArea == currentCommand->caller->currentArea)
- {
- if ((charCount + 38) >= MAX)
- {
- lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
- memset(lookMessage, 0, sizeof(userMessage));
- charCount = 0;
- }
- snprintf(formattedString, 45, "\n%02d. %31s", playerNumber++,
- parameters->connectedPlayers[index].playerName);
- strncat(lookMessage->messageContent, formattedString, 64);
- charCount += 38;
- }
- }
- // Allocate another outputMessage for the queue:
- lookOutputMessage = createTargetedOutputMessage(lookMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, lookOutputMessage, OUTPUT_MESSAGE);
- }
-
- free(lookMessage);
- break;
- }
-
- // Stat command: Displays the current character's sheet.
- case 5987604:
- {
- char * formattedString = calloc(121, sizeof(char));
- userMessage * statMessage = calloc(1, sizeof(userMessage));
- statMessage->senderName[0] = '\0';
- // Basic status: Name, level, location.
- snprintf(formattedString, 120, "%s, Level %d | %s\n", currentCommand->caller->playerName,
- currentCommand->caller->stats->level, currentCommand->caller->currentArea->areaName);
- strncat(statMessage->messageContent, formattedString, 120);
-
- // Current stats: Health and WISED.
- snprintf(formattedString, 120,
- "Health: %d/%d\nStats:\n\tWits: %2d | Intellect: %2d | Strength: %2d | Endurance: %2d | Dexerity: %2d \n",
- currentCommand->caller->stats->currentHealth, currentCommand->caller->stats->maxHealth,
- currentCommand->caller->stats->wits, currentCommand->caller->stats->intellect,
- currentCommand->caller->stats->strength, currentCommand->caller->stats->endurance,
- currentCommand->caller->stats->dexerity);
- strncat(statMessage->messageContent, formattedString, 120);
-
- // Levelling stats: Current XP, and spec points.
- if (currentCommand->caller->stats->specPoints > 0 || currentCommand->caller->stats->skillPoints > 0)
- {
- snprintf(formattedString, 120, "Current Experience: %ld | Spec Points Available: %d | Skill Points Available: %d",
- currentCommand->caller->stats->experience, currentCommand->caller->stats->specPoints, currentCommand->caller->stats->skillPoints);
- }
- else
- {
- snprintf(formattedString, 120, "Current Experience: %ld", currentCommand->caller->stats->experience);
- }
- strncat(statMessage->messageContent, formattedString, 120);
-
- // Allocate an outputMessage for the queue:
- outputMessage * statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
-
- memset(statMessage->messageContent, 0, sizeof(char) * MAX);
- if (currentCommand->caller->skills->head != NULL)
- {
- size_t skillIndex = 0;
- int charCount = 0;
- bool addNewline = false;
- playerSkill * skill;
- while (skillIndex < currentCommand->caller->skills->itemCount)
- {
- skill = getFromList(currentCommand->caller->skills, skillIndex)->skill;
- skillIndex++;
- snprintf(formattedString, 120, "| %2d | %31s ", skill->skillPoints, skill->skillName);
- charCount += 43;
- strncat(statMessage->messageContent, formattedString, 120);
- if ((charCount + 43) >= MAX)
- {
- // Allocate an outputMessage for the queue:
- statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
- memset(statMessage, 0, sizeof(userMessage));
- charCount = 0;
- break;
- }
- else if (addNewline)
- {
- strncat(statMessage->messageContent, "|\n", 3);
- charCount++;
- addNewline = false;
- }
- else
- {
- addNewline = true;
- }
- }
- // Allocate an outputMessage for the queue:
- statOutputMessage = createTargetedOutputMessage(statMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, statOutputMessage, OUTPUT_MESSAGE);
- }
- free(statMessage);
- free(formattedString);
-
- break;
- }
-
- // Spec command: Assign spec points to stats:
- case 5982259:
- {
- userMessage * specMessage = calloc(1, sizeof(userMessage));
- specMessage->senderName[0] = '\0';
- char * formattedString = calloc(121, sizeof(char));
- if (currentCommand->caller->stats->specPoints > 0)
- {
- int selectedAmount = 0;
- strtok(currentCommand->arguments, " ");
- selectedAmount = atoi(¤tCommand->arguments[strlen(currentCommand->arguments) + 1]);
- coreStat selectedStat = getCoreStatFromString(currentCommand->arguments, 16);
- if (selectedAmount > 0 && (currentCommand->caller->stats->specPoints - selectedAmount) >= 0)
- {
- switch (selectedStat)
- {
- case WITS:
- {
- currentCommand->caller->stats->wits += selectedAmount;
- strncat(specMessage->messageContent, "Increased wits.", 16);
- currentCommand->caller->stats->specPoints -= selectedAmount;
- break;
- }
- case INTELLECT:
- {
- currentCommand->caller->stats->intellect += selectedAmount;
- strncat(specMessage->messageContent, "Increased intellect.", 21);
- currentCommand->caller->stats->specPoints -= selectedAmount;
- break;
- }
- case STRENGTH:
- {
- currentCommand->caller->stats->strength += selectedAmount;
- strncat(specMessage->messageContent, "Increased strength.", 20);
- currentCommand->caller->stats->specPoints -= selectedAmount;
- break;
- }
- case ENDURANCE:
- {
- currentCommand->caller->stats->endurance += selectedAmount;
- strncat(specMessage->messageContent, "Increased endurance.", 21);
- currentCommand->caller->stats->specPoints -= selectedAmount;
- break;
- }
- case DEXERITY:
- {
- currentCommand->caller->stats->dexerity += selectedAmount;
- strncat(specMessage->messageContent, "Increased dexerity.", 21);
- currentCommand->caller->stats->specPoints -= selectedAmount;
- break;
- }
- case INVALID:
- {
- strncat(specMessage->messageContent, "Invalid stat.", 21);
- }
- }
- }
- else
- {
- strncat(specMessage->messageContent, "You have entered an invalid amount of spec points.", 51);
- }
- }
- else
- {
- strncat(specMessage->messageContent, "You have no spec points available.", 35);
- }
-
- // Allocate an outputMessage for the queue:
- outputMessage * specOutputMessage = createTargetedOutputMessage(specMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, specOutputMessage, OUTPUT_MESSAGE);
-
- // Show the new stat sheet:
- queue->lock = false;
- queueCommand(queue, "stat", "", 5, 0, currentCommand->caller);
- queue->lock = true;
-
- // Free the finished message:
- free(specMessage);
- free(formattedString);
-
- break;
- }
-
- // Try command: Attempt to use a stat or skill on an object:
- case 163143:
- {
- // Allocate the userMessage to send:
- userMessage * tryMessage = calloc(1, (sizeof(userMessage)));
- tryMessage->senderName[0] = '\0';
-
- // Temporary message until we can implement objects, events, and challenges.
- strcpy(tryMessage->messageContent, "The try command is currently not implemented. Implement it if you want to use it.\n");
-
- // Allocate an outputMessage for the queue:
- outputMessage * tryOutputMessage = createTargetedOutputMessage(tryMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, tryOutputMessage, OUTPUT_MESSAGE);
-
- // Free the userMessage:
- free(tryMessage);
-
- break;
- }
-
- // Move command: Moves the caller to a different area given a path name or number:
- case 5677603:
- {
- char requestedPath[32];
- if (strlen(currentCommand->arguments) > 0 && currentCommand->caller->currentArea != getFromList(parameters->areaList, 0)->area)
- {
- memcpy(requestedPath, currentCommand->arguments, 32);
- userNameSanatize(requestedPath, 32);
- requestedPath[31] = '\0';
- if (movePlayerToArea(currentCommand->caller, requestedPath) == 0)
- {
- // Call the look command after moving. It's fine to unlock, because the loop won't
- // continue until the command is queued:
- queue->lock = false;
- queueCommand(queue, "look", "", 5, 0, currentCommand->caller);
- queue->lock = true;
- }
- }
-
- break;
- }
-
- // Skill command: Allows you to put skill points into skills:
- case 221096235:
- {
- userMessage * skillMessage = calloc(1, sizeof(userMessage));
- skillMessage->senderName[0] = '\0';
- if ((currentCommand->caller->stats->skillPoints - 1) >= 0)
- {
- int returnValue = takeSkill(parameters->globalSkillList, currentCommand->arguments,
- strlen(currentCommand->arguments), currentCommand->caller);
- switch(returnValue)
- {
- case -1:
- {
- strcpy(skillMessage->messageContent, "Not a valid skill.");
- break;
- }
- case 0:
- {
- strcpy(skillMessage->messageContent, "Took ");
- strcat(skillMessage->messageContent, currentCommand->arguments);
- strcat(skillMessage->messageContent, ".");
- currentCommand->caller->stats->skillPoints--;
- break;
- }
- }
- }
- else
- {
- strcpy(skillMessage->messageContent, "You don't have enough skill points to take this skill.\n");
- }
-
- // Allocate an outputMessage for the queue:
- outputMessage * skillOutputMessage = createTargetedOutputMessage(skillMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, skillOutputMessage, OUTPUT_MESSAGE);
-
- free(skillMessage);
- break;
- }
-
- // Listskills commands: List all available skills on the server:
- case 2395990522:
- {
- userMessage * listMessage = calloc(1, sizeof(userMessage));
- char * formattedString = calloc(121, sizeof(char));
- int charCount = 0;
- size_t skillIndex = 0;
- bool addNewline = false;
- playerSkill * currentSkill;
- while (skillIndex < parameters->globalSkillList->itemCount)
- {
- currentSkill = getFromList(parameters->globalSkillList, skillIndex)->skill;
- snprintf(formattedString, 120, "| %-31s ", currentSkill->skillName);
- charCount += 43;
- strncat(listMessage->messageContent, formattedString, 120);
- if ((charCount + 46) >= MAX)
- {
- // Allocate an outputMessage for the queue:
- outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE);
-
- memset(listMessage, 0, sizeof(userMessage));
- charCount = 0;
- addNewline = false;
- }
- else if (addNewline)
- {
- strncat(listMessage->messageContent, "|\n", 3);
- charCount++;
- addNewline = false;
- }
- else
- {
- addNewline = true;
- }
- skillIndex++;
- }
- // Allocate an outputMessage for the queue:
- outputMessage * listOutputMessage = createTargetedOutputMessage(listMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, listOutputMessage, OUTPUT_MESSAGE);
- free(listMessage);
- free(formattedString);
- break;
- }
- // Shout command: Allows the player to talk to everyone in the area if they are in a conversation.
- case 220952831:
- {
- // Allocate an array of playerInfo to store the current players in the area for the output message:
- playerInfo ** recipients = calloc(PLAYERCOUNT, sizeof(playerInfo*));
-
- // Initialize them all to NULL:
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- recipients[index] = NULL;
- }
-
- // Get the players in the current area and add them to our array:
- int recipientIndex = 0;
- for (int playerIndex = 0; playerIndex < *parameters->playerCount; playerIndex++)
- {
- if (parameters->connectedPlayers[playerIndex].currentArea == currentCommand->caller->currentArea)
- {
- recipients[recipientIndex] = ¶meters->connectedPlayers[playerIndex];
- recipientIndex++;
- }
- }
-
- // Create a userMessage to be filled with the data from the command's arguments and caller:
- userMessage * shoutMessage = calloc(1, sizeof(userMessage));
-
- // Copy in the data and terminate it:
- strncpy(shoutMessage->senderName, currentCommand->caller->playerName, 32);
- shoutMessage->senderName[31] = '\0';
- strncpy(shoutMessage->messageContent, currentCommand->arguments, MAX);
- shoutMessage->messageContent[MAX - 1] = '\0';
- strncat(shoutMessage->messageContent, "\n", MAX);
-
- // Create the outputMessage for the queue:
- outputMessage * shoutOutputMessage = createTargetedOutputMessage(shoutMessage, recipients, recipientIndex);
-
- // Push the message onto the output queue:
- pushQueue(parameters->outputQueue, shoutOutputMessage, OUTPUT_MESSAGE);
-
- // Free the array:
- free(recipients);
-
- break;
- }
- // Talk command: Allows the player to begin a chat session with another player:
- case 6012644:
- {
- userMessage * talkMessage = calloc(1, sizeof(userMessage));
- talkMessage->senderName[0] = '\0';
-
- // If there's no name specified, end the current chat sessions.
- if (currentCommand->arguments[0] == '\0' || currentCommand->arguments == NULL)
- {
- currentCommand->caller->talkingWith = NULL;
- strcpy(talkMessage->messageContent, "Conversation ended.");
- strncat(&talkMessage->senderName[1], " > ", 4);
- }
- else
- {
- for(int playerIndex = 0; playerIndex < *parameters->playerCount; playerIndex++)
- {
- if(strncmp(currentCommand->arguments, parameters->connectedPlayers[playerIndex].playerName, 31) == 0)
- {
- currentCommand->caller->talkingWith = &(parameters->connectedPlayers[playerIndex]);
-
- // Fill out the message to inform the receiving user what is happening:
- strncpy(talkMessage->messageContent, currentCommand->caller->playerName, 32);
- strcat(talkMessage->messageContent, " is talking to you.");
-
- playerInfo ** recipients = calloc(1, (sizeof(playerInfo*)));
- recipients[0] = &(parameters->connectedPlayers[playerIndex]);
-
- // Allocate an outputMessage for the receiving user:
- outputMessage * talkReceiverMessage = createTargetedOutputMessage(talkMessage, recipients, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, talkReceiverMessage, OUTPUT_MESSAGE);
-
- // Prep the message to the calling user.
- memcpy(&talkMessage->senderName[1], currentCommand->arguments, sizeof(char) * 27);
- strncat(&talkMessage->senderName[1], " > ", 4);
- strcpy(talkMessage->messageContent, "Conversation begun with: ");
- strcat(talkMessage->messageContent, parameters->connectedPlayers[playerIndex].playerName);
- }
- }
- }
- if(talkMessage->messageContent[0] == '\0')
- {
- strcpy(talkMessage->messageContent, "There is no player by that name connected.");
- }
-
- // Allocate an outputMessage for the queue:
- outputMessage * talkOutputMessage = createTargetedOutputMessage(talkMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, talkOutputMessage, OUTPUT_MESSAGE);
-
- // Free the userMessage:
- free(talkMessage);
-
- break;
- }
-
- // Exit command: Sends an "empty" exit message to disconnect a client:
- case 5284234:
- {
- // Allocate a userMessage containing null characters as the first char in both fields:
- userMessage * exitMessage = calloc(1, (sizeof(userMessage)));
- exitMessage->senderName[0] = '\0';
- exitMessage->messageContent[0] = '\0';
-
- // Allocate an outputMessage for the queue:
- outputMessage * exitOutputMessage = createTargetedOutputMessage(exitMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, exitOutputMessage, OUTPUT_MESSAGE);
-
- // Free the userMessage
- free(exitMessage);
-
- break;
- }
-
- // Join command: Allows the player to join the game given a name:
- // TODO: Implement login/character creation. Will be a while:
- case 5525172:
- {
- if (currentCommand->caller->currentArea == getFromList(parameters->areaList, 0)->area)
- {
- bool validName = true;
- for(int index = 0; index < *parameters->playerCount; index++)
- {
- if (currentCommand->arguments[0] == '\0')
- {
- validName = false;
- }
- if (strncmp(currentCommand->arguments, parameters->connectedPlayers[index].playerName, 16) == 0)
- {
- validName = false;
- }
- }
- if (validName)
- {
- strncpy(currentCommand->caller->playerName, currentCommand->arguments, 16);
- currentCommand->caller->currentArea = getFromList(parameters->areaList, 1)->area;
-
- // Allocate a userMessage containing null characters as the first char in both fields:
- userMessage * joinMessage = calloc(1, (sizeof(userMessage)));
- memcpy(joinMessage->senderName, "\0 > \0", 5);
- strcpy(joinMessage->messageContent, "Logged in successfully.");
-
- // Allocate an outputMessage for the queue:
- outputMessage * joinOutputMessage = createTargetedOutputMessage(joinMessage, ¤tCommand->caller, 1);
-
- // Queue the outputMessage:
- pushQueue(parameters->outputQueue, joinOutputMessage, OUTPUT_MESSAGE);
-
- // Free the userMessage
- free(joinMessage);
-
- // Call the look command after joining. It's fine to unlock, because the loop won't
- // continue until the command is queued:
- queue->lock = false;
- queueCommand(queue, "look", "", 5, 0, currentCommand->caller);
- queue->lock = true;
- }
- }
- break;
- }
- }
-
- // Remove the current command and unlock the queue:
- memset(currentCommand->command, 0, sizeof(char) * 16);
- memset(currentCommand->arguments, 0, sizeof(char) * MAX);
- currentCommand = NULL;
- queue->lock = false;
- popQueue(queue);
- return 0;
-}
-
-// Run a stat check for the given player, returning an outcome:
-outcome statCheck(playerInfo * player, int chance, coreStat statToCheck)
-{
- // Calculate the chance:
- if (chance > 100 || chance < 0)
- {
- return ERROR;
- }
- chance = 100 - chance;
-
- // Calculate the modifier:
- int modifier = 0;
- switch(statToCheck)
- {
- case WITS:
- {
- modifier = player->stats->wits * 4;
- break;
- }
- case INTELLECT:
- {
- modifier = player->stats->intellect * 4;
- break;
- }
- case STRENGTH:
- {
- modifier = player->stats->strength * 4;
- break;
- }
- case ENDURANCE:
- {
- modifier = player->stats->endurance * 4;
- break;
- }
- case DEXERITY:
- {
- modifier = player->stats->dexerity * 4;
- break;
- }
- default:
- {
- return ERROR;
- }
- }
- int attempt = (rand() % 100) + modifier;
- if (attempt >= chance)
- {
- if (attempt >= 98)
- {
- return CRITICAL_SUCCESS;
- }
- else
- {
- return SUCCESS;
- }
- }
- else
- {
- if (attempt <= 2)
- {
- return CRITICAL_FAILURE;
- }
- else
- {
- return FAILURE;
- }
- }
-}
-
-// Run a skill check for the given player, returning an outcome:
-outcome skillCheck(playerInfo * player, int chance, char * skillName, size_t skillNameLength, list * globalSkillList)
-{
- // Calculate the chance:
- if (chance > 100 || chance < 0)
- {
- return ERROR;
- }
- chance = 100 - chance;
-
- // Check if the player has the given skill:
- bool playerHasSkill = false;
- size_t playerIndex = 0;
- while (playerIndex < player->skills->itemCount)
- {
- if (strncmp(skillName, getFromList(player->skills, playerIndex)->skill->skillName, skillNameLength) != 0)
- {
- playerHasSkill = true;
- break;
- }
- playerIndex++;
- }
-
- // If the player doesn't have the skill, check if it's in the game and is trained:
- bool trainedSkill = false;
- size_t globalIndex = 0;
- while (globalIndex < globalSkillList->itemCount)
- {
- if (strncmp(skillName, getFromList(globalSkillList, globalIndex)->skill->skillName, skillNameLength) != 0)
- {
- trainedSkill = getFromList(globalSkillList, globalIndex)->skill->trainedSkill;
- break;
- }
- globalIndex++;
- }
-
- // Calculate the modifier:
- int modifier = 0;
- if (trainedSkill)
- {
- modifier = -100;
- }
- else if (playerHasSkill)
- {
- modifier = getFromList(player->skills, playerIndex)->skill->skillModifier * 4;
- }
-
- // Attempt the check:
- int attempt = (rand() % 100) + modifier;
- if (attempt >= chance)
- {
- if (attempt >= 98)
- {
- return CRITICAL_SUCCESS;
- }
- else
- {
- return SUCCESS;
- }
- }
- else
- {
- if (attempt <= 2)
- {
- return CRITICAL_FAILURE;
- }
- else
- {
- return FAILURE;
- }
- }
-}
-
-// Move a player along a path in their current area:
-int movePlayerToArea(playerInfo * player, char * requestedPath)
-{
- // Check if a number was given first:
- size_t selected = atoi(requestedPath);
- if (selected != 0 && !(selected > player->currentArea->pathList->itemCount))
- {
- if (getFromList(player->currentArea->pathList, selected - 1)->path != NULL &&
- getFromList(player->currentArea->pathList, selected - 1)->path->areaToJoin != NULL)
- {
- player->currentArea = getFromList(player->currentArea->pathList, selected - 1)->path->areaToJoin;
- return 0;
- }
- else
- {
- return 1;
- }
- }
-
- // Otherwise search for the description:
- for (size_t index = 0; index < player->currentArea->pathList->itemCount; index++)
- {
- if (strncmp(getFromList(player->currentArea->pathList, index)->path->pathName,
- requestedPath, 32) == 0)
- {
- player->currentArea = getFromList(player->currentArea->pathList, index)->path->areaToJoin;
- return 0;
- }
- }
- return 1;
-}
-
-// A hash function for distinguishing commands for the game logic handler:
-unsigned int hashCommand(char * command, unsigned int commandLength)
-{
- unsigned int hash = 0;
- char * currentCharacter = command;
-
- for (unsigned int index = 0; index < commandLength && *currentCharacter != '\0'; currentCharacter++)
- {
- hash = 37 * hash + *currentCharacter;
- }
-
- return hash;
-}
diff --git a/src/gamelogic.h b/src/gamelogic.h
deleted file mode 100644
index f36b749..0000000
--- a/src/gamelogic.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// gamelogic.h: Function prototypes and data-structures for dealing with game logic.
-// Barry Kane, 2022.
-#ifndef GAMELOGIC_H
-#define GAMELOGIC_H
-#include "areadata.h"
-#include "constants.h"
-#include "playerdata.h"
-
-// Forward-declare some data structures to prevent cyclic dependencies:
-typedef struct queue queue;
-typedef struct inputMessage inputMessage;
-
-// ========================
-// -=[ Data Structures ]=-:
-// ========================
-
-// An event for storing the information needed to evaluate a command:
-typedef struct commandEvent commandEvent;
-typedef struct commandEvent
-{
- playerInfo * caller;
- commandEvent * next;
- char * command;
- char * arguments;
-} commandEvent;
-
-// A data-structure containing the needed parameters for the main game loop:
-typedef struct gameLogicParameters
-{
- // Players:
- int * playerCount;
- playerInfo * connectedPlayers;
-
- // Queues:
- queue * inputQueue;
- queue * outputQueue;
-
- // Lists:
- list * areaList;
- list * globalSkillList;
-} gameLogicParameters;
-
-// ========================
-// -=[ Functions ]=-:
-// ========================
-
-// Thread function which runs the main game loop, given the needed parameters:
-void * gameLogicHandler(void * parameters);
-
-// Enqueue a command that has been sent as a message from a user to a queue:
-void queueMessagedCommand(queue * queue, inputMessage * messageToQueue);
-
-// Evaluate the next commandEvent in a queue:
-int evaluateNextCommand(gameLogicParameters * parameters, queue * queue);
-
-// Enqueue a command to a queue:
-void queueCommand(queue * queue, char * command, char * arguments, int commandLength, int argumentsLength,
- playerInfo * callingPlayer);
-
-// A hash function for distinguishing commands for the game logic handler:
-unsigned int hashCommand(char * command, unsigned int commandLength);
-
-// ============================
-// -=[ Gameplay Primitives ]=-:
-// ============================
-
-// The possible outcomes of a check or challenge:
-typedef enum outcome
-{
- CRITICAL_FAILURE,
- FAILURE,
- SUCCESS,
- CRITICAL_SUCCESS,
- ERROR
-} outcome;
-
-// Move a player along a path in their current area:
-int movePlayerToArea(playerInfo * player, char * requestedPath);
-
-// Run a stat check for the given player, returning an outcome:
-outcome statCheck(playerInfo * player, int chance, coreStat statToCheck);
-
-// Run a skill check for the given player, returning an outcome:
-outcome skillCheck(playerInfo * player, int chance, char * skillName, size_t skillNameLength, list * globalSkillList);
-
-#endif
diff --git a/src/inputoutput.c b/src/inputoutput.c
deleted file mode 100644
index b8e4136..0000000
--- a/src/inputoutput.c
+++ /dev/null
@@ -1,173 +0,0 @@
-// inputoutput.c: Implementation of input/output library for SilverMUD.
-// Barry Kane, 2022.
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "queue.h"
-#include "constants.h"
-#include "playerdata.h"
-#include "inputoutput.h"
-
-// Sends a message to a given TLS session, wraps the calls to gnutls_write:
-int messageSend(gnutls_session_t receivingSession, userMessage * messageToSend)
-{
- int returnValue = 0;
- // Continuously attempt to send the name field until it succeeds or fatally errors:
- do
- {
- returnValue = gnutls_record_send(receivingSession, messageToSend->senderName,
- sizeof(((userMessage*)0)->senderName));
- } while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
-
- // Continuously attempt to send the message field until it succeeds or fatally errors:
- do
- {
- returnValue = gnutls_record_send(receivingSession, messageToSend->messageContent,
- sizeof(((userMessage*)0)->messageContent));
- } while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
-
- return returnValue;
-}
-
-// Recieves a message from a given TLS session, wraps the calls to gnutls_read:
-int messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToMessage)
-{
- int returnValue = 0;
- // Continuously attempt to receive the name field until it succeeds or fatally errors:
- do
- {
- returnValue = gnutls_record_recv(receiveFromSession, receiveToMessage->senderName,
- sizeof(((userMessage*)0)->senderName));
- } while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
-
- // Continuously attempt to receive the message field until it succeeds or fatally errors:
- do
- {
- returnValue = gnutls_record_recv(receiveFromSession, receiveToMessage->messageContent,
- sizeof(((userMessage*)0)->messageContent));
- } while (returnValue == GNUTLS_E_AGAIN || returnValue == GNUTLS_E_INTERRUPTED);
-
- return returnValue;
-}
-
-// Allocate and initialize an outputMessage targeted to a variable amount of players:
-outputMessage * createTargetedOutputMessage(userMessage * messageToQueue, playerInfo ** recipients, int recipientsCount)
-{
- // Allocate a new output message:
- outputMessage * newOutputMessage = malloc(sizeof(outputMessage));
- newOutputMessage->content = malloc(sizeof(userMessage));
-
- // Allocate an array of playerInfo for the output message recepients:
- newOutputMessage->recipients = malloc(sizeof(playerInfo*) * recipientsCount);
-
- // Copy in the appropriate data:
- memcpy(newOutputMessage->recipients, recipients, sizeof(playerInfo *) * recipientsCount);
- memcpy(newOutputMessage->content, messageToQueue, sizeof(userMessage));
- newOutputMessage->recipientsCount = recipientsCount;
-
- // Return a pointer to the new outputMessage:
- return newOutputMessage;
-}
-
-// A function for the output thread, which sends queued messages:
-void * outputThreadHandler(void * parameters)
-{
- outputThreadParameters * variables = parameters;
- queue * outputQueue = variables->outputQueue;
- gnutls_session_t * tlssessions = variables->tlssessions;
- playerInfo * connectedPlayers = variables->connectedPlayers;
-
- while (true)
- {
- // If there's nothing to do, put the thread to sleep:
- if (outputQueue->itemCount == 0)
- {
- pthread_cond_wait(&outputQueue->condition, &outputQueue->mutex);
- }
-
- // Run through the output queue and send all unsent messages:
- while (outputQueue->itemCount != 0)
- {
- // Wait until the queue unlocks:
- while (outputQueue->lock);
-
- // Lock the queue:
- outputQueue->lock = true;
-
- // Get a message off the queue:
- outputMessage * message = peekQueue(outputQueue)->data.outputMessage;
-
- // Unlock the queue:
- outputQueue->lock = false;
-
- // If the first target is set to NULL, it's intended for all connected:
- if (message->recipientsCount == 0)
- {
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- messageSend(tlssessions[index], message->content);
- }
- }
-
- // Otherwise, send it only to the targeted players:
- else
- {
- int sentCount = 0;
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- if (sentCount == message->recipientsCount)
- {
- break;
- }
- if (&connectedPlayers[index] == message->recipients[sentCount])
- {
- sentCount++;
- messageSend(tlssessions[index], message->content);
- }
- }
- }
-
- // Remove the output message from the queue:
- popQueue(outputQueue);
- }
- }
-}
-
-// Sanatize user input to ensure it's okay to process:
-void userInputSanatize(char * inputString, int length)
-{
- for (int index = 0; index <= length; index++)
- {
- // If it's not a printable character, it has no business being here:
- if(!isprint(inputString[index]))
- {
- inputString[index] = '\n';
- inputString[index + 1] = '\0';
- break;
- }
- }
-
- // Make sure it's null-terminated:
- inputString[length - 1] = '\0';
-}
-
-// Sanatize user names so they display correctly:
-void userNameSanatize(char * inputString, int length)
-{
- for(int index = 0; index <= length; index++)
- {
- // If it's not a printable character, it has no business being here:
- if(!isprint(inputString[index]))
- {
- inputString[index] = '\0';
- break;
- }
- }
- // Make sure it's null-terminated:
- inputString[length - 1] = '\0';
-}
diff --git a/src/inputoutput.h b/src/inputoutput.h
deleted file mode 100644
index 93a1cbb..0000000
--- a/src/inputoutput.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// inputoutput.h: Header file contatning function prototypes and datastructures
-// for dealing with input and output.
-// Barry Kane, 2022.
-#ifndef INPUTOUTPUT_H
-#define INPUTOUTPUT_H
-#include
-#include
-#include
-#include
-#include "constants.h"
-#include "playerdata.h"
-
-// Forward-declare some data structures to prevent cyclic dependencies:
-typedef struct queue queue;
-
-// ========================
-// -=[ Data Structures ]=-:
-// ========================
-
-// Contains a character/player name and the content of a message:
-typedef struct userMessage
-{
- char senderName[32];
- char messageContent[MAX];
-} userMessage;
-
-// Contains a message sent to the server and a pointer to the playerInfo of the connection which sent it:
-typedef struct inputMessage
-{
- playerInfo * sender;
- userMessage * content;
-} inputMessage;
-
-// Contains a message to be sent, the amount of recipients, and pointers to their playerInfo:
-typedef struct outputMessage
-{
- int recipientsCount;
- userMessage * content;
- playerInfo ** recipients;
-} outputMessage;
-
-// Contains pointers to the necessary information to be shared outputThreadHandler function:
-typedef struct outputThreadParameters
-{
- queue * outputQueue;
- gnutls_session_t * tlssessions;
- playerInfo * connectedPlayers;
-} outputThreadParameters;
-
-// ========================
-// -=[ Functions ]=-:
-// ========================
-
-// Sends a message to a given TLS session, wraps the calls to gnutls_write:
-int messageSend(gnutls_session_t receivingSession, userMessage * messageToSend);
-
-// Receives a message from a given TLS session, wraps the calls to gnutls_read:
-int messageReceive(gnutls_session_t receiveFromSession, userMessage * receiveToMessage);
-
-// Create a targetedOutput message to be delivered to the players pointed to in recipients:
-outputMessage * createTargetedOutputMessage(userMessage * messageToQueue, playerInfo ** recipients, int recipientCount);
-
-// A function for the output thread, which sends queued messages:
-void * outputThreadHandler(void * parameters);
-
-// Sanatize user input to ensure it's okay to process:
-void userInputSanatize(char * inputString, int length);
-
-// Sanatize user names so they display correctly:
-void userNameSanatize(char * inputString, int length);
-
-#endif
-
diff --git a/src/linkedlist.c b/src/linkedlist.c
deleted file mode 100644
index c7ff81d..0000000
--- a/src/linkedlist.c
+++ /dev/null
@@ -1,480 +0,0 @@
-// linkedlist.h: Function definitions for the list type for SilverMUD.
-// Barry Kane, 2022.
-#include
-#include
-#include
-#include
-#include "playerdata.h"
-#include "linkedlist.h"
-
-// Deallocate a given list node, including it's data:
-static inline void deallocateListNode(listNode * node, listDataType type)
-{
- // Delete the node:
- switch (type)
- {
- case PLAYER:
- {
- deallocatePlayer(node->data.player);
- break;
- }
- case AREA:
- {
- destroyList(&(node->data.area->pathList));
- free(node->data.area);
- free(node);
- break;
- }
- case PATH:
- {
- free(node->data.path);
- free(node);
- break;
- }
- case SKILL:
- {
- free(node->data.skill);
- free(node);
- break;
- }
- }
-}
-
-// Allocates and instantiates a list of the specified type:
-list * createList(listDataType type)
-{
- // Allocate and clear the memory for the list:
- list * newList = calloc(sizeof(list), 1);
-
- // Set the appropriate values in the new list:
- newList->type = type;
- newList->itemCount = 0;
- newList->head = NULL;
- newList->tail = NULL;
-
- // Return the new list:
- return newList;
-}
-
-// Deallocates a list and all of it's members:
-int destroyList(list ** list)
-{
- // Check if the list is empty:
- if ((*list)->itemCount == 0)
- {
- free(*list);
- list = NULL;
- return 0;
- }
- else
- {
- while ((*list)->itemCount > 0)
- {
- removeFromList((*list), (*list)->type, (*list)->itemCount - 1);
- }
- free(*list);
- *list = NULL;
- return 0;
- }
-}
-
-// Returns the data at a given index in a list:
-listData * getFromList(list * list, size_t listIndex)
-{
- // Check that we were given a valid index:
- if (listIndex > (list->itemCount - 1))
- {
- perror("Invalid index specified.\n");
- return NULL;
- }
- // Return the head if index is 0:
- else if (listIndex == 0)
- {
- return &(list->head->data);
- }
- // Loop through the entries in the list until we get to the right one:
- else
- {
- listNode * currentNode = list->head;
- while (listIndex-- > 0)
- {
- currentNode = currentNode->next;
- }
- return &(currentNode->data);
- }
-}
-
-// Returns the node at a given index in a list:
-listNode * getNodeFromList(list * list, size_t listIndex)
-{
- // Check that we were given a valid index:
- if (listIndex > (list->itemCount - 1))
- {
- perror("Invalid index specified.\n");
- return NULL;
- }
- // Return the head if index is 0:
- else if (listIndex == 0)
- {
- return list->head;
- }
- // Loop through the entries in the list until we get to the right one:
- else
- {
- if ((list->itemCount / 2) < listIndex)
- {
- listNode * currentNode = list->tail;
- while (listIndex-- > 0)
- {
- currentNode = currentNode->previous;
- }
- return currentNode;
- }
- else
- {
- listNode * currentNode = list->head;
- while (listIndex-- > 0)
- {
- currentNode = currentNode->next;
- }
- return currentNode;
- }
- }
-}
-
-// Adds the given data to the end of a list:
-listNode * addToList(list * list, void * data, listDataType type)
-{
- // Check the type:
- if (type != list->type)
- {
- fprintf(stderr, "Not the correct type for this list.\n");
- return NULL;
- }
-
- // If this is the first item in the list:
- if (list->itemCount == 0)
- {
- // Allocate the new node for the list:
- list->head = calloc(1, sizeof(listNode));
-
- // Set the appropriate pointers for the list:
- list->head->next = NULL;
- list->head->previous = NULL;
- list->tail = list->head;
-
- // Add the data to the new node:
- switch (type)
- {
- case PATH:
- {
- list->head->data.path = (playerPath *)data;
- break;
- }
- case AREA:
- {
- list->head->data.area = (playerArea *)data;
- break;
- }
- case PLAYER:
- {
- list->head->data.player = (playerInfo *)data;
- break;
- }
- case SKILL:
- {
- list->head->data.skill = (playerSkill *)data;
- break;
- }
- }
- }
- else
- {
- // Allocate the new node at the end of the list:
- list->tail->next = calloc(1, sizeof(listNode));
-
- // Add the data to the new node:
- switch (type)
- {
- case PATH:
- {
- list->tail->next->data.path = (playerPath *)data;
- break;
- }
- case AREA:
- {
- list->tail->next->data.area = (playerArea *)data;
- break;
- }
- case PLAYER:
- {
- list->tail->next->data.player = (playerInfo *)data;
- break;
- }
- case SKILL:
- {
- list->tail->next->data.skill = (playerSkill *)data;
- break;
- }
- }
-
- // Set the appropriate pointers in the new node:
- list->tail->next->previous = list->tail;
-
- // Set the list's tail to the new tail:
- list->tail = list->tail->next;
- }
- // Increase the count of items in the list:
- list->itemCount++;
-
- // Return the new item in the list:
- return list->tail;
-}
-
-// Insert the given data at a given index in the list:
-listNode * insertIntoList(list * list, void * data, listDataType type, size_t listIndex)
-{
- // Check that the types are correct:
- if (list->type != type)
- {
- fprintf(stderr, "Types do not match.\n");
- return NULL;
- }
-
- // Handle the special case of adding to the end of the list:
- if (listIndex == (list->itemCount - 1))
- {
- return addToList(list, data, type);
- }
-
- // Handle the special case of adding to the beginning of the list:
- if (listIndex == 0)
- {
- // Create the new node:
- listNode * newNode = calloc(1, sizeof(listNode));
-
- // Add the data to the node:
- switch (type)
- {
- case PATH:
- {
- newNode->data.path = (playerPath *)data;
- break;
- }
- case AREA:
- {
- newNode->data.area = (playerArea *)data;
- break;
- }
- case PLAYER:
- {
- newNode->data.player = (playerInfo *)data;
- break;
- }
- case SKILL:
- {
- newNode->data.skill = (playerSkill *)data;
- break;
- }
- }
-
- // Place it in the list:
- newNode->next = list->head;
- newNode->previous = NULL;
- list->head->previous = newNode;
- list->head = newNode;
- list->itemCount++;
-
- // Return the node:
- return newNode;
- }
-
- // Check that the index is valid:
- if (listIndex > (list->itemCount - 1))
- {
- fprintf(stderr, "Index is invalid for the list.\n");
- return NULL;
- }
-
- // Get the current node at the index:
- listNode * currentNode = list->head;
- for(size_t index = 0; index < listIndex; index++)
- {
- currentNode = currentNode->next;
- }
-
- // Get the node before the current node:
- listNode * previousNode = currentNode->previous;
-
- // Create the new node:
- previousNode->next = calloc(1, sizeof(listNode));
- currentNode->previous = previousNode->next;
- previousNode->next->next = currentNode;
- previousNode->next->previous = previousNode;
-
- // Add the data to the node:
- switch (type)
- {
- case PATH:
- {
- previousNode->next->data.path = (playerPath *)data;
- break;
- }
- case AREA:
- {
- previousNode->next->data.area = (playerArea *)data;
- break;
- }
- case PLAYER:
- {
- previousNode->next->data.player = (playerInfo *)data;
- break;
- }
- case SKILL:
- {
- previousNode->next->data.skill = (playerSkill *)data;
- break;
- }
- }
- list->itemCount++;
- return previousNode->next;
-}
-
-// Delete the given data from a list:
-bool deleteFromList(list * list, void * data, listDataType type)
-{
- size_t index = 0;
- if (getIndexFromList(list, data, type, &index) == false)
- {
- return false;
- }
- else
- {
- removeFromList(list, type, index);
- return true;
- }
-}
-
-// Delete the data from a given point in a list:
-int removeFromList(list * list, listDataType type, size_t listIndex)
-{
- // Check that we're removing the correct type:
- if (list->type != type)
- {
- return -1;
- }
-
- // Check the list index is valid:
- if (listIndex > list->itemCount - 1)
- {
- return -2;
- }
-
- // The first node in the list:
- if (listIndex == 0)
- {
- // Get the current head and move the list's head on:
- listNode * oldHead = list->head;
- list->head = list->head->next;
-
- // If we haven't removed the last item, set the previous pointer
- // in the new head to null.
- if (list->head != NULL)
- {
- list->head->previous = NULL;
- }
-
- // Delete the node:
- deallocateListNode(oldHead, type);
-
- // Return the new amount of items in the list:
- list->itemCount--;
- return list->itemCount;
- }
- // The last node in the list:
- else if (listIndex == (list->itemCount - 1))
- {
- // Move the tail up by one:
- list->tail = list->tail->previous;
-
- // Deallocate the former tail:
- deallocateListNode(list->tail->next, type);
-
- // Set the appropriate pointer:
- list->tail->next = NULL;
-
- // Return the new amount of items in the list:
- list->itemCount--;
- return list->itemCount;
- }
- // A node in the middle of the list:
- else
- {
- // Get the needed node as a pointer:
- listNode * nodeToDelete = getNodeFromList(list, listIndex);
-
- // Set the appropriate pointers for the surrounding nodes:
- nodeToDelete->previous->next = nodeToDelete->next;
- nodeToDelete->next->previous = nodeToDelete->previous;
-
- // Deallocate the node:
- deallocateListNode(nodeToDelete, type);
-
- // Return the new amount of items in the list:
- list->itemCount--;
- return list->itemCount;
- }
-}
-
-// Get the index of a given piece of data in a list:
-bool getIndexFromList(list * list, void * data, listDataType type, size_t * index)
-{
- // Check the list types are the same:
- if (list->type == type)
- {
- fprintf(stderr, "List types do not match.\n");
- return false;
- }
-
- // Search through the list, one-by-one, comparing the list items:
- for (*index = 0; *index < list->itemCount; *index += 1)
- {
- switch (type)
- {
- case AREA:
- {
- if (getFromList(list, *index)->area == data)
- {
- return true;
- }
- break;
- }
- case PLAYER:
- {
- if (getFromList(list, *index)->player == data)
- {
- return true;
- }
- break;
- }
- case PATH:
- {
- if (getFromList(list, *index)->path == data)
- {
- return true;
- }
- break;
- }
- case SKILL:
- {
- if (getFromList(list, *index)->skill == data)
- {
- return true;
- }
- break;
- }
- }
- }
- return false;
-}
-
diff --git a/src/linkedlist.h b/src/linkedlist.h
deleted file mode 100644
index 3ac3940..0000000
--- a/src/linkedlist.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// linkedlist.h: Defines the linked list datatype for SilverMUD.
-// Barry Kane, 2022.
-#ifndef LINKEDLIST_H
-#define LINKEDLIST_H
-#include "areadata.h"
-
-// Let the compiler know there will be structs defined elsewhere:
-typedef struct playerPath playerPath;
-typedef struct playerArea playerArea;
-typedef struct playerInfo playerInfo;
-typedef struct playerSkill playerSkill;
-
-// ========================
-// -=[ Data Structures ]=-:
-// ========================
-
-// An enum of the possible data types that can be stored in a list:
-typedef enum listDataType
-{
- PATH,
- AREA,
- PLAYER,
- SKILL
-} listDataType;
-
-// A union containing a pointers to all data types that can be stored in a list:
-typedef union listData
-{
- playerPath * path;
- playerArea * area;
- playerInfo * player;
- playerSkill * skill;
-} listData;
-
-// A doubly linked node for the linked list type:
-typedef struct listNode listNode;
-typedef struct listNode
-{
- listData data;
- listNode * next;
- listNode * previous;
-} listNode;
-
-// A header structure for the list containing the length, head, tail, and type of the list.
-typedef struct list
-{
- listDataType type;
- size_t itemCount;
- listNode * head;
- listNode * tail;
-} list;
-
-// ========================
-// -=[ Functions ]=-:
-// ========================
-
-// Allocates and instantiates a list of the specified type:
-list * createList(listDataType type);
-
-// Deallocates a list and all of it's members:
-int destroyList(list ** list);
-
-// Returns the data at a given index in a list:
-listData * getFromList(list * list, size_t listIndex);
-
-// Returns the node at a given index in a list:
-listNode * getNodeFromList(list * list, size_t listIndex);
-
-// Adds the given data to the end of a list:
-listNode * addToList(list * list, void * data, listDataType type);
-
-// Insert the given data at a given index in the list:
-listNode * insertIntoList(list * list, void * data, listDataType type, size_t listIndex);
-
-// Delete the given data from a list:
-bool deleteFromList(list * list, void * data, listDataType type);
-
-// Delete the data from a given point in a list:
-int removeFromList(list * list, listDataType type, size_t listIndex);
-
-// Get the index of a given piece of data in a list:
-bool getIndexFromList(list * list, void * data, listDataType type, size_t * index);
-
-#endif
diff --git a/src/playerdata.c b/src/playerdata.c
deleted file mode 100644
index 56bb4ed..0000000
--- a/src/playerdata.c
+++ /dev/null
@@ -1,225 +0,0 @@
-// playerdata.c: Contains functions definitions for working with player data.
-// Barry Kane, 2021
-#include
-#include
-#include
-#include
-#include
-#include "constants.h"
-#include "playerdata.h"
-
-// Create a new skill and add it to the global skill list:
-listNode * createSkill(list * globalSkillList, char * skillName, int skillNameLength, bool trainedSkill)
-{
- if (skillNameLength >= 32)
- {
- fprintf(stderr, "Skill name is too long. Please shorten the name and try again.\n");
- return NULL;
- }
- playerSkill * newSkill = malloc(sizeof(playerSkill));
-
- strncpy(newSkill->skillName, skillName, 31);
- newSkill->skillName[31] = '\0';
-
- newSkill->skillPoints = 0;
- newSkill->skillModifier = 0;
- newSkill->trainedSkill = trainedSkill;
-
- // Add the skill to a node in the list:
- return(addToList(globalSkillList, newSkill, SKILL));
-}
-
-// Take a skill and add it to the player's skill list:
-int takeSkill(list * globalSkillList, char * skillName, int skillNameLength, playerInfo * targetPlayer)
-{
- // Check if the skill exists in the game:
- size_t globalIndex = 0;
- bool skillExists = false;
- while (globalIndex < globalSkillList->itemCount)
- {
- if (strncmp(skillName, getFromList(globalSkillList, globalIndex)->skill->skillName, skillNameLength) == 0)
- {
- skillExists = true;
- break;
- }
- globalIndex++;
- }
-
- if (!skillExists)
- {
- fprintf(stderr, "Skill doesn't exist in skill list.\n");
- return -1;
- }
-
- // Check if the player has the skill:
- size_t playerIndex = 0;
- bool playerHasSkill = false;
- while (playerIndex < targetPlayer->skills->itemCount)
- {
- if (strncmp(skillName, getFromList(targetPlayer->skills, playerIndex)->skill->skillName, skillNameLength) == 0)
- {
- playerHasSkill = true;
- break;
- }
- playerIndex++;
- }
- if (playerHasSkill)
- {
- getFromList(targetPlayer->skills, playerIndex)->skill->skillPoints++;
- }
-
- // Copy the skill into the player's skill list:
- else
- {
- playerSkill * newSkill = calloc(1, sizeof(playerSkill));
- strncpy(newSkill->skillName, getFromList(globalSkillList, globalIndex)->skill->skillName, 32);
- printf("%s ", newSkill->skillName);
- newSkill->skillPoints = 1;
- addToList(targetPlayer->skills, newSkill, SKILL);
- }
- return 0;
-}
-
-
-// Take a string containing a core stat name and return the core stat:
-coreStat getCoreStatFromString(char * inputString, int stringLength)
-{
- // Check we've got a long enough string to fit a stat:
- if (stringLength < 4)
- {
- return INVALID;
- }
-
- // Lowercase the string:
- char * string = malloc(sizeof(char) * stringLength);
- for(int index = 0; index < stringLength; index++)
- {
- string[index] = tolower(inputString[index]);
- }
-
- // If we have a string that's at most just the stat name plus a null character, or
- // a dirtier string, we can check in a better order and ignore impossibilites:
- if (stringLength < 9)
- {
- if (stringLength <= 4)
- {
- if (strncmp(string, "wits", 4) == 0)
- {
- free(string);
- return WITS;
- }
- else
- {
- free(string);
- return INVALID;
- }
- }
- // Hopefully one of the seven letter long ones:
- else if (stringLength <= 7)
- {
- if (strncmp(string, "strength", 7) == 0)
- {
- free(string);
- return STRENGTH;
- }
- else if (strncmp(string, "dexerity", 7) == 0)
- {
- free(string);
- return DEXERITY;
- }
- if (strncmp(string, "wits", 4) == 0)
- {
- free(string);
- return WITS;
- }
- else
- {
- free(string);
- return INVALID;
- }
- }
- // Hopefully one of the 8 letter long stats:
- else
- {
- if (strncmp(string, "intellect", 8) == 0)
- {
- free(string);
- return INTELLECT;
- }
- else if (strncmp(string, "endurance", 8) == 0)
- {
- free(string);
- return ENDURANCE;
- }
- else if (strncmp(string, "strength", 7) == 0)
- {
- free(string);
- return STRENGTH;
- }
- else if (strncmp(string, "dexerity", 7) == 0)
- {
- free(string);
- return DEXERITY;
- }
- if (strncmp(string, "wits", 4) == 0)
- {
- free(string);
- return WITS;
- }
- else
- {
- free(string);
- return INVALID;
- }
- }
- }
- // Worst case, it's definitely a dirty string, compare them all:
- else
- {
- if (strncmp(string, "wits", 4) == 0)
- {
- free(string);
- return WITS;
- }
- else if (strncmp(string, "intellect", 8) == 0)
- {
- free(string);
- return INTELLECT;
- }
- else if (strncmp(string, "strength", 7) == 0)
- {
- free(string);
- return STRENGTH;
- }
- else if (strncmp(string, "endurance", 8) == 0)
- {
- free(string);
- return ENDURANCE;
- }
- else if (strncmp(string, "dexerity", 7) == 0)
- {
- free(string);
- return DEXERITY;
- }
- else
- {
- free(string);
- return INVALID;
- }
- }
-}
-
-// Deallocate a player's information including the skill lists and stats:
-int deallocatePlayer(playerInfo * playerToDeallocate)
-{
- // Deallocate the skill list:
- destroyList(&(playerToDeallocate->skills));
-
- // Deallocate the stat block:
- free(playerToDeallocate->stats);
-
- // Deallocate the player:
- free(playerToDeallocate);
-
- return 0;
-}
diff --git a/src/playerdata.h b/src/playerdata.h
deleted file mode 100644
index b48bf80..0000000
--- a/src/playerdata.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// playerdata.h: Header file containing data structures for player data and function
-// prototypes for interacting with said data.
-#ifndef PLAYERDATA_H
-#define PLAYERDATA_H
-#include
-#include
-#include "areadata.h"
-#include "constants.h"
-#include "linkedlist.h"
-
-// Let the compiler know there will be structs defined elsewhere:
-typedef struct playerInfo playerInfo;
-typedef struct playerArea playerArea;
-typedef struct playerPath playerPath;
-typedef struct listNode listNode;
-typedef struct list list;
-
-// The basic information that needs to be stored for a player or creature's stats:
-typedef struct statBlock
-{
- // Levelling:
- int level;
- long experience;
-
- // Health:
- int currentHealth;
- int maxHealth;
-
- // Core Stats:
- int wits;
- int intellect;
- int strength;
- int endurance;
- int dexerity;
-
- // Character Building:
- int specPoints;
- int skillPoints;
-} statBlock;
-
-// Information about a skill, including skill levels and modifiers for the player:
-typedef struct playerSkill
-{
- char skillName[32];
- int skillPoints;
- int skillModifier;
- bool trainedSkill;
-} playerSkill;
-
-// Information about a single player's character:
-typedef struct playerInfo
-{
- playerInfo * talkingWith;
- playerArea * currentArea;
- char playerName[32];
- statBlock * stats;
- list * skills;
-} playerInfo;
-
-// An enum of the main stats of the game:
-typedef enum coreStat
-{
- WITS,
- INTELLECT,
- STRENGTH,
- ENDURANCE,
- DEXERITY,
- INVALID
-} coreStat;
-
-// Create a new skill and add it to the global skill list:
-listNode * createSkill(list * globalSkillList, char * skillName, int skillNameLength, bool trainedSkill);
-
-// Take a skill and add it to the player's skill list:
-int takeSkill(list * globalSkillList, char * skillName, int skillNameLength, playerInfo * targetPlayer);
-int takeSkillbyID(list * globalSkillList, int skillID, playerInfo * targetPlayer);
-
-// Take a string containing a core stat name and return the core stat:
-coreStat getCoreStatFromString(char * string, int stringLength);
-
-// Deallocate a player's information including the skill lists and stats:
-int deallocatePlayer(playerInfo * playerToDeallocate);
-
-#endif
diff --git a/src/queue.c b/src/queue.c
deleted file mode 100644
index 74ba8e8..0000000
--- a/src/queue.c
+++ /dev/null
@@ -1,220 +0,0 @@
-// queue.c: Implements the queue data type and associated functions for SilverMUD.
-// Barry Kane, 2022
-#include
-#include "queue.h"
-
-// Allocates and instantiates a queue:
-queue * createQueue(void)
-{
- // Allocate the memory for the queue:
- queue * newQueue = malloc(sizeof(queue));
-
- // Instantiate the variables in the data-structure:
- newQueue->itemCount = 0;
- newQueue->front = NULL;
- newQueue->back = NULL;
-
- // Create the threading constructs:
- newQueue->mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
- newQueue->condition = (pthread_cond_t)PTHREAD_COND_INITIALIZER;
-
- // Return the pointer to the new queue:
- return newQueue;
-}
-
-// Destroys a queue and all of it's members:
-void destroyQueue(queue ** queue)
-{
- // Pop everything off of the queue:
- while ((*queue)->itemCount > 0)
- {
- popQueue(*queue);
- }
-
- // Deallocate the queue:
- free(*queue);
-
- // Point the queue pointer to NULL;
- *queue = NULL;
-}
-
-// Returns the data at the front of the given queue:
-queueNode * peekQueue(queue * queue)
-{
- return queue->front;
-}
-
-// Removes the current data from the front of the queue:
-void popQueue(queue * queue)
-{
- // Check if the queue is locked, and wait:
- while (queue->lock);
-
- // Lock the queue:
- queue->lock = true;
-
- // Check there is actually anything to remove:
- if (queue->itemCount == 0)
- {
- queue->lock = false;
- return;
- }
-
- // Handle the special case of being the last item in the queue:
- else if (queue->itemCount == 1)
- {
- // Deallocate the correct data:
- switch (queue->front->type)
- {
- case EVENT:
- {
- // TODO: Implement events.
- }
- case COMMAND:
- {
- free(queue->front->data.command->command);
- free(queue->front->data.command->arguments);
- free(queue->front->data.command);
- break;
- }
- case INPUT_MESSAGE:
- {
- free(queue->front->data.inputMessage->content);
- free(queue->front->data.inputMessage);
- break;
- }
- case OUTPUT_MESSAGE:
- {
- free(queue->front->data.outputMessage->content);
- free(queue->front->data.outputMessage);
- break;
- }
- }
-
- // Deallocate the node:
- free(queue->front);
-
- // Set the correct variables for the queue:
- queue->front = NULL;
- queue->back = NULL;
- queue->itemCount = 0;
-
- // Unlock the queue:
- queue->lock = false;
-
- return;
- }
-
- // Remove the current front of the queue:
- else
- {
- // Deallocate the correct data:
- switch (queue->front->type)
- {
- case EVENT:
- {
- // TODO: Implement events.
- break;
- }
- case COMMAND:
- {
- free(queue->front->data.command->command);
- free(queue->front->data.command->arguments);
- free(queue->front->data.command);
- break;
- }
- case INPUT_MESSAGE:
- {
- free(queue->front->data.inputMessage->content);
- free(queue->front->data.inputMessage);
- break;
- }
- case OUTPUT_MESSAGE:
- {
- free(queue->front->data.outputMessage->content);
- free(queue->front->data.outputMessage);
- break;
- }
- }
-
- // Save a pointer to the current node so we don't leak it:
- queueNode * nodeToDelete = queue->front;
-
- // Advance the queue:
- queue->front = queue->front->next;
- queue->itemCount--;
-
- // Deallocate the old node:
- free(nodeToDelete);
-
- // Unlock the queue:
- queue->lock = false;
-
- return;
- }
-}
-
-// Adds data to the back of a queue:
-void pushQueue(queue * queue, void * data, queueDataType type)
-{
- // Check if the queue is locked:
- while (queue->lock);
-
- // Create a new node:
- queueNode * newNode = malloc(sizeof(queueNode));
- newNode->type = type;
- // Copy the data into the correct slot for the type:
- switch (type)
- {
- case EVENT:
- {
- // TODO: Implement events.
- break;
- }
- case COMMAND:
- {
- newNode->data.command = data;
- break;
- }
- case INPUT_MESSAGE:
- {
- newNode->data.inputMessage = data;
- break;
- }
- case OUTPUT_MESSAGE:
- {
- newNode->data.outputMessage = data;
- break;
- }
-
- }
-
- // Check if the queue is locked:
- while (queue->lock);
-
- // Lock the queue:
- queue->lock = true;
-
- // Set the correct pointers:
- newNode->next = NULL;
-
- if (queue->itemCount == 0)
- {
- queue->front = newNode;
- queue->back = newNode;
- }
- else
- {
- queue->back->next = newNode;
- queue->back = newNode;
- }
-
- // Increase the queue item count:
- queue->itemCount++;
-
- // Unlock the queue:
- queue->lock = false;
-
- // Flag that the queue was modified:
- pthread_cond_broadcast(&queue->condition);
-}
diff --git a/src/queue.h b/src/queue.h
deleted file mode 100644
index 616794c..0000000
--- a/src/queue.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// queue.h: Defines the queue data type and associated function prototypes for SilverMUD.
-// Barry Kane, 2022
-#ifndef QUEUE_H
-#define QUEUE_H
-#include "gamelogic.h"
-#include "inputoutput.h"
-
-// Forward-declare some data structures to prevent cyclic dependencies:
-typedef struct queue queue;
-
-// ========================
-// -=[ Data Structures ]=-:
-// ========================
-
-// An enum which is used to state what type of data is being stored in a queueNode:
-typedef enum queueDataType
-{
- EVENT,
- COMMAND,
- INPUT_MESSAGE,
- OUTPUT_MESSAGE
-} queueDataType;
-
-// A union for storing a pointer to all the types of data a queueNode may hold:
-typedef union queueData
-{
- outputMessage * outputMessage;
- inputMessage * inputMessage;
- commandEvent * command;
-} queueData;
-
-// A queue node, a singly-linked list node for our queue:
-typedef struct queueNode queueNode;
-typedef struct queueNode
-{
- queueDataType type;
- queueData data;
- queueNode * next;
-} queueNode;
-
-// A queue, with pointers to the head and tail of the linked list, and data for multi-threading, locking, and an item count.
-typedef struct queue
-{
- volatile bool lock;
- size_t itemCount;
- queueNode * front;
- queueNode * back;
- pthread_mutex_t mutex;
- pthread_cond_t condition;
-} queue;
-
-// ========================
-// -=[ Functions ]=-:
-// ========================
-
-// Allocates and instantiates a queue:
-queue * createQueue(void);
-
-// Destroys a queue and all of it's members:
-void destroyQueue(queue ** queue);
-
-// Returns the node at the front of the given queue:
-queueNode * peekQueue(queue * queue);
-
-// Removes the current node from the front of the queue:
-void popQueue(queue * queue);
-
-// Adds data to the back of a queue:
-void pushQueue(queue * queue, void * data, queueDataType type);
-
-#endif
diff --git a/src/schemeintegration.c b/src/schemeintegration.c
deleted file mode 100644
index f915eca..0000000
--- a/src/schemeintegration.c
+++ /dev/null
@@ -1,217 +0,0 @@
-// schemeintegration.h: Function definitions for SilverMUD's Scheme integration.
-// Barra Ó Catháin, 2023.
-#include
-#include
-#include "schemeintegration.h"
-
-// Create a player skill and add it to a given skill list from Scheme:
-SCM scheme_create_skill(SCM string, SCM skilllist)
-{
- size_t skillNameLength = 0;
- char * skillName = scm_to_latin1_stringn(string, &skillNameLength);
- createSkill(scm_to_pointer(skilllist), skillName, skillNameLength, false);
- free(skillName);
- return SCM_BOOL_T;
-}
-
-// Create a new area and add it to the list, given a name and area description, and an area list from Scheme.
-// Returns the index of the new area:
-SCM scheme_create_area(SCM area_name, SCM area_description, SCM area_list)
-{
- // Check if the area list exists:
- list * areaList = scm_to_pointer(area_list);
- if (areaList == NULL || areaList->type != AREA)
- {
- return SCM_BOOL_F;
- }
-
- // Turn the SCM values into C strings that we can use:
- char * areaName = scm_to_locale_stringn(area_name, NULL);
- char * areaDescription= scm_to_locale_stringn(area_description, NULL);
-
- // Create and add the area to the area list:
- addToList(areaList, createArea(areaName, areaDescription), AREA);
-
- // The new index of the area will be at the end of the list. Consider returning a pointer to the area:
- size_t areaIndex = areaList->itemCount - 1;
-
- // Free the strings:
- free(areaName);
- free(areaDescription);
-
- // Return the area index to Scheme for further lispy hacking:
- return scm_from_size_t(areaIndex);
-}
-
-// Create a one way path between two areas from scheme:
-SCM scheme_create_path(SCM path_name, SCM from_area_index, SCM to_area_index, SCM area_list)
-{
- // Check if the area list exists:
- list * areaList = scm_to_pointer(area_list);
- if (areaList == NULL || areaList->type != AREA)
- {
- return SCM_BOOL_F;
- }
-
- // Check if the areas exist:
- playerArea * fromArea = getFromList(areaList, scm_to_size_t(from_area_index))->area;
- playerArea * toArea = getFromList(areaList, scm_to_size_t(to_area_index))->area;
-
- if (fromArea == NULL || toArea == NULL)
- {
- return SCM_BOOL_F;
- }
-
- // Turn the SCM value into a C string that we can use:
- char * pathName = scm_to_locale_stringn(path_name, NULL);
-
- // Create the path:
- createOneWayPath(fromArea, toArea, pathName);
-
- // Free the string:
- free(pathName);
-
- // Return true to Scheme:
- return SCM_BOOL_T;
-}
-
-// Change the name of an existing area in a list, given the number of the area in the list, from Scheme:
-SCM scheme_change_area_name(SCM new_name, SCM area_number, SCM area_list)
-{
- // Check if the area exists:
- list * areaList = scm_to_pointer(area_list);
- size_t areaNumber = scm_to_size_t(area_number);
-
- if (areaList->type != AREA)
- {
- return SCM_BOOL_F;
- }
-
- playerArea * area = getFromList(areaList, areaNumber)->area;
-
- if (area == NULL)
- {
- return SCM_BOOL_F;
- }
-
- // Create a string from the Scheme string and copy it into the area:
- size_t newNameLength = 0;
- char * newName = scm_to_locale_stringn(new_name, &newNameLength);
- memset(area->areaName, 0, 32);
- if (newNameLength > 32)
- {
- memcpy(area->areaName, newName, 31);
- area->areaName[31] = '\0';
- }
- else
- {
- memcpy(area->areaName, newName, newNameLength);
- area->areaName[31] = '\0';
- }
-
- free(newName);
-
- return SCM_BOOL_T;
-}
-
-// Change the description of an existing area in a list, given the number of the area in the list, from Scheme:
-SCM scheme_change_area_description(SCM new_description, SCM area_number, SCM area_list)
-{
- // Check if the area exists:
- list * areaList = scm_to_pointer(area_list);
- size_t areaNumber = scm_to_size_t(area_number);
-
- if (areaList->type != AREA)
- {
- return SCM_BOOL_F;
- }
-
- playerArea * area = getFromList(areaList, areaNumber)->area;
-
- if (area == NULL)
- {
- return SCM_BOOL_F;
- }
-
- // Create a string from the Scheme string and copy it into the area:
- size_t newDescriptionLength = 0;
- char * newDescription = scm_to_locale_stringn(new_description, &newDescriptionLength);
- memset(area->areaDescription, 0, MAX - 35);
- if (newDescriptionLength > MAX - 35)
- {
- memcpy(area->areaDescription, newDescription, MAX - 35);
- area->areaDescription[MAX - 36] = '\0';
- }
- else
- {
- memcpy(area->areaDescription, newDescription, newDescriptionLength);
- area->areaDescription[MAX - 36] = '\0';
- }
-
- free(newDescription);
-
- return SCM_BOOL_T;
-}
-
-// Message every currently connected player from Scheme:
-SCM scheme_message_everyone(SCM sender_name, SCM message_content, SCM output_queue)
-{
- // Allocate the memory for the needed data structures:
- outputMessage * newOutputMessage = calloc(1, sizeof(userMessage));
- userMessage * newMessage = calloc(1, sizeof(userMessage));
-
- // Set some basic information for the output message, allowing it to be sent to everyone:
- newOutputMessage->content = newMessage;
- newOutputMessage->recipientsCount = 0;
- newOutputMessage->recipients = NULL;
-
- // Convert the Scheme strings to C strings, and ensure they're NULL terminated:
- scm_to_locale_stringbuf(sender_name, newMessage->senderName, 31);
- newMessage->senderName[31] = '\0';
- scm_to_locale_stringbuf(message_content, newMessage->messageContent, MAX - 1);
- newMessage->messageContent[MAX - 1] = '\0';
-
- // Clean up the message contents to ensure they're safe to send and display correctly:
- userNameSanatize(newMessage->senderName, 32);
- userInputSanatize(newMessage->messageContent, MAX);
-
- // Push it to the queue, where it will be handled and de-allocated:
- pushQueue(scm_to_pointer(output_queue), newOutputMessage, OUTPUT_MESSAGE);
-
- // Return a Scheme #t value:
- return SCM_BOOL_T;
-}
-
-// The function ran by the Scheme thread which handles all game-master and interpreter interaction:
-void * schemeHandler(void * parameters)
-{
- // Take in the needed values from the main thread and make it back into the struct:
- SchemeThreadParameters * schemeThreadParameters = parameters;
-
- // Initialize GNU Guile:
- scm_init_guile();
-
- // Register the various functions:
- scm_c_define_gsubr("create-area", 3, 0, 0, &scheme_create_area);
- scm_c_define_gsubr("create-path", 4, 0, 0, &scheme_create_path);
- scm_c_define_gsubr("create-skill", 2, 0, 0, &scheme_create_skill);
- scm_c_define_gsubr("message-everyone", 3, 0, 0, &scheme_message_everyone);
- scm_c_define_gsubr("change-area-name", 3, 0, 0, &scheme_change_area_name);
- scm_c_define_gsubr("change-area-description", 3, 0, 0, &scheme_change_area_description);
-
- // Define the various game state pointers as Scheme objects:
- scm_c_define("area-list", scm_from_pointer(schemeThreadParameters->areaList, NULL));
- scm_c_define("skill-list", scm_from_pointer(schemeThreadParameters->skillList, NULL));
- scm_c_define("output-queue", scm_from_pointer(schemeThreadParameters->outputQueue, NULL));
-
- // Enable readline support:
- scm_c_eval_string("(begin (use-modules (ice-9 readline)) (activate-readline))");
- scm_c_eval_string("(begin (use-modules (system repl server)) (if (file-exists? \"silvermud-repl\") (delete-file \"silvermud-repl\")) (spawn-server (make-unix-domain-server-socket #:path \"silvermud-repl\")))");
-
- // Drop into the Scheme interpreter:
- scm_shell(0, NULL);
-
- // Return NULL. This should be unreachable.
- return NULL;
-}
-
diff --git a/src/schemeintegration.h b/src/schemeintegration.h
deleted file mode 100644
index 9f20f25..0000000
--- a/src/schemeintegration.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// schemeintegration.h: Data-structures and function prototypes for SilverMUD's Scheme integration.
-// Barra Ó Catháin, 2023.
-#ifndef SCHEMEINTEGRATION_H
-#define SCHEMEINTEGRATION_H
-#include "queue.h"
-#include "linkedlist.h"
-
-typedef struct list list;
-typedef struct queue queue;
-
-typedef struct SchemeThreadParameters
-{
- list * areaList, * skillList;
- queue * inputQueue, * outputQueue;
-} SchemeThreadParameters;
-
-void * schemeHandler(void * parameters);
-
-#endif
diff --git a/src/server/SilverMUDServer.c b/src/server/SilverMUDServer.c
deleted file mode 100644
index c861cf7..0000000
--- a/src/server/SilverMUDServer.c
+++ /dev/null
@@ -1,378 +0,0 @@
-// Silverkin Industries Comm-Link Server, Engineering Sample Alpha 0.5
-// PROJECT CODENAME: WHAT DO I PAY YOU FOR? | Level-3 Clearance.
-// Barry Kane, 2021
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "../queue.h"
-#include "../areadata.h"
-#include "../gamelogic.h"
-#include "../constants.h"
-#include "../playerdata.h"
-#include "../linkedlist.h"
-#include "../texteffects.h"
-#include "../inputoutput.h"
-#include "../schemeintegration.h"
-
-typedef struct sockaddr sockaddr;
-void sigintHandler(int signal)
-{
- printf("Caught signal %d.\n", signal);
- exit(EXIT_SUCCESS);
-}
-
-int main(int argc, char ** argv)
-{
- time_t currentTime;
- unsigned delay = 800;
- int socketFileDesc, connectionFileDesc, length, clientsAmount,
- socketCheck, activityCheck;
- fd_set connectedClients;
- pthread_t gameLogicThread, outputThread, schemeThread;
- int clientSockets[PLAYERCOUNT];
- userMessage sendBuffer, receiveBuffer;
- playerInfo connectedPlayers[PLAYERCOUNT];
- char testString[32] = "Hehe.";
- struct sockaddr_in serverAddress, clientAddress;
- char motd[2048] = "Please login with the /join command.";
- queue * inputQueue = createQueue(), * outputQueue = createQueue();
-
- // Parse command-line options:
- int currentopt = 0;
- while ((currentopt = getopt(argc, argv, "d:m:")) != -1)
- {
- switch(currentopt)
- {
- case 'd':
- {
- delay = atoi(optarg);
- break;
- }
- case 'm':
- {
- strncpy(motd, optarg, 2047);
- motd[2047] = '\0';
- break;
- }
- }
- }
-
- // Set the handler for SIGINT:
- signal(2, sigintHandler);
-
- // -==[ TEST GAME-STATE INITIALIZATION ]==-
- // Initialize test areas:
- list * areas = createList(AREA);
- addToList(areas, createArea("Login Area", motd), AREA);
-
- // Create the areas:
- addToList(areas, createArea("Octal One - Docking Bay Alpha",
- "You are standing in the main docking bay of the largest station in the Octal System. "
- "The sheer size of the bay is awe-inpiring. The number of ships is endless. "
- "The bay is curved along with the body of the station. A catwalk runs along the back wall of the bay. "
- "Two large arches lie at each end, leading to the other bays, and in the center, a set of doors leading to the interior of the station."), AREA);
-
- addToList(areas, createArea("Octal One - Station Access Control",
- "You enter into the hallway leading to the main interior of the station."
- "The attendant informs you that due to a computer error, exits cannot be proccessed at the moment,"
- " so you will be unable to leave, until it is resolved. "
- "He apologizes profusely for the inconvenience, and clears you for entry if you wish to continue."), AREA);
-
- addToList(areas, createArea("Octal One - Floor Zero",
- "You've never quite seen so many people in one place. A large ring of shopfronts surrounds an area filled with benches and tables. "
- "There's so many buisnesses in sight that you feel you could find everything you need, and this is only one of 25 main floors, "
- "not to mention the 6 outer pylons which surround the main hull of the station. Staircases lead to an upper platform allowing access to the pylons. "), AREA);
-
- // Initialize test paths:
- createPath(getFromList(areas, 1)->area, getFromList(areas, 2)->area,
- "Enter the station interior.", "Return to Docking Bay Alpha.");
- createOneWayPath(getFromList(areas, 2)->area, getFromList(areas, 3)->area,
- "Continue to station interior. ");
-
- list * globalSkillList = createList(SKILL);
-
- // Create a few basic skills:
- createSkill(globalSkillList, "Medicine", 8, true);
- createSkill(globalSkillList, "Lockpicking", 12, true);
- createSkill(globalSkillList, "Programming", 12, true);
- createSkill(globalSkillList, "Sensor Reading", 14, false);
- createSkill(globalSkillList, "Starship Piloting", 17, true);
- createSkill(globalSkillList, "Mechanical Repair", 17, true);
-
- // Initialize playerdata:
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- sprintf(testString, "UNNAMED %d", index);
- // OH NO IT'S NOT MEMORY SAFE BETTER REWRITE IT IN RUST
- // But wait, we know the string won't be too big, so it's fine.
- strcpy(connectedPlayers[index].playerName, testString);
- connectedPlayers[index].currentArea = getFromList(areas, 0)->area;
- connectedPlayers[index].stats = calloc(1, sizeof(statBlock));
- connectedPlayers[index].stats->specPoints = 30;
- connectedPlayers[index].stats->skillPoints = 30;
- connectedPlayers[index].skills = createList(SKILL);
- }
-
- // -==[ TEST GAME-STATE INITIALIZATION END ]==-
-
- // Give an intro: Display the Silverkin Industries logo and splash text.
- slowPrint(logostring, delay);
- slowPrint("\n--==== \033[33;40mSILVERKIN INDUSTRIES\033[0m COMM-LINK SERVER ====--\nVersion Alpha 0.5\n", delay);
-
- // Seed random number generator from the current time:
- srand((unsigned)time(¤tTime));
-
- // Initialize the sockets to 0, so we don't crash.
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- clientSockets[index] = 0;
- }
-
- // Get a socket and make sure we actually get one.
- socketFileDesc = socket(AF_INET, SOCK_STREAM, 0);
- if (socketFileDesc == -1)
- {
- fprintf(stderr, "\tSocket Creation is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
- exit(0);
- }
-
- else
- {
- slowPrint("\tSocket Creation is:\t\033[32;40mGREEN.\033[0m\n", delay);
- }
-
- memset(&serverAddress, 0, sizeof(serverAddress));
-
- // Assign IP and port:
- serverAddress.sin_family = AF_INET;
- serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
- serverAddress.sin_port = htons(PORT);
-
- // Binding newly created socket to given IP, and checking it works:
- if ((bind(socketFileDesc, (sockaddr*)&serverAddress, sizeof(serverAddress))) != 0)
- {
- fprintf(stderr, "\tSocket Binding is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
- exit(0);
- }
-
- else
- {
- slowPrint("\tSocket Binding is:\t\033[32;40mGREEN.\033[0m\n", delay);
- }
-
- // Let's start listening:
- if ((listen(socketFileDesc, PLAYERCOUNT)) != 0)
- {
- fprintf(stderr, "\tServer Listener is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
- exit(EXIT_FAILURE);
- }
- else
- {
- slowPrint("\tServer Listener is:\t\033[32;40mGREEN.\033[0m\n", delay);
- }
- length = sizeof(clientAddress);
-
- // Declare the needed variables for TLS sessions:
- gnutls_session_t tlssessions[PLAYERCOUNT];
- gnutls_anon_server_credentials_t serverkey = NULL;
- gnutls_anon_allocate_server_credentials(&serverkey);
- gnutls_anon_set_server_known_dh_params(serverkey, GNUTLS_SEC_PARAM_MEDIUM);
-
- // Initialize all the TLS sessions to NULL: We use this to check if it's an "empty connection."
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- tlssessions[index] = NULL;
- if (gnutls_init(&tlssessions[index], GNUTLS_SERVER) < 0)
- {
- fprintf(stderr, "\tTLS Sessions Initialization is:\t\033[33;40mRED.\033[0m Aborting launch.\n");
- exit(EXIT_FAILURE);
- }
- gnutls_priority_set_direct(tlssessions[index], "NORMAL:+ANON-ECDH:+ANON-DH", NULL);
- gnutls_credentials_set(tlssessions[index], GNUTLS_CRD_ANON, &serverkey);
- gnutls_handshake_set_timeout(tlssessions[index], GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
- }
- slowPrint("\tTLS Preparation is:\t\033[32;40mGREEN.\033[0m\n", delay);
-
- // Prepare the game logic thread:
- gameLogicParameters * gameLogicThreadParameters = malloc(sizeof(gameLogicParameters));
- gameLogicThreadParameters->connectedPlayers = connectedPlayers;
- gameLogicThreadParameters->playerCount = &clientsAmount;
- gameLogicThreadParameters->globalSkillList = globalSkillList;
- gameLogicThreadParameters->outputQueue = outputQueue;
- gameLogicThreadParameters->inputQueue = inputQueue;
- gameLogicThreadParameters->areaList = areas;
- pthread_create(&gameLogicThread, NULL, &gameLogicHandler, gameLogicThreadParameters);
-
- slowPrint("\tEvent Thread is:\t\033[32;40mGREEN.\033[0m\n", delay);
-
- // Prepare the output queue thread:
- outputThreadParameters * outputParameters = malloc(sizeof(outputThreadParameters));
- outputParameters->outputQueue = outputQueue;
- outputParameters->tlssessions = tlssessions;
- outputParameters->connectedPlayers = connectedPlayers;
- pthread_create(&outputThread, NULL, &outputThreadHandler, outputParameters);
- slowPrint("\tOutput Thread is:\t\033[32;40mGREEN.\033[0m\n", delay);
-
- // Prepare the Scheme handler thread:
- SchemeThreadParameters * schemeParameters = malloc(sizeof(SchemeThreadParameters));
- schemeParameters->skillList = globalSkillList;
- schemeParameters->outputQueue = outputQueue;
- schemeParameters->areaList = areas;
- slowPrint("\tScheme Thread is:\t\033[32;40mGREEN.\033[0m\n", delay);
- slowPrint("=====\n", delay);
- pthread_create(&schemeThread, NULL, &schemeHandler, schemeParameters);
-
- while(true)
- {
- // Clear the set of file descriptors and add the master socket:
- FD_ZERO(&connectedClients);
- FD_SET(socketFileDesc, &connectedClients);
- clientsAmount = socketFileDesc;
-
- // Find all sockets that are still working and place them in the set:
- for(int index = 0; index < PLAYERCOUNT; index++)
- {
- // Just get the one we're working with to another name:
- socketCheck = clientSockets[index];
-
- // If it's working, bang it into the list:
- if(socketCheck > 0)
- {
- FD_SET(socketCheck, &connectedClients);
- }
- // The amount of clients is needed for select():
- if(socketCheck > clientsAmount)
- {
- clientsAmount = socketCheck;
- }
- }
-
- // See if a connection is ready to be interacted with:
- activityCheck = select((clientsAmount + 1), &connectedClients, NULL, NULL, NULL);
-
- // Check if select() worked:
- if ((activityCheck < 0) && (errno != EINTR))
- {
- fprintf(stderr, "Error in select(), retrying.\n");
- }
-
- // If it's the master socket selected, there is a new connection:
- if (FD_ISSET(socketFileDesc, &connectedClients))
- {
- if ((connectionFileDesc = accept(socketFileDesc, (struct sockaddr *)&clientAddress, (socklen_t*)&length)) < 0)
- {
- fprintf(stderr, "Failed to accept connection. Aborting.\n");
- exit(EXIT_FAILURE);
- }
- // See if we can put in the client:
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- // When there is an empty slot, pop it in:
- if (clientSockets[index] == 0)
- {
- volatile int handshakeReturnValue = 0;
- clientSockets[index] = connectionFileDesc;
- gnutls_transport_set_int(tlssessions[index], clientSockets[index]);
- do
- {
- handshakeReturnValue = gnutls_handshake(tlssessions[index]);
- } while (handshakeReturnValue < 0 && gnutls_error_is_fatal(handshakeReturnValue) == 0);
-
- // If it's good, send them the welcome message:
- if(handshakeReturnValue == 0)
- {
- // Send a greeting message:
- memcpy(sendBuffer.senderName, "\0 Login > \0", 11);
- strcpy(sendBuffer.messageContent, "Welcome to the server!");
- messageSend(tlssessions[index], &sendBuffer);
- strcpy(receiveBuffer.messageContent, "/look");
-
- // Allocate the memory for a new input message:
- inputMessage * newMessage = malloc(sizeof(inputMessage));
- newMessage->content = malloc(sizeof(userMessage));
-
- // Copy in the correct data:
- memcpy(newMessage->content, &receiveBuffer, sizeof(userMessage));
- newMessage->sender = &connectedPlayers[index];
-
- // Push the new message onto the queue:
- pushQueue(inputQueue, newMessage, INPUT_MESSAGE);
- break;
- }
-
- // If it's not good, close it, we don't want it:
- shutdown(clientSockets[index], 2);
- close(clientSockets[index]);
- clientSockets[index] = 0;
- break;
- }
- }
- }
- // Otherwise, it's a client we need to interact with:
- else
- {
- for (int index = 0; index < PLAYERCOUNT; index++)
- {
- socketCheck = clientSockets[index];
-
- if(FD_ISSET(socketCheck, &connectedClients))
- {
- int returnVal = messageReceive(tlssessions[index], &receiveBuffer);
- // If player has disconnected:
- if(returnVal == -10 || returnVal == 0)
- {
- // Close the session:
- gnutls_bye(tlssessions[index], GNUTLS_SHUT_WR);
- gnutls_deinit(tlssessions[index]);
- shutdown(clientSockets[index], 2);
- close(clientSockets[index]);
- clientSockets[index] = 0;
- tlssessions[index] = NULL;
-
- // Clear out the old player state so that a new one may join:
- sprintf(testString, "UNNAMED %d", index);
- strcpy(connectedPlayers[index].playerName, testString);
- connectedPlayers[index].currentArea = getFromList(areas, 0)->area;
-
- // Prepare a fresh SSL session for the next new player:
- gnutls_init(&tlssessions[index], GNUTLS_SERVER);
- gnutls_priority_set_direct(tlssessions[index], "NORMAL:+ANON-ECDH:+ANON-DH", NULL);
- gnutls_credentials_set(tlssessions[index], GNUTLS_CRD_ANON, &serverkey);
- gnutls_handshake_set_timeout(tlssessions[index], GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
- }
- // Otherwise, they've sent a message:
- else
- {
- // Allocate the memory for a new input message:
- inputMessage * newMessage = malloc(sizeof(inputMessage));
- newMessage->content = malloc(sizeof(userMessage));
-
- // Copy in the correct data:
- memcpy(newMessage->content, &receiveBuffer, sizeof(userMessage));
- newMessage->sender = &connectedPlayers[index];
-
- // Push the new message onto the queue:
- pushQueue(inputQueue, newMessage, INPUT_MESSAGE);
- }
- }
- }
- }
- }
- pthread_cancel(gameLogicThread);
- pthread_cancel(outputThread);
- exit(EXIT_SUCCESS);
-}
diff --git a/src/texteffects.c b/src/texteffects.c
deleted file mode 100644
index 7cdaf57..0000000
--- a/src/texteffects.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// texteffects.c: Implementation of text effect library for SilverMUD.
-// Barry Kane, 2021.
-#include
-#include
-#include
-#include
-
-// A character by character print, similar to a serial terminal with lower baud rate:
-void slowPrint(const char * stringToPrint, int delay)
-{
- int characterIndex = 0;
- while (stringToPrint[characterIndex] != '\0')
- {
- putchar(stringToPrint[characterIndex]);
- // Flush the buffer so there's no line buffering.
- fflush(stdout);
- usleep(delay);
- characterIndex++;
- }
-}
-
-// The same, altered to work with ncurses:
-void slowPrintNcurses(const char * stringToPrint, int delay, WINDOW * window, bool bolded)
-{
- int characterIndex = 0;
- if (bolded)
- {
- wattron(window, A_BOLD);
- }
- while (stringToPrint[characterIndex] != '\0')
- {
- waddch(window, stringToPrint[characterIndex]);
- // Refresh the ncurses screen.
- wrefresh(window);
- usleep(delay);
- characterIndex++;
- }
- if (bolded)
- {
- wattroff(window, A_BOLD);
- }
- wrefresh(window);
-}
-
-// A character by character "brute-force" print, similar to Hollywood hacking scenes:
-void bruteforcePrint(const char * stringToPrint, int delay)
-{
- unsigned int characterIndex = 0;
- while (stringToPrint[characterIndex] != '\0')
- {
- for(unsigned char currentCharacter = 32; currentCharacter <= stringToPrint[characterIndex]; currentCharacter++)
- {
- putchar(stringToPrint[currentCharacter]);
- fflush(stdout);
- usleep(delay);
- putchar(8);
- fflush(stdout);
- }
- putchar(stringToPrint[characterIndex]);
- characterIndex++;
- }
-}
-
-// The same, altered to work with ncurses:
-void bruteforcePrintNcurses(const char * stringToPrint, int delay, WINDOW * window, bool bolded)
-{
- int characterIndex = 0;
- if (bolded)
- {
- wattron(window, A_BOLD);
- }
- while (stringToPrint[characterIndex] != '\0')
- {
- for(char currentCharacter = 32; currentCharacter <= stringToPrint[characterIndex]; currentCharacter++)
- {
- waddch(window, currentCharacter);
- wrefresh(window);
- usleep(delay);
- waddch(window, 8);
- wrefresh(window);
- }
- waddch(window, stringToPrint[characterIndex]);
- characterIndex++;
- }
- if (bolded)
- {
- wattroff(window, A_BOLD);
- }
- wrefresh(window);
-}
-
-// Word-wrap a string to a given width:
-void wrapString(char * stringToWrap, int stringLength, int screenWidth)
-{
- int characterCount = 0;
- for(int index = 0; index < stringLength; index++)
- {
- if (stringToWrap[index] == '\n')
- {
- characterCount = 0;
- }
- else
- {
- characterCount++;
- }
- if (characterCount == screenWidth)
- {
- while (!isspace(stringToWrap[index]) && index > 0)
- {
- index--;
- }
- if (index == 0)
- {
- return;
- }
- stringToWrap[index] = '\n';
- index++;
- characterCount = 0;
- }
- }
-}
diff --git a/src/texteffects.h b/src/texteffects.h
deleted file mode 100644
index 37292c4..0000000
--- a/src/texteffects.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// texteffects.h: Header file for the texteffects library for SilverMUD.
-// Barry Kane, 2021.
-#ifndef TEXTEFFECTS_H_
-#define TEXTEFFECTS_H_
-#include
-#include
-
-// A character by character print, similar to a serial terminal with lower baud rate:
-void slowPrint(const char * stringToPrint, int delay);
-
-// The same, altered to work with ncurses:
-void slowPrintNcurses(const char * stringToPrint, int delay, WINDOW * window, bool bolded);
-
-// A character by character "brute-force" print, similar to Hollywood hacking scenes:
-void bruteforcePrint(const char * stringToPrint, int delay);
-
-// The same, altered to work with ncurses:
-void bruteforcePrintNcurses(const char * stringToPrint, int delay, WINDOW * window, bool bolded);
-
-// Word-wrap a string to a given width:
-void wrapString(char * stringToWrap, int stringLength, int screenWidth);
-
-// A string containing an ASCII art version of the Silverkin Industries logo.
-const char * logostring =
- " ///////\n"
- " //////////////////////////////////////////\n"
- " ///////////////////////////////////////////////////////////\n"
- " ////////// ////////////////////////////\n"
- " ### # # # # ##### ### # # # # # /////////////////\n"
- " ## # # # # ## # # ### # ## # //////////////\n"
- " ## # # # # # ### # # # # # # /////////\n"
- " ### # ### # ##### # # # # # # # ///////\n"
- " # ## # ##### # # ### ### ### # ##### ### //////\n"
- " # # # # # # # # ## # # # # ## ## ////\n"
- " # # # # # # # # ## # ### # # ## //\n"
- " # # ### ##### ##### ### # # # # #### ### /\n";
-
-#endif
diff --git a/tests/list-test.c b/tests/list-test.c
deleted file mode 100644
index 94f3db1..0000000
--- a/tests/list-test.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "../src/linkedlist.h"
-#include
-
-static inline void printAreaList(list * areaList)
-{
- listData * currentData;
- for(int index = 0; index < areaList->itemCount; index++)
- {
- currentData = getFromList(areaList, index);
- printf("%d\t| %s - %s\n", index, currentData->area->areaName, currentData->area->areaDescription);
- }
-}
-
-void main()
-{
- list * areaList = createList(AREA);
- char areaName[256];
- char areaDescription[256];
-
- printf("\n--==[ Generating a list of ten items. ]==--\n\n");
- for(int count = 1; count <= 10; count++)
- {
- sprintf(areaName, "Area %d", count);
- sprintf(areaDescription, "This is Area %d.", count);
-
- addToList(areaList, createArea(areaName, areaDescription) , AREA);
- }
- printAreaList(areaList);
-
- printf("\n--==[ Inserting items into specific indexes. ]==--\n\n");
- insertIntoList(areaList, createArea("Cool, it worked.", "Cool, it worked."), AREA, 0);
- insertIntoList(areaList, createArea("Cool, it worked.", "Cool, it worked."), AREA, 6);
- insertIntoList(areaList, createArea("Cool, it worked.", "Cool, it worked."), AREA, 11);
- printAreaList(areaList);
-
- printf("\n--==[ Removing certain areas from the list. ]==--\n\n");
- removeFromList(areaList, AREA, 12);
- removeFromList(areaList, AREA, 6);
- removeFromList(areaList, AREA, 0);
-
- printAreaList(areaList);
-
- destroyList(&areaList);
- printf("");
-}
-
diff --git a/tests/queue-test.c b/tests/queue-test.c
deleted file mode 100644
index d248f9c..0000000
--- a/tests/queue-test.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// Test for the queue type in SilverMUD:
-#include
-#include
-#include
-#include "../src/queue.h"
-
-#define formatBoolean(b) ((b) ? "true" : "false")
-#define formatEquality(b) ((b) ? "equal" : "not equal")
-
-int main(void)
-{
- // Create a queue:
- printf("-=[ Creating queue ]=-:\n");
- queue * testQueue = createQueue();
-
- // Check that the queue has the correct values:
- printf("-=[ Checking initial values ]=-:\n");
-
- printf("- Item count should be 0:\n");
- assert(testQueue->itemCount == 0);
- printf("Item count is %d.\n\n", testQueue->itemCount);
-
- printf("- Lock should be false:\n");
- assert(testQueue->lock == false);
- printf("Lock is %s.\n\n", formatBoolean(testQueue->lock));
-
- printf("- Front should be (nil):\n");
- assert(testQueue->front == NULL);
- printf("Front is %p.\n\n", testQueue->front);
-
- printf("- Back should be (nil):\n");
- assert(testQueue->back == NULL);
- printf("Back is %p.\n\n", testQueue->front);
-
- // Create some items for the queue:
- inputMessage * testInputMessage = malloc(sizeof(inputMessage));
- testInputMessage->sender = NULL;
- testInputMessage->next = NULL;
- testInputMessage->content = malloc(sizeof(userMessage));
- strcpy(testInputMessage->content->senderName,"Queue Test Input Sender");
- strcpy(testInputMessage->content->messageContent, "Queue Test Input Content - Hello!");
-
- outputMessage * testOutputMessage = malloc(sizeof(outputMessage));
- for(int index = 0; index < PLAYERCOUNT; index++)
- {
- testOutputMessage->targets[index] = NULL;
- }
- testOutputMessage->next = NULL;
- testOutputMessage->content = malloc(sizeof(userMessage));
- strcpy(testOutputMessage->content->senderName, "Queue Test Output Sender");
- strcpy(testOutputMessage->content->messageContent, "Queue Test Output Content - World!");
-
- commandEvent * testCommandEvent = malloc(sizeof(commandEvent));
- testCommandEvent->next = NULL;
- testCommandEvent->caller = NULL;
- testCommandEvent->command = malloc(5 * sizeof(char));
- testCommandEvent->arguments = malloc(15 * sizeof(char));
- strcpy(testCommandEvent->command, "Test");
- strcpy(testCommandEvent->arguments, "Test Arguments");
-
- // Add them to the queue:
- printf("-=[ Adding items to the queue ]=-:\n");
- printf("- First item, Item count should be 1. Front and Back should be equal.\n");
- pushQueue(testQueue, testInputMessage, INPUT_MESSAGE);
- assert(testQueue->itemCount == 1);
- assert(testQueue->front == testQueue->back);
- printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
- formatEquality(testQueue->front == testQueue->back));
-
- printf("- Second item, Item count should be 2. Front and Back should be not equal.\n");
- pushQueue(testQueue, testOutputMessage, OUTPUT_MESSAGE);
- assert(testQueue->itemCount == 2);
- assert(testQueue->front != testQueue->back);
- printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
- formatEquality(testQueue->front == testQueue->back));
-
- printf("- Third item, Item count should be 3. Front and Back should be not equal.\n");
- pushQueue(testQueue, testCommandEvent, COMMAND);
- assert(testQueue->itemCount == 3);
- assert(testQueue->front != testQueue->back);
- printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
- formatEquality(testQueue->front == testQueue->back));
-
- printf("-=[ Checking items and popping from queue ]=-:\n");
- printf("- First item peeked should point to testInputMessage.\n");
- assert(peekQueue(testQueue)->data.inputMessage == testInputMessage);
- printf("Peeked data is located at: %p, testInputMessage is located at: %p.\n\n",
- peekQueue(testQueue)->data.inputMessage, testInputMessage);
-
- printf("- Popping first item, Item count should be 2, Front and Back should not be equal.\n");
- popQueue(testQueue);
- assert(testQueue->itemCount == 2);
- assert(testQueue->front != testQueue->back);
- printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
- formatEquality(testQueue->front == testQueue->back));
-
- printf("- Second item peeked should point to testOutputMessage.\n");
- assert(peekQueue(testQueue)->data.outputMessage == testOutputMessage);
- printf("Peeked data is located at: %p, testOutputMessage is located at: %p.\n\n",
- peekQueue(testQueue)->data.outputMessage, testOutputMessage);
-
- printf("- Popping second item, Item count should be 1, Front and Back should be equal.\n");
- popQueue(testQueue);
- assert(testQueue->itemCount == 1);
- assert(testQueue->front == testQueue->back);
- printf("Item count is: %d, Front and Back are %s.\n\n", testQueue->itemCount,
- formatEquality(testQueue->front == testQueue->back));
-
- printf("- Third item peeked should point to testCommandEvent.\n");
- assert(peekQueue(testQueue)->data.command == testCommandEvent);
- printf("Peeked data is located at: %p, testCommandEvent is located at: %p.\n\n",
- peekQueue(testQueue)->data.command, testCommandEvent);
-
- printf("- Popping third item:\n");
- popQueue(testQueue);
-
- printf("- Item count should be 0:\n");
- assert(testQueue->itemCount == 0);
- printf("Item count is %d.\n\n", testQueue->itemCount);
-
- printf("- Lock should be false:\n");
- assert(testQueue->lock == false);
- printf("Lock is %s.\n\n", formatBoolean(testQueue->lock));
-
- printf("- Front should be (nil):\n");
- assert(testQueue->front == NULL);
- printf("Front is %p.\n\n", testQueue->front);
-
- printf("- Back should be (nil):\n");
- assert(testQueue->back == NULL);
- printf("Back is %p.\n\n", testQueue->front);
-}