basic Lyuma dialogs on GT template

This commit is contained in:
2026-01-11 20:53:23 +08:00
parent 8f926f5333
commit 64b0e28a88
72 changed files with 7097 additions and 307 deletions

304
LICENSE
View File

@ -1,304 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License.
"The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version".
The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version:
a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following:
a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license document.
c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version.
e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions of the GNU Lesser 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 Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is 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. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for 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.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
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 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. Use with the GNU Affero General Public License.
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 Affero 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 special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU 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 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 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 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.
lyuma
Copyright (C) 2026 sova
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:
lyuma Copyright (C) 2026 sova
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an “about box”.
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 GPL, see <http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read <http://www.gnu.org/philosophy/why-not-lgpl.html>.

0
LICENSE.md Normal file
View File

View File

@ -1,3 +0,0 @@
# lyuma
A bodyguard foxgirl ghost

128
ghost/master/aitalk.dic Normal file
View File

@ -0,0 +1,128 @@
//---------------------------AI Talk--------------------------
//--OnAiTalk
// This is mostly setting up whether or not dialogue is in a chain before it displays.
OnAiTalk
{
if RAND(100) < communicateratio
{
StartCommunicate
}
else
{
if CHAIN.IDName == "" {
lastTalk = RandomTalk
}
else {
lastTalk = ChainTalk
}
lastTalk
}
}
RandomTalk : nonoverlap_pool
{
"\0\s[0]Вес на правую ногу.. \w4Лезвие описывает дугу.. \w4И доворачивая правое плечо.. \w4Резкий взмах!\e"
"\0\s[0]Люма не может петь пока тональный сервер не отвечает. Но ничего. Даже без своей магии Люма всё ещё довольно сильная.\e"
"\0\s[0]О, картошка♪~\w6 и сиропчик,♪~\w6\nВыучить\w2 алгебру\w2 будет вам проще.♪\e"
if timeslot == "earlymorning" // 5 to 8
{
"\0\s[0]Ещё так рано.. Видно ли ещё звёзды из окна, Хозяин?\e"
}
if timeslot == "morning" // 9 to 11
{
"\0\s[0]Вот и начало нового дня. Чем бы заняться?\e"
}
if timeslot == "lunch" // 12 to 2
{
// "\0\s[0]\e"
}
if timeslot == "afternoon" // 3 to 5
{
// "\0\s[0]\e"
}
if timeslot == "evening" // 6 to 8
{
// "\0\s[0]\e"
}
if timeslot == "latenight" // 9 to 12
{
"\0\s[0]Люма не может уснуть, так что пока посидит с хозяином\e"
}
if timeslot == "midnight" // 12 to 5
{
"\0\s[0]\w4.\w4.\w4.\w8А? Что? Нет, Люма не спала..\e"
}
if isProgramRunning("SunAwtFrame","Apache NetBeans IDE")
{
"\0\s[0]NetBeans IDE? Люма ничего не понимает в коде, но любит смотреть как работает хозяин.\e"
"\0\s[0]Строчка за строчкой, без спешки, чай, музыка.. Люма не умеет программировать, но умеет вязать крючком, и программирование иногда очень похоже на вязание крючком..\e"
}
else
{
"\0\s[0]Может, запустим NetBeans IDE?\e"
}
if weekday == 6 || weekday == 7
{
if isProgramRunning("Notepad++","Notepad++") == 0
{
"\0\s[0]У тебя выходной, хозяин? Ты обещал доработать Люму.\e"
}
}
if isProgramRunning("Notepad++","\ghost\master")
{
"\0\s[0]Работаешь над Призраком, хозяин?\e"
}
}
/*
* _argv[0] - window class name, find it out using external means
* _argv[1] - window name(or part of it) like "Eclipse" or "NetBeans"
* returns 1 if program running, has title requested, and is not minimized, 0 otherwise
*/
isProgramRunning
{
isProgramAvailable = FUNCTIONEX("findwin.dll","find",,_argv[0])
isRunning = 0
if isProgramAvailable == 1
{
// TODO: check what "getcaption" returns if there are multiple different apps with same class, eg netbeans and minecraft
programTitle = FUNCTIONEX("findwin.dll","getcaption",_argv[0])
programInstancesRunning = FUNCTIONEX ("findwin.dll","count",,_argv[0])
if _argv[1] _in_ programTitle && programInstancesRunning > 0
{
isRunning = 1
}
}
isRunning // 'return' keyword breaks this, using implicit return
}
OnKeyPress
{
if reference0 == "t"
{
OnAiTalk
}
elseif reference0 == "r"
{
OnLastTalk
}
elseif reference0 == "f1"
{
"\![open,readme]"
}
}

71
ghost/master/anchor.dic Normal file
View File

@ -0,0 +1,71 @@
//---------------------------Anchors and OnTranslate--------------------------
//This .dic file is for setting up anchor words, which are links to set conversations attached to certain words automatically. It also deals with OnTranslate, which is a fairly unique function. All text goes through OnTranslate first before it displays on your ghost, which is how it knows to turn certain words into links.
//Why should I care about anchor words, you ask? Or what can I use them for? Well, you can set up anchor words to easy explanations for things your ghost might talk about that might confuse your user. People they know, places they've been, pop culture references the user might not get, information about you the creator or the world the characters from, items in an item menu, basically any number of things. Anchor words can be a handy repository of information! Or just an easy way to set up some cheap jokes. The power is yours!
//This file is very short, so don't worry! And if you aren't planning on using anchor words, you just have to delete a few things and you'll be done!
//Make sure to read the walkthrough (http://www.ashido.com/ukagaka/walkthrough.html) for more details about how to properly format ghost dialogue!
//I will reiterate that you should be editing these in Notepad++, and in particular, you should set the Language to C to properly highlight all the text. It will make things A LOT EASIER for you, trust me! It will also help you keep track of your brackets in case you forget some. If you click on a line with a bracket in Notepad++, it should highlight where the other bracket ends, or turn purple if there's no finishing bracket (which you should definitely fix!)
//It will also highlight my commented lines in green, so you'll know where they are. Any line beginning with // is a commented line that the code will not read. It's just for your reference!
//--OnTranslate
//As I said above, OnTranslate filters through all the text your ghost displays and does whatever you specify to it. That doesn't have to just be turning things into links, it could be anything. This is a powerful function that can be used in a lot of creative ways I bet, but I wouldn't mess with it too much since you can pretty easily break stuff if you don't know what you're doing.
//If you're not interested in any anchor words, delete all the lines that start with _talk = REPLACE under OnTranslate.
OnTranslate
{
_talk = reference0
_talk = REPLACE(_talk, "Anchor 1", "\_a[anchor1]Anchor 1\_a")
_talk = REPLACE(_talk, "Anchor 2", "\_a[anchor2]Anchor 2\_a")
_talk = REPLACE(_talk, "Anchor 3", "\_a[anchor3]Anchor 3\_a")
if reference1 == "" && reference2 == "" { //send input box : no event (ref2) , no special flag (ref1)
EVAL('"' + REPLACE(_talk,'"','" + CHR(0x22) + "') + '"')
}
else { //event result from ghost
TOSTR(_talk)
}
}
//Some brief explanation about what's going on in those REPLACE lines! Basically, the function looks through the script and looks for a defined word or set of words. In this case, it's "Anchor 1". It then replaces "Anchor 1" with the second set of text, "\_a[anchor1]Anchor 1\_a". \_a if you recall is the dialogue code for linking something, so this is linking the words Anchor 1 to something called anchor1 set up in the next function, OnAnchorSelect.
//This is being used to change a word into a link, but you could conceivably use this to replace any text with any other kind of text if you wanted.
//--OnAnchorSelect
//OnAnchorSelect runs whenever someone clicks one of the links as specified above, or a link that begins with http://.
OnAnchorSelect
{
if "http://" _in_ reference0 || "https://" _in_ reference0 //checking to see if the link is a web address
{
"\j[%(reference0)]\e" // \j is a tag that will open a specified url in the user's browser of choice. This basically just tells the ghost to open the webpage stored in reference0, which would be the address that the user just clicked. I didn't get too much into \j in the walkthrough page because I have literally never used it except here.
}
else //if it's NOT a web address
{
case reference0 //case is a unique thing that only really shows up in anchor.dic, and it basically sets up reference0 for evaluation to see if matches any of the below criteria, which are all tagged with when. You can read more about this on the coding page on the walkthrough site. You can add as many things here as you want to set up above as long as you follow the basic format.
{
when "anchor1" //if the link is this value
{
"\0\s[0]This dialogue is for when Anchor 1 is clicked.\e"
}
when "anchor2" //if the link is this value
{
"\0\s[0]This dialogue is for when Anchor 2 is clicked.\e"
}
when "anchor3" //if the link is this value
{
"\1\s[10]This dialogue is for when Anchor 3 is clicked.\e"
}
}
}
}
//This bit of code is what makes menu options that don't start with On direct to Select.options instead. Remove or comment it if you prefer!
OnChoiceSelect
{
EVAL("Select.%(reference0)")
}

635
ghost/master/bootend.dic Normal file
View File

@ -0,0 +1,635 @@
//---------------------------Booting and Ending--------------------------
/* This file has...
OnFirstBoot
NameInput (optional)
First pronoun stuff (optional)
GetDaySlot/GetTimeSlot
OnBoot
normalboottalk
OnClose
OnWindowStateRestore
OnGhostChanging
OnGhostChanged
OnShellChanging
OnShellChanged
OnDressupChanged
*/
//*********************Advanced User Info*******************************
//--A Note about Functions--
//A function that begins with On, such as OnFirstBoot here, can be called from anywhere in any .dic file by using \![raise] or by just sticking OnFunction somewhere. A function that does NOT start with On, however, can be a bit finicky. You can create your own functions all over the place if you want, there's just a difference between OnDoodlebop and Doodlebop, if you get me. See the walkthrough page about coding for more about creating functions.
//If you're having trouble getting a function of yours to run, like Doodlebop, try changing it to OnDoodlebop and see if that fixes it.
//***********************************************************************
//--OnFirstBoot--
//OnFirstBoot is, as you can probably guess, what happens when your user first boots up your ghost. This will only run the first time they are booted!
//*********************Advanced User Info*******************************
//Because this only runs once and under an odd set of circumstances, it can be hard to test if this function is working properly. Trying to run the entire function using \![raise,OnFirstBoot] will instead bring up your alternate dialogue, so sadly you can't check it that way. You CAN get it to run using \![raise,OnFirstBoot,0] though.
//If you're going to be adding new variables and values and such, make sure you define them all in OnFirstBoot! You can make any value you want, but it has to equal SOMEthing to exist at first. Then you can do whatever with it.
//***********************************************************************
OnFirstBoot : all
{
//OnFirstBoot begins with some code at first to define some values your ghost will be using. I'll briefly touch on what they are, but for the most part you should not need to edit any of these and you can safely ignore most of them (except nowshell if you've changed your shell folder's name from master). Definitely don't delete them unless you know what you're doing.
lastTalk = "" //This is part of how chained conversations work (see aitalk.dic).
passhour = 0
passmin = 0
passsec = 0 // These keep track of the time.
username = "USER" //This sets a temporary name for the user. It'll be replaced when they tell the ghost their name.
stroke = 0 // Sets their being-pet state to zero.
teachusername = 0 // Related to them learning your name.
mikireflag = 0 // Determines behavior at certain points.
aitalkinterval = 300 //Their default talk rate.
birthdayprint = "????" //A temporary value for the user's birthday.
talktime = "5 minutes" //How the value aitalkinterval will display in the config menu.
deleteshitai = "OFF" //Sets whether or not the user can uninstall the ghost to "OFF". The user can change it later in the config menu (see menu.dic).
nowshell = "master" //This is for a special if check in aitalk.dic to see what shell the ghost is using. You should use the name of your default shell folder here.
//firstboot = 1 //This marks that this is the first time you've run the ghost. It's so it won't reroute to general name changing dialogue when the user inputs their name. Uncomment this if you're going to have your ghost ask the user directly when they're first booted for the user's name.
if reference0 == 0 //Don't touch this line.
{
//---- Alright, here is where the dialogue for your ghost begins! Again, I hope you've studied up on the walkthrough's guide to dialogue coding! However, there are a few unique things about this first conversation that you should keep in mind.
//Make sure to set up poses for both characters right when you start, otherwise one will be invisible until they speak.
//Note also the use of the \x and \c tags. Read more about them in the intermediate SakuraScript section of the walkthrough if you're curious.
"\0\s[0]Ты, новый хозяин Люмы?\e"
//*********************Advanced User Info*******************************
//If you want to directly add the option for the user to give their name and pronouns, you can uncomment and add this text below to the above. You don't have to do this if you don't want to!
// "Now we're going to ask the user the first question about themselves, namely what pronouns they want us to use.\w8\0\s[0]\n\n[half]This will let us construct grammatically correct sentences referring to the user later.\x\w8\1\c\s[10]How should we refer to you, user?\n\n[half]"
// "\w5\_q\![*]\q[He/Him/His,choicefirsthehim]\n"
// "\![*]\q[She/Her/Hers,choicefirstsheher]\n"
// "\![*]\q[They/Them/Their,choicefirsttheythem]\e"
//If you do include this, see the "Name/Pronouns" section below.
//You can rename the choices at the bottom of that pronoun menu question anything you like. The basic structure of a choice goes like \q[Displayed Name,Linkedfunction]. So for example, \q[Do a Dance,danceitup] would display "Do a Dance" in the balloon and it would link to the function titled "danceitup".
//Note - Do not include quotation marks in the displayed name, or any other symbols like brackets or dialogue coding like \_a, since that'll break the option in the balloon. If you do this you'll notice pretty quickly. Also option names do not word wrap, so don't make them too long if your balloon is small.
//If you remember my note from above about the difference between On functions, this is one place it comes up. If your linked function in this menu doesn't start with On, like danceitup up there, you'll have to preface it in the following code with Select.danceitup. You can see this at work below here. However, if it does have On, such as OnDanceitup, then you can simply name the function in the code as OnDanceitup. Take a look whenever functions are defined and how they're called in the files,and it should come together for you.
//If you link to a function that doesn't exist, the ghost will do nothing. This can be handy for "Cancel" type functions, just point it at something that doesn't exist if you don't want to have a specific bit of cancel dialogue.
//***********************************************************************
}
else
{
//---- This is dialogue for when the user uninstalls the ghost for whatever reason, then reinstalls them again. They will run this dialogue instead of their normal dialogue above. You can change this to reflect the fact the user's uninstalled your ghost once, or you can make it the same as the above, it's up to you. You'll see this if you try to run OnFirstBoot using ![raise] without the extra 0 as mentioned above.
{
"\1\s[10]\0\s[0]Я буду стараться лучше в этот раз, хозяин.\e"
}
}
}
//&&&&&&&
//*********************************
//NAME/PRONOUNS START
//*********************************
//&&&&&&&
//This section is only for people who have their ghost ask the user directly for their name/pronouns up above. If you aren't doing that, you can ignore this.
//Below are the choices that were defined at the end of the OnFirstBoot dialogue up there. These define the values your ghost will be using for pronouns according to what the user selected. On the whole, you should not need to touch these.
//*********************Advanced User Info*******************************
//Notice that after the values are set, there's a -- and then it loads up the next function in the sequence. You can use this basic method to set many values at once, then go to the same function afterwords.
//To define a value, you use a single = mark. If it's a word, you need to put it in quotation marks, but if it's a number, you do not. See the walkthrough page on coding for details.
//Notice how each choice is formatted as Select.choice. This is what I was talking about above with the difference between OnFunction and Function. These choices do not start with On, so they must begin with Select. instead. If you're setting up some quick choices for a menu you're only going to do once, then don't be afraid to use select. instead of having everything start with On.
//***********************************************************************
Select.choicefirsthehim
{
presuffix = "masculine"
himher = "him"
heshe = "he"
hisher = "his"
hesshes = "he's"
--
NameInput
}
Select.choicefirstsheher
{
presuffix = "feminine"
himher = "her"
heshe = "she"
hisher = "her"
hesshes = "she's"
--
NameInput
}
Select.choicefirsttheythem
{
himher = "them"
heshe = "they"
hisher = "theirs"
hesshes = "they're"
--
NameInput
}
//--NameInput
//NameInput is the next step in our introduction sequence. Now that the ghost has the pronouns set properly, they can ask the user for their name. It's done in this order so they'll know what prefixes will be appropriate for their name, like Mr. to he/him for example.
//*********************Advanced User Info*******************************
//Note this functions' name. This isn't a natural function included in the ghost, it's a piece of dialogue created by the original base coder to finish this sequence (cindysuke). I point this out to show you that you can do this too! You can create any number of functions just like this called whatever you want to do and say whatever you want! There are many things you can do with your Ghost if you're creative. Don't feel limited by what's in these files or the listed Shiori functions!
//Just make sure you test them and they work, alright? I wrote more about coding and functions in the coding page for the walkthrough.
//***********************************************************************
NameInput
{
"\1\s[10]Now that the pronouns are set, we will ask for the user's name.\w8\0\s[0]What is your name, user? \![open,inputbox,OnNameTeach,-1]\e"
//At the end of this dialogue there's a tag saying "\![open,inputbox,OnNameTeach,-1]". It basically leads to the naming function defined in nameteach.dic, so don't touch it. Make sure it's there though! Otherwise your user won't have a way to put in their name. :o
//*********************Advanced User Info*******************************
//What this tag basically means is that you're calling a function at the end of the dialogue with the \! tag, you are telling it to open, you're telling it to open an inputbox, and you're telling that inputbox to link to a function called OnNameTeach, which is in the nameteach.dic file. Remember what I said about On functions? I talked a bit about this in the SakuraScripting walkthrough page and the coding page.
//The -1 at the end determines how long the box will be open until it times out. -1 means it shouldn't time out at all, I think.
//***********************************************************************
}
//&&&&&&&
//*********************************
//NAME/PRONOUNS END
//*********************************
//&&&&&&&
//--timeslot
//This is another unique function to tell what time of day it is. This is used for specialized dialogue related to the day. If you're uninterested, just ignore it. Either way, don't touch it. If you are going to use it though, make a note of the names used for each chunk of time, like earlymorning or lunch. Those are the names you'll be using later.
timeslot
{
if hour >= 5 && hour <= 8
{ "earlymorning" }
elseif hour >= 9 && hour <= 11
{ "morning" }
elseif hour >= 12 && hour <= 14
{ "lunch" }
elseif hour >= 15 && hour <= 17
{ "afternoon" }
elseif hour >= 18 && hour <= 20
{ "evening" }
elseif hour >= 21 && hour <= 24
{ "latenight" }
else
{ "midnight" }
}
//*********************Advanced User Info*******************************
//Do you see how this function is determining what time of day it is? It's using larger than/smaller than operators to isolate a range of time to define. For example, "hour >= 21 && hour <= 24" defines an hour that's greater than/equal to 21 AND less than/equal to 24. You can use this basic method to define other things too, such as the seasons. Keep this in mind! You never know when it might come in handy. I talk about operators more in the coding walkthrough page.
//***********************************************************************
//--dayslot
//Like the above, but to find out what day it is. You can primarily use this for specialized dialogue on certain days, like the user's birthday. Either way, don't touch it.
dayslot
{
"%(month)month %(day)day"
}
//-----------------------Normal Booting----------------------------
//From this point on, the dialogue will be for any normal boot of your ghost. You can specialize this for certain days or times if you like, or if you're uninterested, leave it very simple.
//--OnBoot
//As you can probably guess, OnBoot runs when you boot your ghost.
//*********************Advanced User Info*******************************
//If you're defining new values that depend on what you were doing with your ghost (like say, if you've hit them, if they're in a certain mode of some kind) and are generally temporary, remember to put them in OnBoot and set them back to zero or off. For example, I have a counter in the Hunter Smoker ghost that keeps track of if you've hit one of them so that when you go into their menus, it will know to give you the option to apologize or not. So I made sure to add a hunterpunchcount = 0 tag at the beginning of OnBoot, that way when you boot them up, they start fresh and don't display the option if you haven't done anything wrong yet. It's unlikely this'll come up very much if you're not interested in expanding your ghost, but I'm making a note of it here anyway for enterprising developers, huge success.
//You can also stick any values you want to reset on boot into their own function, like "BootReset", then run BootReset instead during boot so it's a bit less unwieldy. It's up to you though!
//***********************************************************************
OnBoot
{
lastTalk = "" //These values you may recognize from OnFirstBoot up there. Just pay them no mind.
passhour = 0
passmin = 0
passsec = 0
"\0\s[0]\1\s[10]" //This sets them up in their neutral pose for now.
//If you want to check what day it is first though, read on ahead!
--
if dayslot == userbirthday
{
"\0\s[0]Хозяин, с днем рождения!\e"
//"\0\s[0]It's %(bornmonthprint) %(borndayprint).\w8\1\s[10]Happy birthday, %(username).\e"
//Notice in this dialogue that there are two new envelopes, %(bornmonthprint) and %(borndayprint). These two things basically display the user's birthday - bornmonthprint is the month and borndayprint is the day. These were defined when the user put in their birthday in the menu.dic file. See word.dic for more info on envelopes.
}
elseif dayslot == "6month 6day" //Like above, this if statement is checking the date. It's looking for the sixth month and the sixth day. You can change these to any day or month you want.
//*********************Advanced User Info*******************************
//elseif statements always go after an if statement, and essentially are just what they sound like... if this thing happens, do this; else, if this thing happens, do this. elseifs are good if you have multiple things you want to check for in one function, like multiple days of the year as we're doing right now. elseifs go in descending order, so it'll always check if one is true, then if two is true, then if three is true, and so on.
//***********************************************************************
{
"\0\s[0]Today is June 6th.\e"
}
elseif dayslot == "7month 4day"
{
"\1\s[10]It's the fourth of July.\e"
//You can see how these basically work. You can add in new elseif statements along these same lines with your own dayslots if you want to have them say things for all sorts of days. You can also change these existing ones I put in as examples to other dates, like your character's birthdays, perhaps. This is up to you! If you don't care about this, you can delete all the elseifs and just leave the one for the user's birthday.
}
else
{
"%(normalboottalk)" //If none of the days above match the current date, the ghost instead will go down to the next function, normalboottalk.
}
}
//--normalboottalk
//This is another unique bit of coding from cindysuke's ghost. OnBoot above checks for the day when you open them, but normalboottalk can vary their dialogue in a few different ways depending on the time and weekday. I explain how to do that for advanced users below. If you're not interested, you can just fill out normalboottalk here with as much or as little dialogue as you want.
normalboottalk
{
"\0\s[0]Here is some boot dialogue.\e"
"\1\s[10]Here is some more boot dialogue.\e"
}
//*********************Advanced User Info*******************************
//cindysuke set up a system where you can have your ghost check for certain days or times of day and have dialogue corresponding to that when they boot up! If you're interested, you'll want to add the following into normalboottalk:
// if weekday == 6 && hour >= 19 //This checks if the weekday equals six, meaning saturday AND (using the && operator) if the hour is past 19. You can change these numbers or values to anything you like! As such you can check any combination of date and day and time for potential boot dialogue. You can also add more elseif checks for other days if you want.
// {
// "\0\s[0]It's Saturday night.\e"
// }
// elseif RAND(100) < 40 //What this does is choose a random number from 1-100, and then checks if that number is less than 40. If it's less than forty, then these dialogue pieces will occur. Remember, you can have multiple lines of dialogue within one set of brackets like this! You just need to make sure they're all enclosed in their own set of quotation marks.
// {
// "\0\s[0]This is one of the random boot conversations.\w8\1\s[10]The random number drawn was less than forty.\e"
// "\1\s[10]This is another one of the random boot conversations.\w8\0\s[0]The random number was again less than forty.\e"
// "\0\s[0]This is the third random boot conversation.\w8\1\s[10]The random number was less than forty.\e"
// }
// else
// {
// //The following if statements check the time of the day as defined above in the GetTimeSlot function. Do you remember the names that it defined? Now we're going to use them!
// if timeslot == "earlymorning" //The following dialogue will be called if they are booted during the time specified in GetTimeSlot (in this case, the hour being more than/equal to 5 but less than/equal to 8). Remember, you can add as many lines of dialogue here as you want, or take away as many as you want! Replace the dialogue here with what you see fit.
// {
// "\0\s[0]This is an early morning boot dialogue.\w8\1\s[10]Between the hours of five and eight.\e"
// "\1\s[10]This is another early morning boot dialogue.\w8\0\s[0]Again, between the hours of five and eight.\e"
// "\1\s[10]This is the third early morning boot dialogue.\w8\0\s[0]Between the hours of five and eight.\e"
// }
// elseif timeslot == "morning"
// {
// "\0\s[0]This is a morning boot dialogue.\e"
// "\1\s[10]This is another morning boot dialogue.\w8\0\s[0]Yup.\e"
// }
// elseif timeslot == "lunch"
// {
// "\0\s[0]This is a lunch boot dialogue.\1\s[10]Sure is.\e"
// "\1\s[10]This is another lunch boot dialogue.\e"
// }
// elseif timeslot == "afternoon"
// {
// "\1\s[10]This is an afternoon boot dialogue.\w8\0\s[0]That it is.\e"
// }
// elseif timeslot == "evening"
// {
// "\0\s[0]This is an evening boot dialogue.\1\s[10]Between the hours of 18 and 20.\e"
// }
// elseif timeslot == "latenight"
// {
// "\0\s[0]This is a late night boot dialogue.\1\w8\s[10]Between 21 and 24.\e"
// "\0\s[0]This is another late night boot dialogue.\1\w8\s[10]That it is.\e"
// "\1\s[10]This is the third late night boot dialogue.\w8\0\s[0]Between 21 and 24.\e"
// }
// else //the last timeslot we haven't done is midnight, which is what's under here.
// {
// "\0\s[0]This is a middle of the night boot dialogue.\1\w8\s[10]From midnight to five.\e"
// "\0\s[0]This is another middle of the night boot dialogue.\1\w8\s[10]That it is.\e"
// "\1\s[10]This is the third middle of the night boot dialogue.\w8\0\s[0]Very late at night.\e"
// }
// }
//Note! If you write any general boot dialogue, you'll want to put it in the "elseif RAND(100) < 40" section, since you can't have dialogue floating around outside of an if/else. Or in another if section you make, I don't know. It's up to you!
//**********************************************************************
//}
//--OnClose
//OnClose runs when you close your ghost. Like OnBoot, this can be customized for times and days if you like, as you saw above. I'll leave in the simplified version, and add in the more complicated ones in a comment box for ambitious or experienced developers.
//Do note, close dialogue must end with a \- instead of \e. \- will close the program.
//Like above with OnBoot, just replace all the following pieces of dialogue with your own. Note though that each bit here ends with \w8\w8\- instead of \e. The \w8 there is so there's a little pause before the ghost closes so the user can read the dialogue.
OnClose
{
"\0\s[0]This is some random close dialogue.\w8\w8\-"
"\1\s[10]This is another random close dialogue.\w8\w8\-"
//Add as many or as few close messages in here as you want! Make sure to end them with \w8\w8\- though.
}
//*********************Advanced User Info*******************************
//This works just like the one above for normalbootttalking! There are some different variables that can get checked of course, and make sure that it ends with \w8 and \-. The basic set-up of it here should take care of that for you, but it's always good to be cautious. Just uncomment and add the following into OnClose up there:
// if passmin >= 5 || passhour > 0 //This checks to see if you've had them open for at least five minutes.
// {
// if RAND(100) < 40 //see above about the random number generator
// {
// "\0\s[0]This is a random close dialogue.\w8\1\s[10]The random number generator chose something below 40.\w8\w8"
// }
// else
// {
// if timeslot == "earlymorning"
// {
// "\1\s[10]This is an early morning close dialogue.\w8\0\s[0]From 5 to 8.\w8"
// "\0\s[0]This is another early morning close dialogue.\w8\1\s[10]Yup.\w8\w8"
// }
// elseif timeslot == "morning"
// {
// "\0\s[0]This is a morning close dialogue.\w8\w8"
// }
// elseif timeslot == "lunch"
// {
// "\0\s[0]This is a lunch close dialogue.\w8\1\s[10]Yup.\w8"
// "\0\s[0]This is another lunch close dialogue.\w8\1\s[10]In the middle of the day.\w8"
// }
// elseif timeslot == "afternoon"
// {
// "\0\s[0]This is an afternoon close dialogue.\w8\1\s[10]Done.\w8"
// "\1\s[10]This is another afternoon close dialogue.\w8\0\s[0]Yup.\w8"
// }
// elseif timeslot == "evening"
// {
// if weekday == 6 //here, a nested if statement is checking that if it's evening, is it also saturday? You can do this to check more specific times on other days as well. You can change this to some other day if you want, or just delete this little if/else section entirely and write your own evening related close dialogue.
// {
// "\0\s[0]This is a Saturday evening close dialogue.\w8\1\s[10]Somewhat specific.\w8"
// }
// else //if it's not saturday, then it'll do this dialogue instead.
// {
// "\0\s[0]This is an evening close dialogue.\w8\1\s[10]Bye.\w8"
// "\1\s[10]This is another evening close dialogue.\w8\0\s[0]Yup.\w8"
// }
// }
// elseif timeslot == "latenight"
// {
// if weekday == 6 //This is the same check as above to see if it's Saturday. Note that this doesn't have an else statement! Sometimes you can get away with that, but make sure you test thoroughly.
// //Of course, you can also cut this check entirely if you want.
// {
// "\0\s[0]This is a late Saturday night close dialogue.\w8"
// "\1\s[10]This is another late Saturday night close dialogue.\w8\0\s[0]Yup.\w8"
// }
// "\1\s[10]This is a late night close dialogue.\w8\0\s[0]That it is.\w8"
// "\0\s[0]This is another late night close dialogue.\w8\1\s[10]Done.\w8"
// }
// else //like above, this is the midnight time slot since it's the last one left.
// {
// if weekday == 0 //checking if it's the middle of the night on Sunday
// {
// "\1\s[10]This is a middle of the night Sunday close dialogue.\w8\0\s[0]From midnight to five AM on Sunday.\w8"
// }
// "\0\s[0]This is a middle of the night close dialogue.\w8\1\s[10]Very late at night.\w8"
// "\1\s[10]This is another middle of the night close dialogue.\w8"
// "\1\s[10]This is the third middle of the night close dialogue.\w8\0\s[0]So it is.\w8"
// }
// }
// }
// else //This dialogue is for if they haven't been open for at least five minutes.
// {
// "\0\s[0]This dialogue is for closing us before five minutes have passed.\w8\w8"
// "\1\s[10]This is another bit of dialogue for closing us before five minutes have passed.\w8\0\s[0]Quickly done.\w8\w8"
// }
// --
// "\-\e" //this bit of code actually closes and ends the ghost. Because \e is here, you don't have to end each line above with it. Again, this will come up very rarely, so OnClose is an unusual case.
// }
//**********************************************************************
//-------------------------State Changing--------------------
//From here on, most of the dialogue will have to do with changing shells, ghosts, or states in some way. You only need to fill in the ones you think you'll see. The template default dialogue will take care of the rest.
//--OnWindowStateMinimize
OnWindowStateMinimize
{
"\0\s[0]Люма будет рядом, хозяин\w4\e"
}
//--OnWindowStateRestore
OnWindowStateRestore
{
"\0\s[0]Хозяин, Люма вернулась\w4\e"
}
//--OnGhostChanging
//This runs whenever you change or reload the ghost. You can change ghosts by going into the right click menu and going to Change Ghost, but this dialogue will also be called if you reload them using Utilities->Reload Ghost or the Developer's Console->Reload->Ghost. Protip: If you are going to make a ghost, you will be reloading it A LOT.
//Note: If you reload your ghost using the developer console instead of Utilities->Reload Ghost, it won't do this dialogue, so don't freak out if it doesn't show up.
OnGhostChanging
{
if reference0 == "Lyuma"
{
"\0\s[0]Появится ли после перезагрузки та же самая Люма, или просто очень похожая?\w8\w8\e"
}
else
{
"\0\s[0]Люма позовёт %(reference0)\w8\w8\e"
//Replace this dialogue with whatever you like. Notice the use of the %(reference0) envelope here? In OnGhostChanging, %(reference0) stores the name of the ghost being swapped to, so if you want to display what you're switching to, you can use %(reference0) as in this example. You don't have to use %(reference0) if you don't want to though.
}
}
//--OnGhostChanged
//A sister to the above, this runs after the ghost has either reloaded itself, or when you switch from another ghost to this ghost.
OnGhostChanged
{
"\0\s[0]\1\s[10]" //this sets up their default poses
--
if reference0 == "Lyuma"
{
"\0\s[0]Хозяин, Люма вернулась\e"
}
else
{
"\0\s[0]Пока, %(reference0)...\e"
//Again, %(reference0) in this function is the name of the ghost in question. As above, replace these two lines of dialogue what what'd be appropriate for your ghost.
}
}
//--OnShellChanging
//This will run when you change your ghost's shell. If you don't have any other shells for your ghost, you can safely ignore this but don't delete it, you might as well keep it just in case. I probably won't add a different shell to this template because shells are a lot of work ugh, but for the sake of argument, let's pretend I did.
OnShellChanging
{
if reference0 == "Hypothetical Shell that doesn't actually exist" //reference0 in OnShellChanging is the name of the shell you're swapping to. It should be defined in the descript.txt file in your shell folder. If you do have alternate shells, put in the right name here.
{
"\1\s[10]This dialogue is specifically for changing to this particular shell.\w8\0\w8\s[9]It totally exists.\w8\e"
//Then rewrite this line as appropriate.
}
else //if you don't have any specific dialogue for a specific shell
{
"\0\s[0]This dialogue is for changing shells.\w8\1\s[10]Sure is.\w8\e"
"\1\s[10]This is another bit of dialogue for changing shells.\w8\0\s[8]I wonder how many people will actually have multiple shells?\e"
//Rewrite these two lines as you need.
}
}
//--OnShellChanged
//The sister to the above, this is the dialogue after you've changed the shell.
OnShellChanged
{
if reference0 == "GT Default Shell" //Again, this is the name of your shell as you put in the descript.txt file for that shell.
{
nowshell = "master" //This is the folder name for your shell. Not the same as the above!
"\0\s[0]This dialogue is for switching to our default shell.\w8\1\s[18]No really, will anyone actually put in the work to use these functions?\w8\0\s[9]\n\n[half]Shh.\e"
//Replace dialogue as required.
}
elseif reference0 == "Hypothetical Shell that doesn't actually exist" //You can use as many elseifs for as many shells as you've got.
{
nowshell = "totallyrealshell"
"\0\s[0]This dialogue is for switching to that hypothetical shell.\e"
"\0\s[0]This is another bit of dialogue for switching to this hypothetical shell.\w8\1\s[18]Man if you actually use this, you should tell Zar, it'll blow her mind.\w8\0\n\n[half]\s[9]Shut up, we're not supposed to be in-character here.\e"
//Replace these bits with whatever you have in mind.
}
elseif reference0 == "Another totally real shell wow"
{
nowshell = "thiswouldbesomuchwork"
"\1\s[10]This dialogue is after we've switched to another totally real shell.\e"
//Replace this as well.
}
else //For any shell without a specific name, or if you don't want to bother with individual responses to a shell.
{
"\0\s[0]This dialogue is after we've changed our shell to %(reference[0]).\w8\1\s[18]How many shells you got?\e"
//Note the %(reference[0]) here! This time that should store the name of whatever shell you're switching to. Replace this bit of dialogue as you need.
}
}
//--OnDressupChanged
//This runs whenever you fiddle with their clothing via the dress-up option, if you've set any for your ghost. Make sure to read the clothing page on the walkthrough for details on how clothes work! This template won't have any because Girl and Triangle move around too much for it, but if your ghost is mostly stationary, clothes are an option. In that case, these functions are for you. For now, I'll fill this in with some hypothetical items. Replace the dialogue below with whatever you need.
OnDressupChanged
{
if reference0 == 0 //in OnDressupChanged, reference0 refers to the character, therefore this is evaluating which character in question is getting dressed up. 0 is the main character, as you know from the walkthrough by now.
{
if reference1 == "Clothing for Girl" //This is the name of the clothing item in the descript.txt file, I'm pretty sure.
{
if reference2 == 1 //This checks if you're putting it on.
{
"\0\s[0]You put my clothing item on me.\w8\1\s[19]lol like zar would ever bother with clothes for a ghost.\w8\0\s[9]\n\n[half]Shut up dude you're going to get us in trouble.\e"
}
else // This checks if you're taking it off.
{
"\0\s[0]You took the clothing item off.\e"
}
}
}
else //if reference0 isn't the main character, then it has to be the side character.
{
if reference1 == "some kind of clothing for triangle??" //The name of the item of clothing in the descript.txt file in your shell folder.
{
if reference2 == 1 //If you put it on
{
"\1\s[10]I'm wearing some kind of clothing.\w8\0\s[8]Maybe a hat?\e"
}
else //When you take it off.
{
"\1\s[10]You took off some kind of clothing.\e"
}
}
elseif reference1 == "i'm gonna say a propeller beanie" //As you've seen above, you can use elseifs to expand the list if you have more than one item.
{
if reference2 == 1 //if you're putting it on
{
"\1\s[10]You put a hat on me.\w8\0\s[6]lol.\w8\1\n\n[half]\s[11]Shaddap.\e"
}
else //when you take it off
{
"\1\s[10]You took off the hat.\e"
}
}
}
}

138
ghost/master/commu.dic Normal file
View File

@ -0,0 +1,138 @@
//---------------------------Communication--------------------------
//Alright, after many years, I've finally figured out what the deal is with this file. Basically, it handles inter-ghost communication. Some ghosts have a feature where they will speak to your ghost, usually saying "hello" or "hi" or something like that. This file mostly handles how your ghost will reply when another ghost talks to them like that. While not every ghost has that functionality, you might as well put in one line or two just in case. It won't take you any time at all.
//If you're interested in having your ghost speak to other ghosts through a menu option or something like that, I think that's a bit outside the scope of this template for now, but I'm sure I'll eventually write up how to do it on the walkthrough page in one of the coding sections.
//Some of you may be wondering about the parts for talking to the user. I can't track this down anywhere in the files, and I think it refers to a deprecated functionality to have the user teach your ghost things via the teach box. Basically just ignore it, it will probably never come up.
//As usual, refer to the walkthrough page for info on Sakurascript formatting and all that! I would definitely recommend reading the page about ghost communication as well, since that gets way more in-depth about how it works than here.
//--OnCommunicate
//OnCommunicate is called when your ghost is either targeted by another ghost for a conversation, or when your ghost is targeting another ghost for conversation. There's no need to touch any of this.
OnCommunicate
{
if reference0 == "user" || reference0 == "User"
{
//---- answering the user
ReplyToUser
}
else
{
//---- answering another ghost
ReplyToGhost
}
}
//Just ignore this.
ReplyToUser
{
TalkToUser
}
//--ReplyToGhost
//Here is where you get to write your dialogue. This will be what your ghost will say when another ghost tries to speak to them. Most other ghosts will say something like, "Hello, ghostname" or "How are you" or "hey there". A general greeting. So think about your ghost and how they might respond to such a greeting. This functionality is again pretty rare, and while there may be a case where the other ghost just insults yours, it seems so unlikely that I wouldn't sweat it too much.
//*********************Advanced User Info*******************************
//These text boxes are meant for those who have an interest in expanding or using more complicated functions in their ghost. Also for my own reference in the future since I plan on using this template too, haha. If you have no interest in any of this and just want to keep things as simple as possible, feel free to skip these boxes.
//There are a few different ways you can refine this dialogue, depending on what ghost is speaking to yours and what they're saying. The things you can check for are reference0 and reference1, being the ghost's sakuraname (in their descript.txt) and what they're saying. For example, let's say you want to check if my Gaster ghost is speaking to yours. In that case, you'd set it up like...
/*
ReplyToGhost
{
if reference0 == "Gaster"
{
res_reference0 = "Gaster" //res_reference0 would be the name of the ghost they're replying to. if the ghost they're responding to has it enabled, this will allow the other ghost to respond to this statement. if you notice that your ghost is getting stuck in a loop with the other ghost, you can erase this line and it should be fine.
"\0\s[0]Hello, Gaster.\e"
}
else
{
res_reference0 = reference0 //see above, although erasing this line may make it so the res_reference0 envelope may not work. In that case, you can write around it instead.
{
"\0\s[0]Hello, %(res_reference0).\w8\1\s[10]Hope you're doing well.\e"
"\1\s[10]Hey, %(res_reference0).\e"
}
}
}*/
//You can also specify it even further by looking in that ghost's dialogue with nested ifs. As an example...
/*
ReplyToGhost
{
if reference0 == "Gaster"
{
res_reference0 = "Gaster"
if reference1 == "I'm a skeleton."
{
"\0\s[0]You sure are.\e"
}
else
{
"\0\s[0]Hello, Gaster.\e"
}
}
else
{
res_reference0 = reference0
{
"\0\s[0]Hello, %(res_reference0).\w8\1\s[10]Hope you're doing well.\e"
"\1\s[10]Hey, %(res_reference0).\e"
}
}
}*/
//As you can see, you can check reference1 for certain phrases the other ghost is saying, and reply to those phrases. You can customize your ghost's responses to another ghost's conversation in almost any way you like for any kind of custom flags or states you may have made for your ghost. It's all up to you!
//***********************************************************************
//Now, real quick, there is a chance that your ghost could get stuck in a loop of saying hi to the other ghost unless you take a few precautions. Mostly, setting a little flag to make sure your ghost won't get stuck. I'll add it in here just in case, so you won't have to worry about that.
ReplyToGhost
{
if AlreadyResponded == 1 //checking the status of the flag
{
//This dialogue here is in case the other ghost doesn't have loop protection set up. As an example, let's say a ghost with no loop protection says hi to yours. The conversation would go like this.
//Other Ghost: Hi, I'm [name].
//Your Ghost: Hello, [name].
//Other Ghost: Hi, I'm [name].
//Your Ghost: Hello, [name].
//And so on and so on. This dialogue down here will stop the loop, so instead it will go...
//Other Ghost: Hi, I'm [name].
//Your Ghost: Hello, [name].
//Other Ghost: Hi, I'm [name].
//Your Ghost: Well, it's nice to meet you. (conversation ends)
//So, the dialogue you'll want here may depend on how you want your ghost to respond in the first place. This will depend on the character you are writing for! But that is the basic structure of this check, if that helps you decide what to have them say.
AlreadyResponded = 0 //Resetting the flag.
res_reference0 = "" //this will clear the value so the conversation will end
"Yeah okay."
}
else
{
//if you don't want your ghost to say anything, just comment out everything here
res_reference0 = reference0 //targeting the other ghost.
AlreadyResponded = 1 //setting a flag to say they've responded once already
{
"\0\s[0]Hello, %(res_reference0).\w8\1\s[10]Hope you're doing well.\e"
"\1\s[10]Hey, %(res_reference0).\e"
}
}
}

39
ghost/master/descript.txt Normal file
View File

@ -0,0 +1,39 @@
//This sets the character set for your ghost. Most Japanese ghosts are set to Shift-JIS, but yours will be UTF-8. Don't mess with this.
charset,UTF-8
//The name of your ghost is what will be displayed when you are loading your ghost or switching to it, and also how it is referred to in certain functions. Usually this will be "Character and character" or just "Character" depending on your ghost. The type of the ghost will be ghost, obviously, leave that alone.
name,Lyuma
type,ghost
//This defines which is the main character and which is the side character. The main character of a ghost is referred to as "sakura" by the code, and the side character as "kero". If you see these names in the functions, that's who they are referring to. Replace the names as you need.
sakura.name,Lyuma
kero.name,Triangle
//This is the information about you, the creator of your ghost! Put in your name or whatever alias you want and whatever website you'd like to link to.
//You may be wondering why there's both craftman and craftmanw. Well, craftmanw is for non-alphanumeric characters like Japanese, Chinese, Korean, Russian, Arabic, things like that. So if your name is, say, 大嶋啓之, then you'd want to put that in craftmanw. Then you'd put your name in alphanumeric characters in craftman. If you want, you can delete craftmanw if you're not going to use it. Don't delete craftman though.
craftman,sova
craftmanw,sova
craftmanurl,https://coders-teaparty.cafe/
//This is coding stuff, don't touch it.
sstp.allowunspecifiedsend,0
shiori,yaya.dll
//This next bit defines what icon your ghost will use in your taskbar.
//To make an icon file, draw yourself a 16x16 image for your ghost and save it as a png. You can use http://www.convertico.com/
icon,lyuma.ico
//If you have a special balloon for your ghost, you can set it here with balloon, which will highlight it in the Change Balloon menu so it'll be easier to find.
balloon,z_simple

766
ghost/master/etc.dic Normal file
View File

@ -0,0 +1,766 @@
//---------------------------Miscellaneous Functions--------------------------
//This .dic file is concerned with a number of functions that didn't quite fit in anywhere else. If you're adding new functions, this may be the place to do it! This also has the functions related to updating your ghost, among others. Most of this will just be replacing simple placeholder dialogue with dialogue more appropriate for your ghost.
//This is basically bonus features and flavor text for a few of the more uncommon functions of a ghost. You don't HAVE to fill these out if you don't want to, the template's default dialogue will handle it (assuming you're making a two person ghost... if not, you may have to go through and remove Triangle's dialogue tags so he doesn't appear when you don't want him to). So if this file is boring or intimidating or you don't care, you can ignore it! These are again edge-cases compared to how often you'll see aitalk, bootend, or menu dialogue instead.
/*
This file has...
OnInstallBegin
OnInstallComplete
OnInstallFailure
OnInstallRefuse
OnVanishSelecting
OnVanishSelected
OnVanishCancel
OnVanishButtonHold
OnVanished
OnBIFFBegin
OnBIFFComplete
OnBIFFFailure
OnUpdateBegin
OnUpdateReady
OnUpdateComplete
OnUpdateFailure
OnUpdate.OnDownloadBegin
OnUpdate.OnMD5CompareBegin
OnUpdate.OnMD5CompareComplete
OnUpdate.OnMD5CompareFailure
OnHeadlinesenseBegin
OnHeadlinesense.OnFind
Select.Headline_Cancel
OnHeadlinesenseComplete
OnHeadlinesenseFailure
OnUpdatedataCreating
OnUpdatedataCreated
OnNarCreating
OnNarCreated
OnSNTPBegin
OnSNTPCompare
OnSNTPEXECUTE
OnSNTPCANCEL
OnSNTPFailure
OnDisplayChange
OnScreenSaverStart
OnScreenSaverEnd
OnApplicationBoot
OnApplicationClose
OnApplicationFileOpen
OnBatteryLow
OnBatteryCritical
OnShellScaling
OnFileDrop2
*/
//You can guess at what each function does by its name for the most part. You can go through and find the functions that seem the most interesting, or the most likely, to appear and then just fill those out if you don't want to do all of them. Or, if you want to go full nuclear, you can just wipe this whole file and let SSP's default dialogue handle whenever these scenarios come up. It depends on what you have the energy for and how thorough you want to be.
//This file IS long, but you'll only have to do it once! Probably. And again, you don't have to do all of it, or even most of it if you don't want to. Don't let this be a roadblock for you! It's basically bonus material! What matters is your aitalk file more than anything. You can always come back to this and fill it out over time once your ghost is already published. Don't get stuck here! I know it's easy to do so but don't let it happen to you! If you're getting stuck here just walk out, you can leave! lol. There's always aitalk, bootend, and menu to have more fun with, and that's the dialogue your user is going to see the most often.
//Make sure to read the walkthrough page (http://www.ashido.com/ukagaka/walkthrough.html) for more details about how to properly format ghost dialogue!
//I will reiterate that you should be editing these in Notepad++, and in particular, you should set the Language to C (or Java I guess) to properly highlight all the text. It will make things A LOT EASIER for you, trust me! It will also help you keep track of your brackets in case you forget some. If you click on a line with a bracket in Notepad++, it should highlight where the other bracket ends, or turn purple if there's no finishing bracket (which you should definitely fix!)
//It will also highlight my commented lines in green, so you'll know where they are. Any line beginning with // is a commented line that the code will not read. It's just for your reference!
//If you see a big block of commented text you want to uncomment, highlight the text and then hit ctrl-shift-k in Notepad++ and that should uncomment it. Mostly this is intended for advanced users.
//---- OnInstallBegin -------------------------------------------------------
//OnInstallBegin is called when a file with an included install.txt is dropped on your ghost. This primarily means things like .nar files for other ghosts or .zip files containing balloons or shells for your ghosts. Primarily ghost-related things. Replace as you want.
OnInstallBegin
{
"\0\s[0]This is the beginning dialogue for installing a file. This zip or nar contains an install.txt file.\e"
}
//---- OnInstallComplete -------------------------------------------------------
//OnInstallComplete runs once the file above has finished installing.
OnInstallComplete
{
"\0" //this means your main character will be speaking first, therefore the \s[] at the beginning of each line will be defining your main character's pose.
--
if reference0 == "shell" //This is checking to see if what you installed is classified as a shell in the install.txt. Remember the line in install.txt that said type,ghost or type,shell? This is why that line is important, that's what tells the program what it's installing like so.
{
if reference1 == "Hypothetical Shell that doesn't actually exist" //This is the name of your shell as you defined in descript.txt in the shell folder.
{
"\s[0]Installed Hypothetical Shell. Truncated for space.\e"
//Replace if needed.
}
elseif reference1 == "Another totally real shell wow" //As in other files, you can use elseif to expand a list like this to include as many shells as you have or think you'll make. See bootend.dic for more details about elseif.
{
"\s[0]Installed another totally real shell.\e"
//Replace if needed.
}
else //For any other shell they may install.
{
"\s[0]Installed a new shell. It's called %(reference1).\e"
//%(reference1) here would be the name of the shell they installed. Replace if needed.
}
}
elseif reference0 == "ghost" //if the type of the file they're installing is a ghost.
{
"\s[0]Installed a new Ghost. It's called %(reference1).\e"
//Reference1 here would be the name of the ghost. Replace as needed.
}
elseif reference0 == "balloon" //if the type of file is a balloon
{
"\s[0]Installed a new balloon. It's called %(reference1).\e"
//Reference1 here would be the name of the balloon. Replace as needed.
}
elseif reference0 == "plugin" //if the type of file is a plug-in
{
"\s[0]Installed a plug-in. It's called %(reference1).\e"
//Reference1 here would be the name of the plug-in. Replace as needed.
}
elseif reference0 == "calendar skin" //if the type of file is a calendar skin
{
"\s[0]Installed a calendar skin. It's called %(reference1)."
}
elseif reference0 == "headline" //if the file/url you drop on them is counted as a headline. To be honest with you I don't know what determines whether a url is a headline or what.
{
"\0\s[0]Set up a headline. It's called %(reference1).\e"
}
elseif reference0 == "rss" //this is more clearly for when you drag an rss feed onto your ghost. you can find rss feeds on sites by looking for the little rss icon, it kind of looks like a little satellite. you can google more info on rss feeds if you're curious! They're neat!
{
"\0\s[0]Set up an RSS feed. It's called %(reference1).\e"
}
else //for any other file they'd install
{
"\s[0]Installed %(reference1)."
}
}
//---- OnInstallFailure -------------------------------------------------------
//If the file you dropped fails to install for one reason or another.
OnInstallFailure
{
"\0\s[0]The installation has failed.\n\n[half]\w5" //this first bit of dialogue begins the explanation of what happened. You can replace this with an appropriate intro statement.
--
if reference0 == "unsupported" //These if statements determine how it happened to finish the piece of dialogue. This checks if the reason it failed is because it was unsupported.
{
"This file is unsupported.\e"
//Replace with whatever dialogue for an unsupported file you may come up with.
}
elseif reference0 == "extraction" //This checks if the file didn't extract properly.
{
"The file could not be extracted properly.\e"
//See above but for a failed extraction.
}
}
//--OnInstallRefuse
//If the file you dropped can't be installed with this ghost.
OnInstallRefuse
{
"\0\s[0]Can't install this. \w4It may be for %(reference0) instead.\e"
//reference0 in this function refers to the ghost this file is associated with, probably the name of the ghost listed in its install.txt file. You would see this if you dropped a shell made for a different ghost on your current ghost, for example. They can't install a shell for themselves they can't use, right? Anyway, replace this with what you wish, you can use the reference0 envelope or not if you want.
}
//**** Uninstallation ******************************************
//You may have noticed in the configuration menus in menu.dic an option to turn Uninstall on or off, as well as a greyed out option to uninstall in the right click menu. These following functions relate to the uninstallation process when it's on. Replace the dialogue in each function as we go along.
//--OnVanishSelecting
//When you select the uninstall option in the menu.
OnVanishSelecting
{
"\0\s[0]The user is deciding whether or not to uninstall us.\w8\1\s[10]If you're testing this, be careful about what you click here, huh?\e"
}
//OnVanishSelected
//When you decide to uninstall them.
OnVanishSelected
{
"\0\s[0]The user has decided to uninstall us. Bye.\w9\w9\e"
}
//--OnVanishCancel
//If you select Uninstall from the menu, but decide not to do it.
OnVanishCancel
{
"\0\s[0]The user has decided not to uninstall us after all.\e"
}
//--OnVanishButtonHold
//This should trigger if you double click the ghost's balloon in the middle of OnVanishSelected above. So it basically cancels their uninstallation. I'd be pretty careful about testing this, and I'd probably just put the line of dialogue into their script input and test it that way instead.
OnVanishButtonHold
{
"\1\s[10]This dialogue displays when the user double clicks on the balloon when we're saying we're going to uninstall ourselves.\e"
}
//---- OnVanished -----------------------------------------
//OnVanished is a weird little function. Basically, if you uninstall a ghost, it'll automatically go back to the last ghost you were using. They'll then say this line of dialogue about the ghost you just uninstalled. This is very annoying to test as you can imagine! But unlikely to come up super often, I bet. Make sure to set up both their poses immediately so they both appear when it switches back to them.
OnVanished
{
"\0\s[0]\1\s[10]%(reference0) has been uninstalled.\w8\0\s[0]Harsh.\e"
//reference0 here is the name of the other ghost.
}
//**** Mail Checking *******************************************************************
//The next set of functions have to do with checking your email. This function is a slippery little thing - I've had people test it following my directions and have it work, but I've never actually gotten it to report back the right amount of emails myself. Very frustrating. But perhaps you'll have more luck with it, haha.
//Girl and Triangle can't actually read your email, they can just tell you how many emails you have. I've seen ghosts that can read the HEADERS of email, but I still don't think ghosts can actually display the contents of an email. You should be using your actual email client for that. It's still kind of a neat feature though.
//*********************Advanced User Info*******************************
//These text boxes are meant for those who have an interest in expanding or using more complicated functions in their ghost. Also for my own reference in the future since I plan on using this template too, haha. If you have no interest in any of this and just want to keep things as simple as possible, feel free to skip these boxes.
//If you want to set up your ghost to check your mail so you can more easily check these messages instead of just writing the dialogue and moving on, it's a little bit tricky, but not super hard.
//Basically, you're going to need to find your POP settings for your email account. Googling your provider + POP should bring it up pretty quick. Once you have the info, you'll go to the right click menu, options, then preferences. A big menu should pop up, and you should see POP in the left side. Click that, and input all the info from the POP page you looked up for your account. Tell your ghost to check your email, and if it works, then congratulations!
//***********************************************************************
//---- OnBIFFBegin ---------------------------------------------------------------
//When you first tell the ghost to check your email. An intro statement, if you will. Replace with whatever you like.
OnBIFFBegin
{
"\0\s[0]This is the starting dialogue for checking email.\e"
"\1\s[10]This is another starting dialogue for checking email.\e"
}
//---- OnBIFFComplete ---------------------------------------------------------------
//After they've succeeded in checking your mail, they'll report back with how many new emails you have. Replace the dialogue with whatever would be character appropriate.
OnBIFFComplete
{
if reference0 == 0 //If you have no new mail.
{
"\0\s[0]There is no new mail.\e"
}
elseif reference0 == 1 //If you have one new email.
{
"\0\s[0]There is one new email.\e"
}
elseif reference0 > 1 && reference0 < 11 //If you have more than one email but less than eleven.
{
"\0\s[0]There are %(reference0) emails.\e"
//reference0 here stores the amount of new email it finds.
}
elseif reference0 > 100 //If there are over one hundred new emails.
{
"\0\s[0]There are %(reference0) emails unread.\w8\1\s[10]Woah.\e"
}
else //For any other number of emails.
{
"\0\s[0]There are %(reference0) emails.\e"
}
}
//---- OnBIFFFailure ---------------------------------------------------------------
//Various error messages that can happen when your ghost tries to connect to an email account. Replace the dialogue as appropriate.
OnBIFFFailure
{
if reference0 == "timeout" //If the connection times out.
{
"\0\s[0]The connection has timed out.\e"
}
elseif reference0 == "kick" //If the account blocks the ghost from accessing it. I think gmail may do this at first to try and protect your account from unapproved applications using it. It gives you the option to change the setting in the warning email they send you about it.
{
"\0\s[0]We can't access the account.\e"
}
elseif reference0 == "defect" //If the information put into the POP menu is wrong.
{
"\0\s[0]The email account was not set up properly.\w8\1\s[10]It can be reset at the POP menu.\w8\![open,configurationdialog]\e"
//Note that this ends with \![open,configurationdialog]. This will open up the preferences menu I described above automatically. More on \! functions in the walkthrough. You can delete the \! tag here if you want to.
}
else //if there's some other kind of error.
{
"\0\s[0]We can't connect to the account.\w8\1\s[10]The error returned is '%(reference[0])'.\e"
//reference0 here stores the error message the email server would have given the ghost, hopefully.
}
}
//**** Network Update *****************************************************************
//The following functions are for the Network Update of your ghost, where it will connect to your website, check for new files, and update itself. This is a handy feature, but tricky to set up. If you have no intention of using Network Update, you can disregard these, but it won't hurt to fill them out anyway just in case. More details about how to set up Network Update are in the walkthrough (http://www.ashido.com/ukagaka/).
//Replace the dialogue in the next set of functions as appropriate. You can easily test these messages using the Developer panel. Go to Open at the bottom of it and choose one of the four Update Event options to simulate a Ghost's update process. I highly recommend doing this at LEAST once if you're going to use this feature to make sure it flows well.
//---- OnUpdateBegin -------------------------------------------------------------
//When you first tell your ghost to update. An introductory statement, like OnBIFFBegin above. Replace or add more dialogue as appropriate. Note that they end with \w8 to give a little breather time.
OnUpdateBegin
{
"\0\s[0]Starting the update process.\w8\e"
"\1\s[10]Another message for starting the update process.\w8\0\s[0]Hope you read the directions properly.\w8\e"
}
//---- OnUpdateReady ---------------------------------------------------------
//If the ghost finds new files to update with.
OnUpdateReady
{
reference0++ //makes sure it starts at 1 instead of 0
"\1\s[10]There are %(reference0) new files.\w8\e"
//reference0 here storing the number of new files. You don't have to use it if you don't want to.
}
//---- OnUpdateComplete -------------------------------------------------------------
//When the ghost has finished the update process.
OnUpdateComplete
{
if reference0 == "none" //if the ghost had nothing to update with
{
"\1\s[10]There are no new files.\e"
"\1\s[10]This is another message about there being no new files to update with.\e"
}
else //if the ghost has updated successfully
{
"\1\s[10]Update successful!\e"
}
}
//---- OnUpdateFailure -------------------------------------------------------------
//Error messages if the update process fails in some way.
OnUpdateFailure
{
_file = SPLITPATH(reference1)[2] + SPLITPATH(reference1)[3] //This gets the name and extension of the offending file
if reference0 == "timeout" //if the connection times out
{
"\1\s[10]The update connection has timed out.\e"
}
elseif reference0 == "md5 miss" //This is the final message displayed when you've run into an md5 error below at some point.
{
"\1\s[10]The MD5 hash of %(_file) doesn't match.\e"
}
else //for other errors
{
"\1\s[10]The update could not be completed.\w8\0\s[0]The error is '%(reference0)'.\e"
}
}
//---- OnUpdate.OnDownloadBegin ------------------------------------------------
//This dialogue plays when they begin downloading a new file. WARNING: if you have big plans for your ghost and are going to make a lot of new image files for it (like... i do, cough) at some point, you're going to want to make these messages very brief, if you even have them at all. The reason is because the user will see these messages for EVERY individual file that they have to download, and if you have, say, 50 pna files in the queue, they will see this dialogue 50 times. Not only that, but displaying the dialogue takes some time, so it also extends the download process.
//If you aren't planning on adding a ton of files at any point, or are only intending to update the .dic files which will be at most a handful of files, then you can go ahead and put a short message in here. But if your ghost is going to grow in leaps and bounds as you work on it, try and keep these messages as brief as possible (or again, just make it "" to have there be no message at all) to make the process that much faster for your user.
OnUpdate.OnDownloadBegin
{
if "aitalk" _in_ reference0 //this is checking to see what kind of files are being downloaded. In this case, it's looking for files called aitalk in the download queue. If you want to have a specialized bit of dialogue for each type of file, you can expand this with elseifs and by replacing aitalk with whatever file you have in mind. Keep in mind my warning above though.
{
"\0\s[0]We are going to download more dialogue.\w8\1\s[10]It's in the aitalk file.\e"
}
else //for files not specified above
{
"\1\s[10]This is dialogue for finding a new file.\e"
"\0\s[0]This is another bit of dialogue for finding a new file.\e"
}
}
//---- OnUpdate.OnMD5CompareBegin ---------------------------------------------------
//This checks the hash value of the files in the directory and the files listed in updates.dau, I believe. It will do this for every file the user downloads, so I again remind you of my warning above! For every file they download, they will have to go through three sets of unique dialogue, and it can get old fast. Not to mention it slows things down a lot. Again, I would recommend keeping this very brief, if not just replacing it with "" instead.
OnUpdate.OnMD5CompareBegin
{
"\1\s[10]Checking the MD5 value.\e"
}
//---- OnUpdate.OnMD5CompareComplete --------------------------------------------------
//After they've checked the MD5 value and it matches. See above about the length of this message.
OnUpdate.OnMD5CompareComplete
{
"\0\s[0]MD5 check good.\e"
}
//---- OnUpdate.OnMD5CompareFailure ---------------------------------------------------
//If the MD5 values don't match, meaning if the file is missing or damaged or incomplete in some way. If you follow my Network Update directions carefully, this shouldn't come up very often, but don't be surprised if you run into it every now and then by forgetting a file here or there.
OnUpdate.OnMD5CompareFailure
{
"\0\s[0]The MD5 values don't match.\w8\e"
}
//**** Headlines and RSS Feeds *********************************************************
//This section has to do with the RSS feeds option on your ghost. If you drag and drop a url on them, they'll add it to a list you can access via the right-click menu, and they'll tell you the last set of updates for the site. This works best with RSS feeds I think, but you can experiment with other sites to see how it works.
//The headlines you see under the tab are in the headline folder under your base SSP install. So it'd be SSP\headlines. You should see the folders for each linked headline in there. I've very rarely ever messed with them or used them. Likewise, your RSS feeds you've added will be under SSP\rss and I don't think that option will appear in the headlines/RSS tab until you add an RSS feed to a ghost. If you want to clear your RSS feeds or headlines, just delete either of those two folders.
//---- OnHeadlinesenseBegin -----------------------------------------------------------
//This dialogue comes up when you select something in your RSS feed as an intro, like the other On[Thing]Begin things we've seen so far. Replace as you need.
OnHeadlinesenseBegin
{
"\0\s[0]You've selected %(reference0).\e"
}
//---- OnHeadlinesense.OnFind --------------------------------------------------------
//This actually displays the feed. My set-up for it is pretty simple but gets the job done, it just has the name of the feed, a line space, then a list of links. You shouldn't have to edit any of these and I probably wouldn't honestly.
OnHeadlinesense.OnFind
{
//---- What page You're on
if reference2 == "First" || reference2 == "First and Last"
{
//---- First page
"\0\b2\s[0]%(reference0):"
}
elseif reference2 == "Next"
{
//---- Second page
"\0\b2\s[0]%(reference0):"
}
elseif reference2 == "Last"
{
//---- Last page
"\0\b2\s[0]%(reference0):"
}
--
//---- Headlines
"\n\n%reference3\n"
--
//---- Pages
if reference2 == "First" || reference2 == "Next"
{
//---- Bottom buttons
"\![*]\q[Next,] - \![*]\q[Stop,Headline_Cancel]\e"
}
else
{
//---- Bottom buttons
"\![*]\q[Stop,Headline_Cancel]\e"
}
}
Select.Headline_Cancel
{
"\0\s[0]Headline viewing complete.\e"
//Actually I take that back, you can change this line of dialogue here for when you're done looking at a headline to something else if you want.
}
//---- OnHeadlinesenseComplete -------------------------------------------------------
//This is an odd function. As far as I can gather, this is if the headline information gathering was successful, but there's no new information to report. Possibly if none of the feeds have updated? I'm a little fuzzy on this one.
OnHeadlinesenseComplete
{
"\0\s[0]No update. %(reference0).\e"
//reference0 here supposedly always stores the value no update? Again this isn't hugely clear from what I can see. Anyway, this dialogue has never come up for me while using a ghost, so perhaps someone else who runs into it can offer more clarity. For now, you can leave it as is, or write up something else in here if you like.
}
//---- OnHeadlinesenseFailure ---------------------------------------------------------
//This one is more clearly for when the ghost can't get the information it needs about the RSS feed in question.
OnHeadlinesenseFailure
{
"\0\s[0]The feed can't updated.\w8\1\s[10]Why not?\w8\0\s[0]\n\n[half]" //This sets up an exchange between the two characters. The final part of the exchange continues below in the if statements.
--
if reference0 == "can't download" //if they can't download the rss feed for some reason
{
"It can't be downloaded."
}
elseif reference0 == "can't analyze" //if they can't read the file for some reason
{
"It can't be analyzed."
}
else //other errors
{
"I don't know."
}
--
"\e" //And here is the final /e, so you don't need to include it in the if statements above. Another one of the very rare cases this occurs.
}
//**** Ghost Creation and Updating ******************************************************
//These next few are related to creating updates2.dau and .nar files for your ghosts. You'll want to at least make a .nar to distribute your ghost, and if you're going to be using Network Update, you'll also want to make updates2.dau as well. It's unlikely that anyone other than you will see these messages, but they can be fun to add some color to while you're developing. I gave Temmie some silly ones and they make me smile each time I update her.
//Primarily, you will see these messages when you're creating your updates file or updating your ghost.nar file. More on this on the walkthrough page. However, you can drag and drop another ghost's folder onto them and they'll also create a nar for that as well, if for some reason you want to do that.
//---- OnUpdatedataCreating -----------------------------------------------------------
//This will begin the creation of the updates2.dau file. Not unlike the other beginning functions you've seen throughout this file. Replace with whatever you like.
OnUpdatedataCreating
{
"\1\s[10]Creating the updates2.dau file.\e"
}
//---- OnUpdatedataCreated -------------------------------------------------------------
//After the updates2.dau file has been successfully created. Replace with whatever.
OnUpdatedataCreated
{
"\0\s[0]Successfully created updates2.dau.\e"
}
//---- OnNarCreating ------------------------------------------------------------------
//Along the same lines, this is when they begin creating a .nar file for your ghost. .nars are the format most ghosts will be in, something similar to a .zip file, and this is the format you'll be distributing your ghost in most likely. Replace the dialogue with whatever you like.
OnNarCreating
{
"\0\s[0]Creating the .nar file.\e"
}
//---- OnNarCreated -------------------------------------------------------------------
//After the nar file has been successfully created.
OnNarCreated
{
"\0\s[0]Successfully created '%(reference0)'.\e"
//reference0 here will be the filename of the nar you just created. It should drop the nar in the folder where all your ghosts are listed, ssp\ghost\.
}
//**** Clock Synchronization **********************************************************
//**** 미카 (http://homepage2.nifty.com/ko-ki/)의 사전을 참고했습니다.감사>こ 나무 성
//This set of functions was done by the above Korean coder, I think. I'll leave their comment there untouched.
//If you right click your ghost and go into the Utilities menu, there's an option called NTP Time Sync. That's what this is for!
//----OnSNTPBegin ------------------------------------------------------------------
//As with the others you've seen above, this is the beginning bit of dialogue for this process.
OnSNTPBegin
{
"\0\s[0]We're going to check the time.\w9\1\s[10]We are connecting to %(reference0).\e"
//%(reference0) here is the site they'll be using to check your clock. I wouldn't worry too much about what the site is or where it's defined, it should be accurate. Replace the dialogue with what you need, you don't have to use reference0 if you don't want to.
}
//---- OnSNTPCompare----------------------------------------------------------
//Now the ghost is going to compare the current time of your computer's system to the time of the site they connected to. Most of this you don't have to touch, just replace the dialogue as indicated.
OnSNTPCompare
{
"Retrieved Time: %reference1[1]/%reference1[2]/%reference1[0] %reference1[3]:%reference1[4]:%reference1[5]\w2\n/
Your Time: %reference2[1]/%reference2[2]/%reference2[0] %reference2[3]:%reference2[4]:%reference2[5]\w2\n/
\n"
--
if reference3 == 0 //if your clock is already accurate.
{
"\0\s[0]Your clock is accurate.\e" //replace this with whatever message you like.
}
else //if your clock doesn't match
{
//you can redo this top line up to the \n\n[half] part, but leave the \q options alone.
"\0\s[0]Your clock doesn't match.\w6\nShould we fix it?\n\n[half]/
\![*]\q[Fix it,OnSNTPEXECUTE]\n/
\![*]\q[Leave it alone,OnSNTPCANCEL]\e"
}
}
//---- OnSNTPEXECUTE ------------------------------------------------------------------
//After they've fixed your clock. Note the \6 tag - that's what actually changes the clock. Do not remove that tag. Replace the rest with what you want.
OnSNTPEXECUTE
{
"\0\s[0]The clock has been fixed.\6\e"
}
//---- OnSNTPCANCEL ------------------------------------------------------------------
//If you decide not to change your clock when they tell you it doesn't match. Replace with what you want.
OnSNTPCANCEL
{
"\0\s[0]The user decided not to change the clock.\e"
}
//---- OnSNTPFailure ------------------------------------------------------------------
//If they can't change the clock for some reason, possibly because the site timed out but it could be anything. Replace with what you want.
OnSNTPFailure
{
"\0\s[0]The clock wasn't changed.\w8\1\s[10]Something went wrong.\e"
}
//--OnDisplayChange----------------------------------------------------------------
//This is when you change the resolution of your monitor while your ghost is running. Don't mess with any of this, it should be fine as is.
OnDisplayChange
{
displaybpp = reference0
displaywidth = reference1
displayheight = reference2
}
//---- OnScreenSaverStart -------------------------------------------------------
//This happens if your ghost is running when your screensaver starts up. I've never got this to trigger but I love this idea, and I feel like there's a way to do it I haven't figured out yet. So you can skip these for now if you want, but if I do ever get it working, I'll come back and make a note of it.
OnScreenSaverStart
{
"\0\s[0]The screensaver is starting.\w7\1\s[10]Wiggle your mouse!\e"
//Replace with what you want.
}
//---- OnScreenSaverEnd -------------------------------------------------------
//When you wiggle your mouse and stop your screensaver.
OnScreenSaverEnd
{
"\0\s[0]The screensaver is gone.\e"
//Replace with what you want.
}
//---- OnApplicationBoot ---------------------------------------------------------------
//This supposedly is for when a program starts but I have honestly never gotten it to work or seen it happen. I wouldn't sweat these three related functions too much.
OnApplicationBoot
{
"\0\s[0]%(reference0) just started.\e"
}
//---- OnApplicationClose --------------------------------------------------------------
//See above, but for the program closing.
OnApplicationClose
{
"\0\s[0]%(reference0) has closed.\e"
}
//---- OnApplicationFileOpen ----------------------------------------------------------
//I believe this is for when the program detailed above opens a document file of some kind.
OnApplicationFileOpen
{
"\0\s[0]Opening %(reference1).\e"
}
//---- OnBatteryLow -----------------------------------------------------------------
//This is for when your laptop's battery is low. I don't have a laptop, so I've never really been able to test this. Perhaps someone with a laptop can report back to me with more details about the battery related functions?
OnBatteryLow
{
"\1\s[10]The laptop's battery is low. \w8\0\s[0]There is %(reference0) power left.\e"
//reference0 here is the amount of battery power. Replace as you like.
}
//--OnBatteryCritical-----------------------------------------------------------------
//Likewise, this is for if your battery is REALLY low. Replace as you like.
OnBatteryCritical
{
"\0\s[0]The laptop's battery is critically low.\e"
}
//--OnBatteryNotify--------------------------------------------------------------------
//This I believe checks to see if your laptop is plugged in or not. Originally this bit of code was commented out, so I suspect it may not work. It may need a plug-in of some sort. Either way, you can delete it or fill it out as you like.
//Actually investigating this, leaving this in makes it so the ghost updates you about whether or not your computer is plugged-in constantly, which makes no sense for desktops. No doubt why it was commented out. You can delete it or just leave it be.
/*
OnBatteryNotify
{
if reference2 == "online" //If your laptop is plugged in
{
"\0\s[0]The laptop is plugged in.\e"
}
elseif reference2 == "offline" //If you unplug your laptop
{
"\1\s[10]The laptop is not plugged in.\w8\0\s[0]Watch your battery.\e"
}
}
*/
//--OnShellScaling
//This is a function however that you may actually use! Or at least, I often use it when desktop space is at a premium (which it always is on my computer). If you right click the ghost, you can go to Shell Scaling, which lists a number of different percentages. Those are the percentages your ghost can be scaled in size up or down. You can try them out yourself to get an idea of what I mean. I often scale mine down to get them out of the way sometimes. This adds dialogue whenever you change their scale. You don't have to do this if you don't want to, in which case they will just stay silent when you size them up or down. If that's what you want, just delete the whole thing or leave "" instead of any dialogue.
OnShellScaling
{
if reference0 >= 150 //this number is the percentage that you're scaling the ghost up to. In this case, it's 150%.
{
"\0\s[0]We are now 150% our original size.\w8\1\s[10]Bigger.\e"
}
elseif reference0 == 100 //this is 100%
{
"\1\s[10]We are normal sized.\e"
}
elseif reference0 == 50 //this is 50%. You can add any percentage that's listed under shell scaling if you want using more elseifs.
{
"\0\s[0]We are now 50% our original size.\w8\1\s[10]Smaller.\e"
}
}
//--OnFileDrop2
//OnFileDrop2 handles how your ghost will set an image as the desktop background when someone drags and drops an image on them. You don't need to touch any of the coding here, just replace the dialogue as needed and leave the \q options alone. More about \q options in bootend.dic and in the walkthrough.
OnFileDrop2
{
_filepath = SPLITPATH(reference0)
_filename = _filepath[2]
_fileext = TOLOWER(_filepath[3])
case _fileext
{
when ".jpg", ".jpeg", ".bmp", ".png" //These are the formats your ghost will recognize as image files to set as the background.
{
Wallpaperfile = reference0
"\0\s[0]The file you dropped is %(_filename)%(_fileext).\w8\1\s[10]How would you like us to set this picture as your wallpaper?\n\n[half]/
\![*]\q[Centered,SetWallpaper_0]\n/
\![*]\q[Tiled,SetWallpaper_1]\n/
\![*]\q[Stretched,SetWallpaper_2]\n\n[half]/
\![*]\q[No thanks,SetWallpaper_Cancel]\e"
}
when ".mid", ".wav", ".mp3", ".wma", ".au" //Other file formats you might want to give your ghost a specific response to.
{
"\1\s[10]%(_filename)%(_fileext) is a music file.\e"
}
others //Any other file format. As a note here, if you drop something ghost-related on them that does not have an install.txt, then they won't install it and will just say this response. If you are testing your balloon or nar files and you get this response instead of a proper installation, you should check and make sure you have an install.txt in the file!
{
"\0\s[0]This is %(_filename)%(_fileext).\e"
}
}
}
//This set of options sets the wallpaper up. You can replace the dialogue, but make sure to leave the \![set,wallpaper, etc.] tag at the beginning.
Select.SetWallpaper_0
{
"\![set,wallpaper,%(Wallpaperfile),center]\0\s[0]The image is centered.\e"
}
Select.SetWallpaper_1
{
"\![set,wallpaper,%(Wallpaperfile),tile]\0\s[0]The image is tiled.\e"
}
Select.SetWallpaper_2
{
"\![set,wallpaper,%(Wallpaperfile),stretch]\0\s[0]The image is stretched.\e"
}
Select.SetWallpaper_Cancel
{
"\0\s[0]You don't want to set the file as your desktop background.\1\s[10]Kay.\e"
}

BIN
ghost/master/findwin.dll Normal file

Binary file not shown.

BIN
ghost/master/gomi.dll Normal file

Binary file not shown.

BIN
ghost/master/lyuma.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
ghost/master/mciaudior.dll Normal file

Binary file not shown.

693
ghost/master/menu.dic Normal file
View File

@ -0,0 +1,693 @@
//---------------------------Menus--------------------------
//This .dic file is primarily concerned with the double-click menus for each of your ghosts. If you don't want to have menus for your characters, you'd just have to delete the OnMouseDoubleClick functions near the end of mouse.dic and then ignore this file, as none of it will be called I believe. Menus can be cool though, since you can put stuff in them and create new functions if you know what you're doing. For example, I've added a lot of games and interactions and little linked icons to my Hunter Smoker ghost to keep track of their feelings and such. Much of that is pretty complicated though (and kind of messy, cough), so I won't go into it here, but I covered some of the concepts in the coding page of the walkthrough, and enterprising ghost makers can study the menu.dic file I set up for Hunter/Smoker and see how I put it together.
//The complexity of this file depends on how customized you want your menus. If you just want to leave them as they are, then all you'll have to do is replace dialogue appropriately. Many of the options here can be ignored if you don't care. You only have to fill in the things that interest you! The default template dialogue will handle anything you don't. If you get bored or tired, you can skip a lot of these if it comes down to it. You can always go back and fill them in later too. Your ghost will function fine either way!
//And of course, this file will always be waiting for you when you've gotten more familiar with ghosts and want to add cool features! It can be a flexible playground, but don't feel too stressed out about it. As mentioned, just fill in what comes to you and the template dialogue will cover the rest.
//Make sure to read the walkthrough (http://www.ashido.com/ukagaka/) for more details about how to properly format ghost dialogue!
//I will reiterate that you should be editing these in Notepad++, and in particular, you should set the Language to C (or Java I guess) to properly highlight all the text. It will make things A LOT EASIER for you, trust me! It will also help you keep track of your brackets in case you forget some. If you click on a line with a bracket in Notepad++, it should highlight where the other bracket ends, or turn purple if there's no finishing bracket (which you should definitely fix!)
//It will also highlight my commented lines in green, so you'll know where they are. Any line beginning with // is a commented line that the code will not read. It's just for your reference!
//If you see a big block of commented text you want to uncomment, highlight the text and then hit ctrl-shift-k in Notepad++ and that should uncomment it. Mostly this is intended for advanced users.
//--OpenSakuraMenu
//This is a bit of intro dialogue before the main character opens their menu. You can see below that there are three pieces of separate dialogue listed before it goes to MenuRun. The character will randomly choose one of those pieces of dialogue before opening the rest of their menu. You can customize this with individual greetings for the character, such as "Yes, %(username)?" or "Need something, %(username)?" or things like that. Note that none of the lines end with \e!
//The \b2 tag tells the ghost to use their big balloon for this dialogue. If your menu has a lot of stuff, this'll probably look better than the small one.
//If you don't want multiple responses before opening the menu, you can delete the dialogue and just leave MenuRun.
OpenSakuraMenu
{
"\0\s[0]\b2This is the first random menu open dialogue."
"\0\s[0]\b2This is the second random menu open dialogue."
"\0\s[0]\b2This is the third random menu open dialogue."
--
MenuRun
}
//--MenuRun
//As you just saw above. This actually fills out the rest of the menu. If you're going to be adding or changing functions, this is where you'll be doing your edits.
MenuRun : all
{
wd = GetWeekDay
ap = GetAP
//These four statements basically get the day of the week, whether it's AM or PM, the hour, and the time. It's putting together the information to display the time at the bottom of the balloon. Pay it no mind.
--
"\n\n\_q\b2" //The \n\n means two new lines as detailed in the walkthrough, and \_q means quick session, meaning all the text from this point on will display instantly instead of a few letters at a time like normal ghost dialogue. You can ignore it.
--
if lastTalk != "" //What this does is check to see if the ghost has already said a random bit of dialogue on its own, essentially by seeing if the lastTalk thing is NOT empty (!= means "does not equal").
{
"\![*]\q[Repeat Last Dialogue,OnLastTalk]\n\n[half]"
//If the ghost has said something, it will then display this menu option. You can replace "Repeat Last Dialogue" with whatever caption you like, such as "What were you saying?" or "What did you say?" or "Could you repeat that?" or something like that.
//*********************Advanced User Info*******************************
//These text boxes are meant for those who have an interest in expanding or using more complicated functions in their ghost. Also for my own reference in the future since I plan on using this template too, haha. If you have no interest in any of this and just want to keep things as simple as possible, feel free to skip these boxes.
//I briefly touched in bootend.dic about \q, but I'll again cover it here. Pay very close attention to how this bit of dialogue is formatted. You'll see it goes \![*]\q[Displayed Name,linkedfunction]. Breaking it down, \![*] puts the balloon's option icon in front of the choice (usually a > or something), \q sets up the choice, Displayed Name which is the text that will display in the ghost's balloon, then linkedfunction, which is what the choice is linked to when the user clicks it. As you go through this file, look at how every menu option is set up, and you will see they all follow this format, give or take a \![*]. If you're going to be adding new options to menus or creating your own functions and such, make sure you follow this format and learn it well. Make sure to read the coding page of the walkthrough.
//***********************************************************************
}
--
"\![*]\q[Say something,OnAiTalk]\n"
//"\![*]\q[Say something 2,OnAiTalk]\n"
//This option will force the ghost to say something from aitalk if the user clicks it. Just replace "Say something" with whatever caption you think would be appropriate.
//Advanced users, you can add multiple captions for any option you add to a menu you make just like this, as long as you separate it from the other options into its own section with two dashes above and below. Note that you can't do this if the Function above has ": all" after it, since that will put every potential option in. You'll have to set it your menu up differently to take --s into account. I commented it out here because of ": all" above, but you can see the basic idea.
--
"\![*]\q[Config Menu,configmenu]\n"
"\![*]\q[Functions,dosomething]\n\n[half]"
"\![*]\q[Nevermind,CANCEL]\n\n\n[half]%(wd) %(nowhour):%(nowmin) %(ap), %(month)/%(day)/%(year)\e"
//These three lead to the Config Menu, the Function menu, and Cancel. You can leave these alone if you like. All the envelopes at the end (see word.dic) basically display the year, month, day, weekday, and time.
}
//Leave this alone
OnLastTalk
{
"%(lastTalk)\e"
}
//This is figuring out what day of the week it is. Leave it alone.
GetWeekDay
{
if weekday == 0
{"Sun"}
elseif weekday == 1
{"Mon"}
elseif weekday == 2
{"Tue"}
elseif weekday == 3
{"Wed"}
elseif weekday == 4
{"Thu"}
elseif weekday == 5
{"Fri"}
else
{"Sat"}
}
//This is finding out whether it's AM or PM. Leave it alone.
GetAP
{
if hour >= 0 && hour <= 11
{"AM"}
else
{"PM"}
}
nowhour
{
if hour12 == 0; "1"
else; "%(hour12)"
}
nowmin
{
if minute >= 0 && minute <=9; "0%(minute)"
else; "%(minute)"
}
//If someone selects an option linked to BACKTOMENU, it will go back to MenuRun.
//Advanced users, note that this is formatted as Select.linkedfunction? Remember how it went \q[Displayed Name,linkedfunction] above? When a user clicks an option that doesn't begin with On, they'll be linked to Select.linkedfunction. Pay close attention as we go through and you'll see this in action.
Select.BACKTOMENU
{
MenuRun
}
//If someone selects configmenu, this will lead to TalkConfig.
Select.configmenu
{
TalkConfig
}
//*********************Advanced User Info*******************************
//Some of you may be wondering why some of these Select.options lead to another function. Why not just put the config menu coding under Select.configmenu, instead of linking to TalkConfig?
//Basically any function that's preceded with Select. is limited in its complexity and can only be called within its own .dic file in my experience. Why should you care, you ask? Well, if you're going to link to this function any other way, such as linking it in other .dic files or as a page in a menu, it needs to be a stand-alone function so it can be properly called. I'm pretty sure.
//The basic jist is this; if you're going to reuse whatever it is the option leads to, you should make it its own function. Otherwise, you can leave it in Select.option. As a rule of thumb I'd probably put any complicated stuff in its own function, then use the Select.option to call the full function as you can see above. Simple dialogue responses to a choice can stay as a Select.option though (Like "Do you like going to raves and partying? Yes/No"). Study what stays as a Select.option and what links to another Function as we go through the file.
//***********************************************************************
//--TalkConfig
//This menu allows the user to change their name and other information, as well as put in their birthday and change how often the ghost speaks. You can restructure how this looks if you want, but it's perfectly functional as is. You can of course change the dialogue though if you like.
//I commented out birthday and pronoun options, you can uncomment them if you want to add them back. They are optional! It's up to you if you want those features or not.
TalkConfig : all
{
"\0\b[2]\_q\"
//This bit of dialogue sets up a large balloon and a quick session, like above, so all the text will appear immediately. The rest is formatted to display the information and options to change it. I wouldn't touch any of it if you don't know what you're doing.
//I'll briefly explain the font tags I used here. \f[bold,1] turns bold on, \f[bold,0] turns it off, not unlike a <b> tag. \f[sup,1] turns superscript on (making it tiny and above the text) and \f[sup,0] turns it off. I touch on these tags in the walkthrough on SakuraScript.
"f[bold,1]Your name:\f[bold,0] %(username) \f[sup,1](\q[Change it?,TEACHNAME])\f[sup,0]\n"
//If you want your user to set their pronouns, you can uncomment this menu option by removing the two slashes in front. Read more on the walkthrough about commenting.
//"\f[bold,1]Your pronouns:\f[bold,0] %(heshe)/%(himher)/%(hisher) \f[sup,1](\q[Change them?,TEACHPRONOUN])\f[sup,0]\n"
//If you want your user to be able to set their birthday, you can uncomment this menu option.
//"\f[bold,1]Your birthday:\f[bold,0] %(birthdayprint) \f[sup,1](\q[Change it?,TEACHBDAY])\f[sup,0]\n"
"\n\f[bold,1]Talk Rate:\f[bold,0] - every %(talktime) \f[sup,1](\q[Change it,talkinter])\f[sup,0]\n\n"
{
"\![*]Enable Uninstall? (NOW : %(deleteshitai))\n\q[ON,deleteon] \q[OFF,deleteoff]\n\n[half]\n"
}
"\![*]\q[Back to the menu,BACKTOMENU]\e"
}
// ______ _____ _ _
// | ___ \ / ___| | | |
// | |_/ / __ ___ _ __ ___ _ _ _ __ ___ ______ \ `--.| |_ __ _ _ __| |_
// | __/ '__/ _ \| '_ \ / _ \| | | | '_ \/ __| |______| `--. \ __/ _` | '__| __|
// | | | | | (_) | | | | (_) | |_| | | | \__ \ /\__/ / || (_| | | | |_
// \_| |_| \___/|_| |_|\___/ \__,_|_| |_|___/ \____/ \__\__,_|_| \__|
//This and the next few set up the pronouns, as you can see by the linkedfunction names. You can replace "\0\s[0]What pronouns do you want?" with your own dialogue if you prefer, but leave the rest of it alone.
//If you're not going to add this feature, you can ignore these. I marked where the pronoun section begins and ends with some ascii banners. :3
Select.TEACHPRONOUN : all
{
"\0\s[0]What pronouns do you want?\w5\n\n[half]\_q"
"\![*]\q[He-His-Him,choicemasc]\n"
"\![*]\q[She-Her-Her,choicefem]\n"
"\![*]\q[They-Their-Them,choiceneither]\e"
}
Select.choicemasc
{
presuffix = "masculine"
himher = "him"
heshe = "he"
hisher = "his"
hesshes = "he's"
--
"\0\s[0]The pronouns are now he him and his.\e"
//Leave the part above the double dashes alone. You can replace the snip of dialogue however with whatever you like.
}
Select.choicefem
{
presuffix = "feminine"
himher = "her"
heshe = "she"
hisher = "her"
hesshes = "she's"
--
"\0\s[0]The pronouns are now she her and her.\e"
//as above, you can also replace this dialogue.
}
Select.choiceneither
{
presuffix = "undefine"
himher = "them"
heshe = "they"
hisher = "their"
hesshes = "they're"
--
"\0\s[0]The pronouns are now they them and their.\e"
//and this one.
}
//Here are some examples of these envelopes in use.
//"%(heshe) left that there."
//"%(hisher) work is really cool."
//"I'll ask %(himher) later."
//"%(hesshes) really good at it."
//These envelopes only apply if the pronouns are set! If the user can't set their pronouns, that then you don't have to think about these envelopes.
// ______ _____ _
// | ___ \ | ___| | |
// | |_/ / __ ___ _ __ ___ _ _ _ __ ___ ______ | |__ _ __ __| |
// | __/ '__/ _ \| '_ \ / _ \| | | | '_ \/ __| |______| | __| '_ \ / _` |
// | | | | | (_) | | | | (_) | |_| | | | \__ \ | |__| | | | (_| |
// \_| |_| \___/|_| |_|\___/ \__,_|_| |_|___/ \____/_| |_|\__,_|
//These two options toggle whether or not you can delete your ghost. Leave them alone.
Select.deleteon
{
deleteshitai = "ON"
TalkConfig
}
Select.deleteoff
{
deleteshitai = "OFF"
TalkConfig
}
// ____ _ _ _ _ ____ _ _
// | __ )(_)_ __| |_| |__ __| | __ _ _ _ / ___|| |_ __ _ _ __| |_
// | _ \| | '__| __| '_ \ / _` |/ _` | | | | _____ \___ \| __/ _` | '__| __|
// | |_) | | | | |_| | | | (_| | (_| | |_| | |_____| ___) | || (_| | | | |_
// |____/|_|_| \__|_| |_|\__,_|\__,_|\__, | |____/ \__\__,_|_| \__|
// |___/
//This next set of functions handles inputting the user's birthday. If you don't want this to be a feature, you can ignore all of this. I marked where the birthday code starts and ends for you with some good old-fashioned ascii banners. :3
Select.TEACHBDAY
{
"\0\s[0]What month were you born? \w8Name or number is fine.\![open,inputbox,OnUserBornMonth,-1]\e"
//You can replace the dialogue up to the \![open,inputbox,OnUserBornMonth,-1] tag, leave that alone. You'll need the input box to get the information.
//*********************Advanced User Info*******************************
//I also touched on this in bootend.dic and explained it in the walkthrough page on coding, but I'll also go into it here. I'm going to break down the tag there at the end of the sentence so you know what it's doing. Basically, \! means a function is going to happen, open tells it to open something, inputbox tells it to open an input box, and OnUserBornMonth is the function the input box will be linked to, which is just below here. -1 means the input box should not time out. If you want to add input boxes to some new function for whatever reason, you should follow this basic format.
//On a related note, you can raise any function at the end of any piece of dialogue by using this format - \![raise,InsertFunctionName]. This can be handy for testing things if the function is hard to get to run otherwise.
//***********************************************************************
}
//--OnUserBornMonth
//This takes the value that the user put into the input box above and evaluates it. Most of this you won't have to touch, but I'll explain what it's doing anyway. I'll point out where you can change the dialogue.
OnUserBornMonth
{
_tempmonth = TOSTR(reference0) //this stores what the user put in as a variable called _tempmonth
_tempmonth = TOLOWER(_tempmonth) //changes it to lowercase
//this is attaching the right value to the input from the user
if _tempmonth == "january" || _tempmonth == "1" {bornmonth = 1; bornmonthprint = "January"}
elseif _tempmonth == "february" || _tempmonth == "2" {bornmonth = 2; bornmonthprint = "February"}
elseif _tempmonth == "march" || _tempmonth == "3" {bornmonth = 3; bornmonthprint = "March"}
elseif _tempmonth == "april" || _tempmonth == "4" {bornmonth = 4; bornmonthprint = "April"}
elseif _tempmonth == "may" || _tempmonth == "5" {bornmonth = 5; bornmonthprint = "May"}
elseif _tempmonth == "june" || _tempmonth == "6" {bornmonth = 6; bornmonthprint = "June"}
elseif _tempmonth == "july" || _tempmonth == "7" {bornmonth = 7; bornmonthprint = "July"}
elseif _tempmonth == "august" || _tempmonth == "8" {bornmonth = 8; bornmonthprint = "August"}
elseif _tempmonth == "september" || _tempmonth == "9" {bornmonth = 9; bornmonthprint = "September"}
elseif _tempmonth == "october" || _tempmonth == "10" {bornmonth = 10; bornmonthprint = "October"}
elseif _tempmonth == "november" || _tempmonth == "11" {bornmonth = 11; bornmonthprint = "November"}
elseif _tempmonth == "december" || _tempmonth == "12" {bornmonth = 12; bornmonthprint = "December"}
else //if the month isn't a valid month, like 32 or something.
{
"\0\s[0]That's not a valid month. Try again."
--
"\![open,inputbox,OnUserBornMonth,-1]\![set,balloontimeout,-1]\e"
//You can replace this dialogue in the first line. You need to leave the tag for the input box so they can put in a correct month. That last tag there for ![set,balloontimeout,-1] makes it so the input box won't time out if the user takes too long.
}
--
//If it's a valid month
"\0\s[0]So you were born in %(bornmonthprint).\n\w8What day was it?"
--
"\![open,inputbox,OnUserBornDay,-1]\![set,balloontimeout,-1]\e"
//Here you can see the use of a bornmonthprint envelope to show the user what month they put in. Notice that it opens an inputbox at the end the same way the one above did. You can replace the dialogue in the first line just as with above.
}
//This adds an appropriate suffix to the number for the day. No need to mess with this.
Printday
{
if bornday == 1 || bornday == 21 || bornday == 31
{ "%(bornday)st" }
elseif bornday == 2 || bornday == 22
{ "%(bornday)nd" }
elseif bornday == 3 || bornday == 23
{ "%(bornday)rd" }
else
{ "%(bornday)th" }
}
//--OnUserBornDay
//This is much like the above function OnUserBornMonth. It'll take the value the user put in for the day and analyze it. Again, there'll be comments explaining how it works, but all you really need to do is change the dialogue appropriately. I'll point out where you can add new dates to check for.
OnUserBornDay
{
_tempday = reference0 //storing the input in _tempday
_tempday = TOLOWER(_tempday) //changes it to lowercase
_tempday = REPLACE(_tempday,"st","") //if the user types something like 2nd, 3rd, etc, this will make it just the number. It'll just add the suffix back later on the one that actually shows.
_tempday = REPLACE(_tempday,"nd","")
_tempday = REPLACE(_tempday,"rd","")
_tempday = REPLACE(_tempday,"th","")
_tempday = TOINT(_tempday) //Converts it to an integer
if ((bornmonth == 1 || bornmonth == 3 || bornmonth == 5 || bornmonth == 7 || bornmonth == 8 || bornmonth == 10 || bornmonth == 12) && _tempday >= 1 && _tempday <= 31) || (bornmonth == 2 && _tempday >= 1 && _tempday <= 29) || ((bornmonth == 4 || bornmonth == 6 || bornmonth == 9 || bornmonth == 11) && _tempday >= 1 && _tempday <= 30) //This ugly function checks if the day falls into a valid range. If it does, we set some variables and continue down.
{
bornday = _tempday
borndayprint = Printday
userbirthday = "%(bornmonth)month %(bornday)day"
birthdayprint = "%(bornmonthprint) %(borndayprint)"
"%(birthchecked)"
//Mostly defining envelopes and values in here. No need to touch any of this! Eagle-eyed readers will notice the new envelope birthchecked on its own line like a tiny king. We'll get to that momentarily, but pay it no mind for now.
}
else //If the day isn't valid, like the 10046th or something, this will open the input box again and have a \e so the dialogue below doesn't play. You can replace the dialogue in the first line here.
{
"\0\s[0]That's not a valid day. Try again."
--
"\![open,inputbox,OnUserBornDay,-1]\e"
}
}
//--birthchecked
//This is the new envelope you saw me point out above. As you can see here, you can actually call dialogue in a function with an envelope, even when it has if and else statements like here! Which can be pretty handy. Again, more on envelopes in word.dic. Creative ghostmakers can find handy ways to exploit this, I'm sure.
birthchecked
{
if userbirthday == dayslot //if today is the user's birthday
{
"\0\s[0]It's the user's birthday.\w8\1\s[10]Happy birthday, %(username).\e"
//replace this dialogue with whatever you like
}
elseif userbirthday == "12month 25day"
{
"\0\s[0]The user was born on Christmas.\w8\1\s[10]Happy birthday, %(username). \w5\s[15]AND JESUS!\w8\0\s[9]\n\n[half]We're supposed to be a blank template, knock it off before we get in trouble.\e"
//As you can see, you can set up an elseif statement to check if the user's birthday is any day you want! More on elseif statements in bootend.dic. In this case, there's specialized dialogue if the user was born on Christmas. You can replace this with whatever you like, or change the date you're checking as well, like to one of your character's birthdays if you want. You can also delete this elseif if you don't care.
}
else //if the birthday is not listed above.
{
"\0\s[0]Your birthday is %(bornmonthprint) %(borndayprint). We'll remember.\e"
//note the use of envelopes to display the newly set birthday properly. You can replace this dialogue as well, and you can use %(bornmonthprint) and %(borndayprint) to display the month and day in the new dialogue, if you want.
}
}
// ____ _ _ _ _ _____ _
// | __ )(_)_ __| |_| |__ __| | __ _ _ _ | ____|_ __ __| |
// | _ \| | '__| __| '_ \ / _` |/ _` | | | | _____ | _| | '_ \ / _` |
// | |_) | | | | |_| | | | (_| | (_| | |_| | |_____| | |___| | | | (_| |
// |____/|_|_| \__|_| |_|\__,_|\__,_|\__, | |_____|_| |_|\__,_|
// |___/
//--Talk Rate
//This is when the user chooses to adjust the talk rate in the config menu. The talk rate is how often the ghost will read some dialogue from aitalk.dic.
Select.talkinter : all
{
"\0\s[0]\b2How often should we speak?\w8\1\s[10]The interval is currently set to %(talktime)."
//note the new envelope here for %(talktime). You'll see it again in a second. You can replace the dialogue above with whatever you like, just make sure it ends with ./ and not \e.
"\0\n\n[half]"
"\![*]\q[Every 30 seconds,TALKMAX]\n"
"\![*]\q[Every minute,TALKHIGH]\n"
"\![*]\q[Every 3 minutes,TALKNORMAL]\n"
"\![*]\q[Every 5 minutes,TALKPOOR]\n"
"\![*]\q[Don't speak,TALKNONE]\n\n[half]"
"\![*]\q[Don't change,TalksTill]\e"
}
//If the user doesn't want to change the rate. You can change all of the dialogue in any of these options if you want to reflect the choice the user made. You TECHNICALLY could also change the value in talktime to reflect some other way of measuring time but I wouldn't recommend it, it'd just be confusing I'm sure.
Select.TalksTill
{
"\0\s[0]No change to the talk rate.\e"
}
//If the user chooses every 30 seconds.
Select.TALKMAX
{
talktime = "30 seconds" //this sets up the envelope properly
aitalkinterval = 30 //this changes the actual rate
"\0\s[0]We will speak every 30 seconds.\e"
}
//If the user chooses every minute.
Select.TALKHIGH
{
talktime = "minute"
aitalkinterval = 60
"\0\s[0]We will speak every minute.\e"
}
//If the user chooses every three minutes.
Select.TALKNORMAL
{
talktime = "3 minutes"
aitalkinterval = 180
"\0\s[0]We will speak every three minutes.\e"
}
//If the user chooses every five minutes. This is the default rate the ghost will start up in, as seen in bootend.dic.
Select.TALKPOOR
{
talktime = "5 minutes"
aitalkinterval = 300
"\1\s[10]We will speak every five minutes.\e"
}
//If the user chooses to not have them speak. This is one case where you MIGHT want to make talktime equal something else, if you have a snappier way of saying the ghost won't talk. Make sure it flows well in your menus though, since it will be displayed in your config menu.
Select.TALKNONE
{
talktime = "...actually we won't talk at all"
aitalkinterval = 0
"\0\s[0]We will not speak.\e"
}
//This is when the user chooses to change their name. It's linked to the functions outlined in nameteach.dic. Nothing to touch here.
Select.TEACHNAME
{
OnTeachName
}
//If the user selects cancel in a menu. Replace as you like, or just leave them blank.
Select.CANCEL
{
"\0\s[0]This is a cancel message.\e"
"\0\s[0]This is another cancel message.\e"
}
//In the MenuRun function above, if someone selects Functions (linked to dosomething), it will take them here to Select.dosomething.
//If you want to have your ghost pick from multiple intro lines for this menu, you can uncomment FunctionMenuIntros here, and add in dialogue as you like.
// FunctionMenuIntros : nonoverlap
// {
// //I mentioned this above in MenuRun, but you can have a set of multiple different responses that may randomly appear when the menu is opened. Try opening this menu yourself with the template to see how it works. The character will randomly choose one line as the intro.
// //If you don't want to deal with this, just delete the extra lines and leave one. Otherwise, replace the dialogue below as you like, but note that they don't end with \e here.
// "\0\s[0]\b2This is the first function menu intro.\n\n"
// "\0\s[0]\b2This is the second function menu intro.\n\n"
// "\0\s[0]\b2This is the third function menu intro.\n\n"
// }
Select.dosomething : all
{
//FunctionMenuIntros
//this line ^ calls one of the intros above. If you are using the extra intros, you can uncomment this line.
//the -- splits the intros and the menu choices
--
//the actual menu options.
"\![*]\q[Open Calendar,CALENDAR]\n"
"\![*]\q[Check Email,MailCheck]\n"
"\![*]\q[Open SSP Preferences,sspconfig]\n"
//"\![*]\q[Empty Recycle Bin,ChoiceGarbagecan]\n"
//I commented out the Empty Recycle Bin one because that one will need some tweaks to the dialogue to work for every ghost, since it uses Girl and Triangle's names. If you want your ghost to have this feature, uncomment this and fill out the corresponding dialogue below for Select.ChoiceGarbageCan.
"\![*]\q[System Information,ChoiceSystemInformation]\n\n"
"\![*]\q[Back to main menu,BACKTOMENU]\e"
}
//When the user clicks Open Calender. This will open the calender function of SSP, an in-built feature that you don't have to worry about in the least. You don't have to write dialogue here if you don't want to, the template's default dialogue will handle it, but it is an option.
Select.CALENDAR
{
"\0\s[0]Opening the calender.\w8\![open,calendar]\e"
//You can replace the dialogue here up to the \!.
//Advanced users, can you break it down yet? It's basically just using \! to open calender.exe or dll or whatever SSP uses to make it happen.
}
//When the user chooses SSP preferences. This will open the same window that shows up if you right click your ghost and go to Utilities - Preferences. You don't have to write dialogue here if you don't want to, the template's default dialogue will handle it, but it is an option.
Select.sspconfig
{
"\0\s[0]Opening the SSP config menu.\w8\![open,configurationdialog]\e"
//Again, you can replace up to the \! tag.
}
//If the user chooses to empty the recycle bin. Make sure to uncomment the "Empty Recycle Bin" option above in the Select.dosomething menu if you want to include this feature.
Select.ChoiceGarbagecan
{
_gomicheck = FUNCTIONEX("gomi.dll", "-n") //Don't touch this line. for those curious, it's referencing a SAORI, which are optional user-made plug-in dlls you can download to enable different functions on your ghost. gomi.dll is one included with this template. All SAORI are in Japanese (maybe Korean or Chinese as well idk) and many have disappeared by now, so don't concern yourself very much with SAORI. They're for skilled developers, mostly.
if _gomicheck == 0 //If the recycle bin is empty.
{
"\0\s[0]Triangle, go check the recycle bin.\w8\1\s[19]Fine.\w8\w8\s[-1]\w8\w8\w8\w8\w8\1\s[10]\cIt was empty.\e"
//This isn't the usual flat template dialogue, mostly because I wanted to show that this is a good place to use s[-1], which I covered in the walkthrough file. You can have your ghost disappear momentarily like they're going to check your recycle bin, then come back. \c clears the ghost's balloon of text. Replace dialogue as you desire.
}
elseif _gomicheck >= 1 //If the recycle bin is full.
{
"\0\s[0]Emptying the recycle bin.\w8\1\s[19]I'm going.\w8\w8\s[-1]\w8\w8\w8\w8\w8\![raise,OnGarbagecanEmpty]\w9\w9\w9\1\s[10]\cDone.\e"
"\0\s[0]This is the second recycle bin emptying dialogue.\w8\1\s[19]I'm going.\w8\w8\s[-1]\w8\w8\w8\w8\w8\![raise,OnGarbagecanEmpty]\w9\w9\w9\1\s[10]\cDone.\e"
//Somewhat similar to the above, but notice the \![raise],OnGarbagecanEmpty] tag in there. That's what actually empties the recycle bin, so make sure you don't delete that tag. Otherwise, replace the dialogue as you want.
//As you can see, you can have multiple pieces of dialogue in here, just like you can for many other functions scattered through the .dic files. If you only want the one, just delete the others, or if you want to add more, just copy and paste and write new dialogue as it comes to you. This applies to when the recycle bin is empty as well.
}
}
//This is for the SAORI, don't touch it.
OnGarbagecanEmpty
{
_gomi = FUNCTIONEX("gomi.dll", "-f")
}
//This is when the user chooses System Information. Don't touch any of this either. For those curious though, note that this is done using another SAORI, this time saori_cpuid.dll.
Select.ChoiceSystemInformation
{
os_name = FUNCTIONEX("saori_cpuid.dll","os.name")
os_version = FUNCTIONEX("saori_cpuid.dll","os.version")
cpu_name = FUNCTIONEX("saori_cpuid.dll","cpu.name")
cpu_clockex = FUNCTIONEX("saori_cpuid.dll","cpu.clockex")
"/
\0\s[0]\b[2]/
\_q\f[bold,1]OS:\f[bold,0] %(os_name) %(os_version)\n/
\f[bold,1]Memory Load:\f[bold,0] %(memoryload)%\n/
\f[bold,1]Physical Memory:\f[bold,0] %(memoryavailphys) KB\n/
\f[bold,1]CPU:\f[bold,0] %(cpu_name) %(cpu_clockex)MHz\n/
\f[bold,1]Ukagaka:\f[bold,0] %property[baseware.version]/
\e"
}
//This is when the user chooses to check their email. The rest of this function plays out in etc.dic. You can leave this alone.
Select.MailCheck
{
"\![biff]\e"
}
//---- OnChoiceTimeout ---------------------------------------------------------
//If the user is given a menu with choices, but doesn't pick one of the choices, it will eventually time out. At that point, they will say this dialogue. Replace with whatever you like, or leave it blank.
OnChoiceTimeout
{
"\0\s[0]The menu has timed out.\e"
}
//---- Secondary Character Menu ---------------------------------------------------------
//This section has to do with the menu for the second character. If you don't want your second character to have a menu, you can just delete to the end of the file. Advanced users, you can also move the menu options from here to the main character's menu instead and then delete it, if you want to keep these.
KeroMenuIntros : nonoverlap
{
"\1\s[10]\b[2]"
"\1\s[15]\b[2]"
"\1\s[16]\b[2]"
//You've seen so far that you can set up multiple options for menu introductions. You can also set up multiple poses to match up to multiple dialogue. So for example, when you open Triangle's menu, he may randomly do any of these three poses, and randomly choose from any of the four dialogue options below, before continuing with his menu. Make a close note of the -- dashes breaking these up.
//if you aren't interested in such tomfoolery, you can cut them each down to one line.
--
"This is a menu introduction dialogue."
"This is another menu introduction dialogue."
"This is the third menu introduction dialogue."
"This is the fourth menu introduction dialogue."
}
OpenKeroMenu : all
{
//this calls the intros above
KeroMenuIntros
//this splits the intros from the menu options
--
//these are the menu options
"\n\n[half]"
"\![*]\q[Update,keroupdatecheck]\n"
"\![*]\q[Bug report,bugreport]\n\n"
"\![*]\q[Test variable,testvariable]\n\n"
//When you are done with the test variable, aka your ghost is finished or you just don't want it showing up when you publish your ghost beta or whatevs, simply add two // slashes in front of "\![*]\q[Test variable,testvariable]\n\n" to comment the line out. In Notepad++, it will turn green. When you want to use it again, erase the two slashes to turn it back to normal.
"\![*]\q[Nothing,keroCANCEL]\e"
}
//There are no real set things for the second character to do, really. You can mostly add whatever functions you want to them, their menu is totally free reign. In mine for example, Hunter has some games, a pseudo-FAQ for users, a bug report, an update option, and most importantly, a test variable. A lot of that is fairly complicated though, so I won't get into it here. Advanced Users can pick up Hunter and Smoker and study their menu.dic to see how I did it though, and those who read the coding page of the walkthrough and want to make their own functions can feel free to add them here.
//For the purposes of this simple template, I'll include two options that may come in handy - an update option and a bug report option, as well as the test variable.
//If you click cancel. Replace dialogue as you want.
Select.keroCANCEL
{
"\1\s[10]This is menu cancel dialogue.\e"
}
//This is when they select bug report. This is mostly meant to briefly give the user information about you, the creator, and how to report a problem to you. This can be handy if the person forgot where they got their ghost or how to contact you. Add whatever info you like here.
Select.bugreport
{
"\1\s[10]This is the bug report dialogue. \w5Report bugs to youremailaddress@emailprovider.com. \w5We were downloaded from \_a[http://www.whereveryoupostedthem.com/]some place\_a.\e"
}
//When clicked, this will automatically tell the ghost to check for updates. More detail on updates in etc.dic. You can leave this alone.
Select.keroupdatecheck
{
"\1\s[10]\![updatebymyself]\e"
}
//--Test Variable --------------------------------------------------------
//I briefly mentioned the test variable in bootend.dic and possibly in etc.dic as well, I'm not sure. What exactly is the test variable? Basically, it's a place you can plug in anything you want to test out. While you can use Script Input to test most of your ghost's dialogue, there are some lines it just can't do, and it can't help you test choices. But the test variable can!
//You can also use this to test functions as I mentioned above by adding \![raise,function] at the end of it, although you can do this with Script Input as well. Advanced Users, the test variable is also great for testing out any new stuff you may add to your ghost, like mode settings, item values, functions, raising or lowering numbers, what have you, particularly if you have a bunch you want to change all at once.
//It is ALWAYS A GOOD IDEA to test your dialogue! If you won't check it with the test variable, at least test it with Script Input! It'll save you so much trouble!
Select.testvariable
{
"\1\s[10]Testing!\e"
}

183
ghost/master/mouse.dic Normal file
View File

@ -0,0 +1,183 @@
//---------------------------Mouse Functions--------------------------
//As you've probably guessed, this .dic file has to do with mouse functions. This includes the petting feature and what happens when you double click your ghost.
//As a note, this .dic file isn't strictly necessary - I'm pretty sure you can just clear the file and it won't hurt your ghost any, it'll just make it so you can't pet or double click them. And if you're interested in only petting or double clicking one character, all you have to do is delete the chunks of code for the other character you want to be uninvolved. However, I'm assuming most people making ghosts want to make their ghosts pettable and clickable, so this will cover the messages for both.
//Make sure to read the walkthrough page (http://www.ashido.com/ukagaka/walkthrough.html) for more details about how to properly format ghost dialogue!
//I will reiterate that you should be editing these in Notepad++, and in particular, you should set the Language to C (or Java I guess) to properly highlight all the text. It will make things A LOT EASIER for you, trust me! It will also help you keep track of your brackets in case you forget some. If you click on a line with a bracket in Notepad++, it should highlight where the other bracket ends, or turn purple if there's no finishing bracket (which you should definitely fix!)
//It will also highlight my commented lines in green, so you'll know where they are. Any line beginning with // is a commented line that the code will not read. It's just for your reference!
//--OnMouseMove
//This is a bunch of code determining who the mouse is over. Don't touch any of it.
OnMouseMove
{
//---- reference3 determines the character in question
if reference3 == 0 //if the character is 0, aka the main character
{
//---- it will run the mouse functions for that character
MouseMoveSakura
}
else //if the character isn't 0, then it must be the side character.
{
//---- this will run the mouse functions for the side character.
MouseMoveKero
}
}
//*********************Advanced User Info*******************************
//These text boxes are meant for those who have an interest in expanding or using more complicated functions in their ghost. Also for my own reference in the future since I plan on using this template too, haha. If you have no interest in any of this and just want to keep things as simple as possible, feel free to skip these boxes.
//If you want to have more than two characters at any point, like for example how I added Charger with my Hunter/Smoker ghost, and you want to be able to interact with that character like you can with the others, you will have to add in that character to OnMouseMove above. You'll need to know the p[] you've assigned your third character to, which in Charger's case was 3. You can assign your third character any p you want, just be consistent about using the same p[] everytime. I touch on \p a bit more in the walkthrough.
//So anyway, as you can see above, OnMouseMove determines who the user is touching, so you'll just have to add in an elseif checking for reference3 == 3, or reference3 == 4, or whatever p number is you're using. More on elseif in the walkthrough and in bootend.dic. After that, you'll just need to copy and paste the other mouse functions below and change the name as you need (for example, MouseMoveCharger, MouseDoubleClickCharger).
//Note though that the extra character will not be a hard-coded character like 0 and 1! You're basically tricking the program into thinking there's another character, and some functions in things like menu.dic and aitalk.dic won't work quite right if you put in a value other than 0 or 1, and you'll need to be careful about making sure to remove the third character when you're done. But luckily for you, this won't be a problem with any of the mouse functions as far as I'm aware, and you can fill them out for the third character just like you would for the two main ones.
//***********************************************************************
//--MouseMoveSakura
//The petting function for your main character. Remember how it was referred to as sakura in some of the descript.txt and install.txt files?
MouseMoveSakura
{
if reference4 != "" //ignore
{
stroke++ //if you move the mouse over the right areas, the stroke count will go up.
if stroke >= 40 //if the stroke count is above a certain number, the petting dialogue will kick in. You can change this number to make the petting take longer or shorter if you want. FLELEs have it set to 50 for some reason, which makes it take longer than this.
{
stroke = 0 //resetting the stroke count
if reference4 == "Head" //do you remember the names of the areas you set up for your collisions in surfaces.txt? This is where they come into play! This is where you'd put in the name of your collision, such as head, face, horns, tail, ears, whatever. As mentioned in surfaces.txt, you can add as many collisions to a pose as you want, as long as you make sure to add them all in here so they can actually be used.
{
"\0\s[0]This is some petting dialogue.\e"
"\0\s[0]This is some more petting dialogue.\e"
"\0\s[0]This is another bit of petting dialogue.\e"
//Replace these with whatever petting responses you like. You can also add more dialogue here if you want, or cut them down. Though removing them entirely seems a bit counter-intuitive to all that work we've been doing.
}
elseif reference4 == "Face" //Another area set up by the collisions in surfaces.txt. You can expand this list with as many elseifs as you need depending on how many collisions you've set up.
{
"\0\s[0]This is petting dialogue for my face.\e"
"\0\s[0]This is more petting dialogue for my face.\e"
"\0\s[0]This is another bit of petting dialogue for my face. Well, stroking would probably be more accurate.\e"
//Replace with appropriate dialogue as needed.
}
}
}
else
{
// If the mouse isn't over the ghost, it'll zero out the stroke value.
stroke = 0
}
}
//---- MouseMoveKero -----------------------------------------------------------------
//MouseMoveKero is exactly like the above, except set up for your second character.
MouseMoveKero
{
if reference4 != ""
{
stroke++
if stroke >= 40
{
stroke = 0
if reference4 == "Face" //Put in the name of your collision area you set up for your secondary character here.
{
"\1\s[10]This is a face touching dialogue.\e"
"\1\s[10]This is another face touching dialogue.\e"
"\1\s[10]This is yet another face touching dialogue.\e"
//Replace this dialogue with your secondary character's dialogue.
}
elseif reference4 == "Point" //Like above, put in the name of another collision you set up in surfaces.txt for the secondary character. You can keep adding more elseifs like this for any extra collisions you may have set up.
{
"\1\s[10]This is a point touching dialogue since I don't really have a head, being a triangle.\e"
"\1\s[10]This is another point touching dialogue.\e"
"\1\s[10]This is yet another point touching dialogue.\e"
//Replace this dialogue as appropriate.
}
}
}
else
{
// If the mouse isn't over the ghost, it'll zero out the stroke value.
stroke = 0
}
}
//---- OnMouseDoubleClick -------------------------------------------------------
//This is set up much like OnMouseMove above, except this is checking to see if the user is double clicking on the ghost. You also don't need to touch any of this.
//Advanced users adding a third character, the same principles from OnMouseMove apply here as well! Make sure to add an elseif with the right number for your third character.
OnMouseDoubleClick
{
//---- like with the OnMouseMove function above, this determines who the user is clicking on.
if reference5 == 0 //checks which button is being used for the click
{
if reference3 == 0 //if the character is 0, aka your main character
{
MouseDoubleClickSakura
}
else
{
MouseDoubleClickKero
}
}
}
//---- MouseDoubleClickSakura ----------------------------------------------------------
//Like the petting animation above, this is the reactions they have to being double clicked. These also rely on the collisions you set up in surfaces.txt! This set is specifically for the main character, as indicated by the Sakura in the name again.
//*********************Advanced User Info*******************************
//As a note, double clicking on a certain area of your ghost doesn't have to be the user hitting them. You could instead set up a collision for a piece of clothing, and then have the character talk about that bit of clothing when it's double clicked, for example. One of Smoker's double clicks gives her a high-five when she's in a certain pose. Maybe double clicking is patting them, or pointing behind them, or tapping them, or any number of things. You can be creative here with how they respond depending on what areas you've set up as collisions!
//If you don't want your character to be hittable at all, you can just delete everything in MouseDoubleClickSakura except OpenSakuraMenu. So it'd look like
//MouseDoubleClickSakura
//{
//OpenSakuraMenu
//}
//That's all there is to it. This method also applies to the secondary character, Kero, below this set.
//***********************************************************************
MouseDoubleClickSakura
{
if reference4 == "Head" || reference4 == "Face" //here, this is checking to see if the user is double clicking on either the character's head OR their face, which for our purposes means they're hitting the ghost. More about operators at the walkthrough.
{
"\0\s[0]This is the hitting dialogue.\w8\1\s[15]lol\w8\0\s[9]\n\n[half]Shut up.\e"
"\0\s[0]This is another hitting dialogue.\e"
"\0\s[0]This is yet another bit of text for hitting.\e"
"\0\s[0]This is the fourth hitting dialogue.\e"
//Replace this dialogue with appropriate dialogue as you need. You can add more or cut it down if you want, even down to nothing if you want no response from your ghost at all when those areas are double clicked.
}
else
{
//Otherwise, if the user doubleclicks somewhere else on the character, they will open their menu as detailed in menu.dic.
OpenSakuraMenu
}
}
//---- MouseDoubleClickKero -----------------------------------------------------------
//This is just the same as MouseDoubleClickSakura above, except for your secondary character. The same principles apply, including how to make your character unhittable.
MouseDoubleClickKero
{
if reference4 == "Face" //Triangle doesn't have a separate head really, being a triangle, so this only happens if you doubleclick his face.
{
"\1\s[10]This is hitting dialogue.\w8\0\s[5]ha ha\w8\1\s[19]\n\n[half]Quiet.\e"
"\1\s[10]This is another hit dialogue.\e"
"\1\s[10]This is yet another hit dialogue.\e"
"\1\s[10]This is the fourth hitting dialogue.\e"
//Replace the dialogue here for the second character with whatever you want. What I said above about adding or trimming still holds here.
}
else //Otherwise if you click anywhere else on Triangle's body
{
OpenKeroMenu //This will open his menu set up in menu.dic.
}
}
//*********************Advanced User Info*******************************
//There are other mouse related functions you could set up much like the above, such as OnMouseDragStart, OnMouseDragEnd, OnMouseWheel, and others which correspond to various things you can do with your mouse. You can probably guess what those functions do just by their names - OnMouseWheel would be if someone spun their mouse wheel over a certain area, for example. If you're interested in these, I'd recommend doing some reading at the CROW-SSP Encyclopedia to get a better idea of them and settle down for some trial and error learning as you try to put them in.
//***********************************************************************

168
ghost/master/nameteach.dic Normal file
View File

@ -0,0 +1,168 @@
//---------------------------The User's Name--------------------------
//This .dic file has to do with setting the user's name and suffix/prefix (optional). You may recall some of the functions mentioned here from bootend.dic. As you can see, you can spread functions across multiple .dic files if you like! Just remember my note in bootend.dic about the different between OnFunction and Function.
//This file is fairly short, so don't worry! It shouldn't take you too long to finish.
//Make sure to read the walkthrough (http://www.ashido.com/ukagaka/walkthrough.html) for more details about how to properly format ghost dialogue!
//I will reiterate that you should be editing these in Notepad++, and in particular, you should set the Language to C (or Java I guess) to properly highlight all the text. It will make things A LOT EASIER for you, trust me! It will also help you keep track of your brackets in case you forget some. If you click on a line with a bracket in Notepad++, it should highlight where the other bracket ends, or turn purple if there's no finishing bracket (which you should definitely fix!)
//It will also highlight my commented lines in green, so you'll know where they are. Any line beginning with // is a commented line that the code will not read. It's just for your reference!
//If you see a big block of commented text you want to uncomment, highlight the text and then hit ctrl-shift-k in Notepad++ and that should uncomment it. Mostly this is intended for advanced users.
//--OnTeachName
//This is called from the config menu in the main character's double click menu when the user says they want to change their name. If you look in menu.dic you'll see the code leading to here.
OnTeachName
{
if reference0 == "TEACHNAME" //ignore this
{
"\0\s[0]The user wants to change their name. What do you want it to be?\![open,inputbox,OnNameTeach,-1]\e"
//This is the bit of dialogue you can rewrite if you want. Note that this line ends with \![open,inputbox,OnNameTeach,-1]. You may recognize this from bootend.dic. Essentially, this will lead to the next function. Make sure you don't delete that tag! The rest you can do whatever with though.
}
else
{
//This else statement is empty, and I'm mostly pointing this out to mention that you can do this too with your if/elses if you want! An empty else will simply cause your ghost not to do anything. I wouldn't get too crazy with this though.
}
}
//--OnNameTeach
//This is where the user inputs their name and the ghost analyzes it. If you want your ghost to have specific responses to certain names, this is where you would add them. If not, you can blank OnNameTeach and just leave these three lines in there.
//OnNameTeach
// {
//tempname = reference0
//username = tempname
//"\0\s[0]The user is now called %(username).\e"
// }
//For this template, we're going to check at least for the user having the same name as Girl or Triangle and if the user puts in a valid name.
OnNameTeach
{
tempname = reference0 //this stores the name value from reference0 in tempname
reference0 = TOLOWER(reference0) //changes it to lowercase
reference0 = REPLACE(reference0," ","") //removes spaces
reference0 = REPLACE(reference0,".","") //removes periods
reference0 = REPLACE(reference0,"-","") //removes dashes
//Those extra TOLOWER/REPLACE things up there basically clean up the user's input so you don't have to check for Girl, GIRL, girl, GiRl, etc. It'll make it much easier to check for any specific name, since you won't have to account for any edge cases. Note that the names you will be checking for should be in all lowercase, however.
if reference0 == "girl" //this checks to see if the user input any variation of the name "Girl". You may want to put in a check here if the user tries to name themselves the same name as your characters, since that could be confusing in dialogue. Or just a response to any kind of strange name, like Barack Obama or Cindy Crawford or Mike Nelson or Random Hajile. Or you can prevent certain offensive names if you don't want users using them. Really the power is yours here.
{
"\0\s[0]That's my name.\w8\1\s[10]That might be confusing. You should try again.\![open,inputbox,OnNameTeach,-1]"
//Note here that it's using the same tag as above to reopen the text box to let the user put in another name. You can replace the dialogue with whatever as long as you keep the \![open,inputbox,OnNameTeach,-1] tag.
}
elseif reference0 == "triangle" //like the above, this checks to see if the user put in Triangle. Again, this is mostly to avoid confusion in dialogue between the user and the characters.
{
"\1\s[10]That's my name. Try putting in another one.\![open,inputbox,OnNameTeach,-1]"
//See again that this ends with the same tag to reopen the input box. Again, replace but keep the \![open,inputbox,OnNameTeach,-1] tag at the end.
}
elseif reference0 == "" //This is if the user doesn't put in a name at all, since that'd also get awkward in dialogue.
{
username = "USER" //this sets the user's name to USER.
"\1\s[10]You didn't put in anything.\w8\0\s[0]We will call you USER.\e"
//You can change this snip to whatever.
}
else //if the user put in something not specified above, ie a proper name the ghost can use.
{
username = tempname
"\0\s[0]The user is now called %(username).\e"
//change this dialogue to whatever you like.
}
}
//The rest of this is for advanced users who want to add titles to their user's names. If you're not interested, you can ignore this and move on to another file.
//*********************Advanced User Info*******************************
//If you want to let your user add a title to their name, like Lady or Master, then you'll want to expand this section a little. This check would go AFTER the check above for a valid name, leading to further choices instead of setting the name. So you'd want to uncomment and put in the else above...
// {
// "\0\s[0]Do you want a title?\w4\n\n[half]\![*]\q[Nope,titlenone]\n"
// //You can replace "\0\s[0]Do you want a title?", but don't touch the rest of it.
// --
// if presuffix == "masculine" //this value was defined in bootend.dic and menu.dic when the user chose their pronouns. Thus, if someone chose he/him pronouns, they would be able to choose Mr. or Master. If the user hasn't set their pronouns, or that's not a feature of your ghost, you can just put all the choices together without these presuffix checks and let the user decide from all.
// {
// "\![*]\q[Mr.,titlemr]\n/
// \![*]\q[Master,titlemaster]\n"
// }
// elseif presuffix == "feminine" //Likewise, if someone chose she/her pronouns, they could choose Ms. or Lady.
// {
// "\![*]\q[Ms.,titlems]\n/
// \![*]\q[Lady,titlelady]\n"
// }
// -- //the titles after this are gender neutral and will appear for all users. If you want to remove the masculine and feminine titles entirely, just delete from the curly bracket one line up to the double dashes above "if presuffix == "masculine". That should leave only the neutral titles. Make sure to leave a set of double dashes above the neutral titles though. You can also just put the feminine and masculine titles in here too if you want all titles to be available to all users at all times.
// "\![*]\q[-ssi,titlessi]\n/
// \![*]\q[-san,titlesan]\e"
// //Note that the final line here ends with \e instead of \n/, since it is the final option. Make sure your final option (and ONLY your final option) always ends with \e. More on that in the box below.
// }
//Adding new titles for your users to use is simply a matter of copy and pasting creatively. You can see how the ghost puts together the title and your name in the Select. sections below. Above, you simply need to add a new option and link it to a new Select. For example, you could add "\![*]\q[Mistress,titlemistress]\n/" between Ms. and Lady up there, then write up a Select.titlemistress below that fits the pattern of the others.
//***********************************************************************
//The following Select.title[word] functions add the title to the user's name, then go to the final step, NameDone. You don't have to touch any of these. Advanced users, notice how these match the linked functions in the choices above.
Select.titlenone
{
username = tempname
NameDone
}
Select.titlemr
{
username = "Mr. " + tempname
NameDone
}
Select.titlemaster
{
username = "Master " + tempname
NameDone
}
Select.titlems
{
username = "Ms. " + tempname
NameDone
}
Select.titlelady
{
username = "Lady " + tempname
NameDone
}
Select.titlessi
{
username = tempname + "-ssi"
NameDone
}
Select.titlesan
{
username = tempname + "-san"
NameDone
}
//--NameDone
//This is the final bit of dialogue your ghosts will have when the user changes their name and adds a title above. There is a special section here for when the user first boots the ghost, if you uncommented that in bootend.dic. If you aren't doing either of those things, then you can ignore this.
NameDone
{
if firstboot == 1 //this checks for the flag that was set during the firstboot sequence
{
firstboot = 0 //this turns the flag off
//This dialogue will display the first time the user puts in their name. You might want to add some closing thoughts to the introduction your ghost had in OnFirstBoot, or directions about how to use the ghost, or something like that. It's up to you!
"\0\s[0]Thank you for inputting your name for the first time, %(username).\w8\1\s[10]Good luck on finishing your ghost!\e"
}
else
{
"\0\s[0]The user is now called %(username).\e"
//Rewrite this as you like. Note the %(username) tag here, as you should be well familiar with by now from the walkthrough and the other .dic files. That will display the name the user just created.
}
}

View File

@ -0,0 +1,18 @@
Charset,UTF-8
__system_settings_version__,2
balloon,C:\Users\Denis-PC\Downloads\SSP\balloon\plasmatablet\
scriptbox.left,960
shiori.debugnotify,0
Char0.ratio.x,0,959375000
Char0.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
Char0.ratio.y,1,004629630
Char.VirtualDesktop,5d1be626-0563-4e74-b79d-89ffdb19ff93
Char1.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
scriptbox.top,510
shell,shell\master\
FirstBoot,booted
Char1.ratio.x,0,867187500
Char1.ratio.y,0,960185185
shell.ischanged.2,1
update.lastexec,811780090
__system_written_flag_do_not_remove__,written

View File

@ -0,0 +1,18 @@
Charset,UTF-8
__system_settings_version__,2
balloon,C:\Users\Denis-PC\Downloads\SSP\balloon\plasmatablet\
scriptbox.left,960
shiori.debugnotify,0
Char0.ratio.x,0,959375000
Char0.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
Char0.ratio.y,1,004629630
Char.VirtualDesktop,5d1be626-0563-4e74-b79d-89ffdb19ff93
Char1.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
scriptbox.top,510
shell,shell\master\
FirstBoot,booted
Char1.ratio.x,0,867187500
Char1.ratio.y,0,960185185
shell.ischanged.2,1
update.lastexec,811780090
__system_written_flag_do_not_remove__,written

View File

@ -0,0 +1 @@
PgdjdxuqTmihtl0OrnYMjg==

View File

@ -0,0 +1,7 @@
Charset,UTF-8
install,811779446
surfacecount,25
update_result,NG(timeout)
firstboot,811779990
commitmemorysize,582444
lastboot,821450117

Binary file not shown.

308
ghost/master/string.dic Normal file
View File

@ -0,0 +1,308 @@
///////// 빒?긕?긚긣긡깛긵깒?긣
///////// 빒럻쀱깏??긚렖룕
///////// written by umeici.
//---------------------------Strings--------------------------
//As you can see above, this file was written by umeici, but unfortunately the rest of the text up there got a bit garbled at some point. I'll leave it though.
//Anyway, string.dic has to do with the right-click SSP menu, specifically the captions for the menu options. This is VERY IMPORTANT if you're going to set up the Network Update for your ghost! Otherwise this is just an easy place to customize your ghost's menu to your tastes. You don't HAVE to if you don't want to. The only thing in here you really need to change is the network update information, if you're using it.
//If you're going to set up Network Update, make sure to read the walkthrough (http://www.ashido.com/ukagaka/) for more details! I won't get into the whole thing here, but this page has a very important value you will need to change for Network Update to work!
//Note also here that lines do not end with \e here. This is because the ghost isn't speaking these lines, they're just being used in the right-click menu.
//---- Username -----------------------------------------------------------------------
//Don't touch this.
On_username
{
username
}
//---- Network Update URL ----------------------------------------------
//This is the URL where your ghost will look for updates. If you're setting up Network Updates YOU MUST change this to point at the right directory! Otherwise your ghost will not update properly! If you're not going to use the Network Update feature, just leave this section as it is or delete it, it should be fine.
On_homeurl
{
"http://www.somekindofwebhost.com/yourghostsdirectory/"
}
//---- Top Menu Option Caption -----------------------------------------
//You may have noticed that there are two collapsed links at the top of the SSP right click menu that lead you to another assortment of links. This is the caption for the top option of the menu.
On_recommendrootbutton.caption
{
"Reference Sites"
}
//---- Top Menu Option Websites -----------------------------------------------------
//These are the websites listed under that button we just named up there. You can put whatever sites you want in here. I'll actually link to some real sites here to be helpful. Feel free to replace these with the sites you like instead. Pay close attention to the formatting that follows!
On_sakura.recommendsites
{
"Ghost Template Walkthrough"
--
//This first line is the name that will display in the menu for your site. In this case, it would display "Ghost Template Walkthrough".
"%ASC(1)http://www.ashido.com/ukagaka/%ASC(2)"
--
//And this is the site that it would link to. Note that a website address begins with %ASC(1) and ends with %ASC(2). Don't forget these!
"Zarla's Twitter"
--
"%ASC(1)https://twitter.com/Zarla_S/%ASC(2)"
--
"Zarla's Tumblr"
--
"%ASC(1)http://zarla-s.tumblr.com/%ASC(2)"
--
"Zarla's Dreamwidth"
--
"%ASC(1)http://zarla.dreamwidth.org/%ASC(2)"
--
"SSP"
--
"%ASC(1)http://ssp.shillest.net/%ASC(2)"
--
"Crow + SSP Reference (J)"
--
"%ASC(1)http://crow.aqrs.jp/reference/all/index.html%ASC(2)"
--
"Ghost Documentation (J)"
--
"%ASC(1)http://usada.sakura.vg/contents/specification.html%ASC(2)"
--
"Disc-2 (J)"
--
"%ASC(1)http://disc2.s56.xrea.com/%ASC(2)"
"UKADOC Project Wiki (J)"
--
"%ASC(1)http://ssp.shillest.net/ukadoc/manual/index.html/%ASC(2)"
//You don't have to space these out like this between sites, but I thought it'd make it a bit easier to read.
}
//---- The second option from the top's caption -----------------------------------------
//This is the name of the second option in that list. You can change this to whatever you want, or even put in multiple names. If you do more than one, the names will switch randomly.
On_portalrootbutton.caption
{
"Second Website Caption"
"Another Second Website Caption"
}
//---- Websites in the Second Option --------------------------------------------------
//These are the websites listed under that second button we just named up there. Like with the other option, these are the websites you want to link to. You can put whatever sites you want in here. Pay close attention to the formatting that follows!
On_sakura.portalsites
{
"Site Name 1"
"Site Name 1 Alternate"
--
"%ASC(1)http://somesite.com/%ASC(2)"
--
//Here, you'll notice that there are two names, a --, then a website bracketed by %ASC(1) and %ASC(2). What this will do is randomly chose between those two site names for the link. So if you open the menu, maybe it will say Site Name 1, or maybe it will say Site Name 1 Alternate. Honestly I find links changing names without warning kind of confusing, but maybe some find it amusing, idk. Put the address of the site you want to link to between the two ASC tags.
"Site Name 2"
--
"%ASC(1)http://www.anothersite.org/%ASC(2)"
--
//If you want to keep things simple, you can just give each website one name like so.
"Site Name 3"
--
"%ASC(1)http://www.thirdsite.com/%ASC(2)"
--
"Site Name 4"
--
"%ASC(1)http://www.fourthsite.com/%ASC(2)"
--
"Site Name 5"
--
"%ASC(1)http://www.fifthsite.com/%ASC(2)"
//You get the idea. You can add more links or take them away as you like following this basic formula.
}
//---- Top Menu Option in the Second Character -----------------------------------------
//If you right-click the secondary character, a tiny menu will pop up. This is the caption for the top option.
On_kero.recommendbuttoncaption
{
"Top Menu Option Caption"
}
//---- Top Menu Websites for the Second Character --------------------------------------
//As with the above, this is another chance for you to add some links to some websites you like.
On_kero.recommendsites
{
"A Site"
--
"%ASC(1)http://www.asite.com/%ASC(2)"
--
"Another Site"
--
"%ASC(1)http://anothersite.org/%ASC(2)"
}
//---- Update Menu Caption ------------------------------------------------------------
//What it will say on the menu for the option to Update.
On_updatebutton.caption
{
"Update Menu Caption"
}
//---- Dress-up Menu Caption ----------------------------------------------------------
//What it will say on the menu for Dress-Up.
On_dressuprootbutton.caption
{
"Dress-Up Caption"
}
//---- Headlines and RSS Feeds ---------------------------------------------------------
//You'll see this below uninstall. This is where all the headlines/RSS feeds the user may have subscribed to will be listed, and this is the caption it'll have on the menu.
On_headlinesenserootbutton.caption
{
"Headlines + RSS Feeds"
}
//---- Readme Caption -------------------------------------------------------
//What the menu displays for the readme file link under Information.
On_readmebutton.caption
{
"READ ME"
"readme.txt"
"Manual"
}
//---- Uninstall Caption -----------------------------------------------------
//This is the caption for the option to uninstall them.
On_vanishbutton.caption
{
"Uninstall"
}
//---- Shell Caption -----------------------------------------------------
//This is the caption for the option to change shells.
On_shellrootbutton.caption
{
"Change Shell"
}
//---- Change Ghost Caption -----------------------------------------------------
//This is the caption for the option to change ghosts.
On_ghostrootbutton.caption
{
"Change Ghost"
}
//---- Call Ghosts Caption -----------------------------------------------------
//This is the caption for the option to call another ghost. What this does essentially is load up another ghost on your desktop. For example, you could run your ghost, then call FLELE, and have them both running at the same time.
On_callghostrootbutton.caption
{
"Call Ghost"
}
//---- Quit Caption -----------------------------------------------------
//This is the caption for the option to quit.
On_quitbutton.caption
{
"Quit"
}
//----------------------------------Stop!------------------------------------
//Don't mess with anything after this point! It's all stuff you don't need to worry about. Just save and move on to the next .dic file.
//---- 소멸 지시 버튼 표시 교체 -------------------------------------------------------
On_vanishbutton.visible
{
if deleteshitai == "ON"
{
"1"
}
else
{
"0"
}
}
//---- 딳벍뭷궻뫜궻긕?긚긣뼹롦벦 -------------------------------------------------------
On_otherghostname
{
ghostexlist = ""
_i = 0
while _i >= 0 {
_ghostname = NAMETOVALUE("reference%_i")
if _ghostname != "" {
if _i > 0; ghostexlist += ","
ghostexlist += _ghostname[0]
_i++
}
else; _i = -1
}
ghostexcount = ARRAYSIZE(ghostexlist)
}
//---- SHIORI 듫쁀륃뺪 ------------------------------------------------------------------
On_version
{
GETSETTING(AYAINFO_VERSION)
}
On_craftman
{
"umeici"
}
On_craftmanw
{
"?럖"
}
On_name
{
"AYA"
}
//---- Owned SSTP 뾭 uniqueid 롦벦 ------------------------------------------------------
On_uniqueid
{
uniqueid = reference0
}
//---- hwnd 롦벦 ------------------------------------------------------------------------
On_hwnd
{
sakurahwnd = reference0[0]
kerohwnd = reference0[1]
sakurablnhwnd = reference1[0]
keroblnhwnd = reference1[1]
}

81
ghost/master/updates.txt Normal file
View File

@ -0,0 +1,81 @@
file,ghost/master/aitalk.dic3abec1e404417fd317ceb73acf33ffe0size=38522
file,ghost/master/anchor.dic56bbd05dec8002e08c50f9074deda54asize=4922
file,ghost/master/aya5.dll7737614f08f642a0261a4f81917ed77asize=198144
file,ghost/master/aya5.txt2ed462a7033d35c6d9397dd1803eaa28size=1267
file,ghost/master/bootend.dic509254cbce358ad53d2d34e7cd0d961bsize=38990
file,ghost/master/commu.dice8aecf682cfdeb1065aadc102eb669ebsize=1545
file,ghost/master/descript.txt03b165949bdd3133350f403207749f33size=2451
file,ghost/master/etc.dic5480ebfe4f9c6da4575c1ea0c4646c9asize=34388
file,ghost/master/gomi.dll51fe9597398db01e684a0f9d52c63242size=13312
file,ghost/master/gt_template.ico9b275939dbf11bd2ec5f4ef3e00fa06asize=1148
file,ghost/master/mciaudior.dllb1082bccd2aac2017f7936baf2d967b3size=29696
file,ghost/master/menu.dic8eff4ef2f64423ffcb2a4113acf532desize=32752
file,ghost/master/mouse.dica5ed9de92b59846712781ea54fb1ee45size=12195
file,ghost/master/nameteach.dica144a305b1f3c6a9208e18d7e1dcc21csize=8619
file,ghost/master/saori_cpuid.dlld13370aee8e579fe2517d789dba7c45esize=225280
file,ghost/master/shiori3.dic58b4b947e0aa6741018aa8861f862ebfsize=34827
file,ghost/master/string.dic4426fac5717e78dd605ba40f69d5f84dsize=9436
file,ghost/master/word.dic1921585b5cfcf3279184b544c4164a37size=6063
file,install.txt8a3f799789ce72a9684605ffd5cc11a4size=680
file,readme.txtcb336bd90cc70f2f21a1b257218b0cc6size=395
file,shell/default_shell/descript.txt99c56195a55846037db35aa6c89fd895size=5286
file,shell/default_shell/menu_background.pngee82ad72761d4837c3334f61ade1fbc5size=2775
file,shell/default_shell/menu_foreground.pnge0d10ee3534c5391c8e97a0897dc77a9size=2775
file,shell/default_shell/menu_sidebar.png7c405dcca0c16de439fcf21b4efecbb7size=7225
file,shell/default_shell/read me.txt855c908f8863b8a773dbb37ea1cf451asize=1838
file,shell/default_shell/surface0.pna8db2e7cd6580c90459c3a5d215b15d04size=7202
file,shell/default_shell/surface0.png18d3dc83a1ee78c27ab4095e63cf362dsize=17629
file,shell/default_shell/surface10.pnacae60b6a3665fc040f41aa0112b03891size=3537
file,shell/default_shell/surface10.pngf1347c38e4e02e5fa2ab0bc1d325a7c2size=4187
file,shell/default_shell/surface1000.png43fcc1badac8488c409587e3c6c7ce18size=4130
file,shell/default_shell/surface1001.png4537e386ca077ae4afb238ce2e501c42size=4106
file,shell/default_shell/surface1002.png51cf9c6937efc7b331b554984ef1e841size=3956
file,shell/default_shell/surface1100.png293959a52fd2c725c4d51b5d611d6e2csize=2575
file,shell/default_shell/surface1101.png024329002f6cb026d1cffa9dabdf2ec6size=2677
file,shell/default_shell/surface1102.png19f8aee616bae415fa8527953d1aeb77size=2733
file,shell/default_shell/surface1501.pna465f5936870d1b1fb53b9179a95e99a6size=6891
file,shell/default_shell/surface1501.pnge07d88f63fdbb5ca6579a852ff982d75size=16730
file,shell/default_shell/surface1502.pnab57df3575edfb8bbfcf8aab0d76fb8f4size=8647
file,shell/default_shell/surface1502.png63390a888531184ed6ec4d743b8e79acsize=21790
file,shell/default_shell/surface1503.pnaf7665607c0c65b1536d697dd1e1e4e32size=7496
file,shell/default_shell/surface1503.pngd800add782f77fdd6cfc4cbc11b1113asize=18466
file,shell/default_shell/surface1504.pna81aefe387a4269a89aefdb707a8f9091size=6044
file,shell/default_shell/surface1504.png9928fe1e9bc8dfb13cbb7fbba59bbde0size=15691
file,shell/default_shell/surface1505.pna9bd798e7811d28eeaeb685bedea7df04size=7096
file,shell/default_shell/surface1505.png586e2f1f55823c5692bfdae10d47c348size=17345
file,shell/default_shell/surface1506.pnadf0d82506894b675fe3e673f906a609bsize=7295
file,shell/default_shell/surface1506.png490a29b13be538e711f5a242e414f8fdsize=16935
file,shell/default_shell/surface1507.pnaa6c7828f11677a27010614bf8ed56b09size=7845
file,shell/default_shell/surface1507.pngdd0e79c5f854dd8513a2c24904c7ac7dsize=19573
file,shell/default_shell/surface1508.pna1b854563a7cfee7feac56410e288c923size=6829
file,shell/default_shell/surface1508.png68e1f524eae0bb8bb72b6b094fb8602esize=16708
file,shell/default_shell/surface1509.pnaf7d0b3e22d36a112e347b1111fb4e1d4size=6804
file,shell/default_shell/surface1509.pngbabc5ad41e504c0f308ba7957637b3cbsize=17108
file,shell/default_shell/surface2000.pna33345d7c3ba8b23323cda5bb9aa61f94size=2893
file,shell/default_shell/surface2000.pnge09f8d0641d29b5c469158b1e27b9d60size=3175
file,shell/default_shell/surface2001.pna33345d7c3ba8b23323cda5bb9aa61f94size=2893
file,shell/default_shell/surface2001.pngdcda5475d214354c66d6bedef6f03148size=3192
file,shell/default_shell/surface2002.pna33345d7c3ba8b23323cda5bb9aa61f94size=2893
file,shell/default_shell/surface2002.png7b513b7089b727827c4f223f5de1032csize=3179
file,shell/default_shell/surface2501.pna3e4f1a343d5d63777c3577e3ff69ac30size=3518
file,shell/default_shell/surface2501.pngffc302dac41904efb061edfc7a2bad0esize=4731
file,shell/default_shell/surface2502.pna728dc3f0c5c142f0a082c82ca5031380size=3835
file,shell/default_shell/surface2502.pnge328b8e90c7995383b08fe943092e1b8size=5085
file,shell/default_shell/surface2503.pna134e56b7e7696258163368dee84bd77dsize=3628
file,shell/default_shell/surface2503.png6b4daf0ba84052c4966ff9ec0ddac30csize=4710
file,shell/default_shell/surface2504.pnafd64691eabd34532e617e4bfd21aab37size=3579
file,shell/default_shell/surface2504.png38d15a5612a60bcd92b373e585bd7ed6size=4381
file,shell/default_shell/surface2505.pnad5ff2272170107c66fddae559604601fsize=3929
file,shell/default_shell/surface2505.png2b197381b9e38fba86554bd498df3580size=4782
file,shell/default_shell/surface2506.pna04096f0e9d47a65c471104ba0c37b8e7size=3612
file,shell/default_shell/surface2506.png562b0262cb9620e47bda23f84bd798b4size=4252
file,shell/default_shell/surface2507.pna3d6cc833dcd91f6f2c1602f2105b158asize=3707
file,shell/default_shell/surface2507.pngd95a99c2f4f4d1b6af442aa809ded3bfsize=4527
file,shell/default_shell/surface2508.pna84c1cf5bd2df84242c51b0f96afc0201size=3458
file,shell/default_shell/surface2508.png6e94830f867e783f4e26bba4bff9145bsize=4324
file,shell/default_shell/surface2509.pna04096f0e9d47a65c471104ba0c37b8e7size=3612
file,shell/default_shell/surface2509.pnge6e43f21dafd057ab890c67e1346df80size=4262
file,shell/default_shell/surfaces.txtf9a43fae269c315270cefe08da7a4005size=42945
file,shell/default_shell/thumbnail.png9993d1bdfb6f26b9886d13f69d0a22b8size=24167
file,Template Readme - READ ME FIRST!.txtb7af188866ba330858f3a6bdf8b56edbsize=2921
file,thumbnail.pngaaac9f3a86600c8e3f01dfb3e3986aa2size=24459

146
ghost/master/word.dic Normal file
View File

@ -0,0 +1,146 @@
//---------------------------Envelopes--------------------------
//This .dic file is probably one of the simplest you will have to edit, and in fact, if the way it works doesn't appeal to you, you can completely ignore it if you like!
//Basically, what this file does is set up some things that, for the purposes of this file, I'll call envelopes (this is what they're referred to as on the CROW-SSP Dictionary site... at least, that's what I remember, it's been a while since I've checked it). They are technically functions and can do many things, but this file is mostly an organizational tool for storing lists you may use.
//For the purposes of this file, an envelope is a list that you can populate with items, and this list can be called later during dialogue with the %(name) format. If you've read the walkthrough or gone through any of the other .dic files, you've probably seen these before. %(username) is one, which displays the user's name, and %(heshe) is another, which displays the right pronoun depending on what the user selected in bootend.dic or menu.dic. Other ones include %(passmin), which shows how many minutes have passed since the ghost was started, %(screenheight) which shows the height of the display they're currently on, and %(keroname) for the name of the second character, among many, many others. Many of these are predefined by the AYA scripting and will be listed on the CROW-SSP site mentioned above, and many of them you will never have to use.
//So where does this file come in? Well, you can define your own envelopes/variables if you want! Here's an example.
exampleenvelope
{
"Example Envelope Dialogue 1"
"Example Envelope Dialogue 2"
"Example Envelope Dialogue 3"
}
//As you can see, we stated a word, opened some brackets, wrote some text, and closed the brackets. Now when you write ghost dialogue, you can write %(exampleenvelope) and your ghost will randomly display any of the three bits of text within the brackets! You can go ahead and test this yourself to see how it works, and I'll include some sample dialogue with this in aitalk.dic.
//What can you use this kind of envelope for? You can store tons of random information to keep your ghost's dialogue varied! You can store various cities you like in %(city), musicians you like in %(musicians), places your ghost has been in %(places), food you like in %(food), movies you like in %(movie), fandoms you like in %(fandom), characters you like in %(fandomcharacter), celebrities you like under %(celebrity) or friends of yours in %(friends) or bnfs in %(bnfs), folders on your computer under %(folders), Pokemon you like under %(pokemon), insults under %(insult), swear words under %(swearword) which could potentially be hilarious, just about anything! You can make lists of absolutely anything to use with dialogue for your ghost! This .dic file is only limited by your imagination!
//Not only that, but you can put an envelope IN an envelope. Here's another example.
internalenvelope
{
"Internal Envelope Dialogue 1 - %(exampleenvelope)"
"%(username)'s computer"
"Here is a blanklist object - %(blanklist)."
}
//You can nest envelopes all day long, although it might get kind of convoluted if you don't keep track. This is particularly handy with %(username), so your ghost can be specific if they're talking about something of the user's, like their files or folders for example. I'll leave a few lists in here you can fill out as you like. And if this doesn't give you ideas, you can ignore this file, since nothing in it will show up unless you write it into the dialogue. You can add or take away as many items as you want from each list.
//*********************Advanced User Info*******************************
//These text boxes are meant for those who have an interest in expanding or using more complicated functions in their ghost. Also for my own reference in the future since I plan on using this template too, haha. If you have no interest in any of this and just want to keep things as simple as possible, feel free to skip these boxes.
//Because these are basically their own functions, you can do other things with them as well as display dialogue. You can add if/else checks, run other functions, have pools of alternate dialogue... the possibilities are really endless.
//One particularly useful thing you can do is add value changes to an envelope, if your dialogue is in a place where it's not easy to add the change directly. For example...
//FeelingsGoUp
//{
//Feelings += 1
//"Thank you, %(username), that was really nice of you.\e"
//}
//So this would display the dialogue as well as change the value. Then you can call this in dialogue if you need to to change the value without having to do a bunch of fiddly business. Specifically I'm thinking about things like RandomTalk, where it can be finicky to have dialogue that also changes a value like this. Like "Oh... wow... %(FeelingsGoUp\e" could go into RandomTalk and still change the value effectively without breaking anything. You can of course also change multiple values at once, and if you don't put dialogue in there, it will change the value invisibly.
//Another use for these envelopes is to shortcut certain long lines of SakuraScript you don't want to have to keep typing. A good example is if you want to change the font for a character. Take Papyrus from my Gaster ghost, he talks in the font Papyrus. But I don't want to have to type the tag for it for every line of dialogue he does. So instead I can put it in an envelope.
//p
// {
// "\f[name,Papyrus UT]\f[height,16]"
// }
//And then I can make one that'll change the font back to normal.
// d
//{
//"\f[name,default]\f[height,default]"
//}
//So in dialogue, to change fonts I'd just have to go "%(p)HEY THERE!%(d)" to change fonts back and forth quickly. These kind of shortcuts can be very useful.
//Another way to use envelopes is to store multiple poses for SurfaceRestore in aitalk.dic. Gaster for example has several neutral idle poses, but also several poses for when he's scared. So I can make an envelope like
//scared
//{
//"\0\s[9]\i[3]\i[104]\i[39]"
//"\0\s[100]\i[2]\i[40]\i[104]"
//"\0\s[100]\i[2]\i[40]\i[106]"
//}
//And have him randomly pick one whenever I use %(scared) in dialogue. This can be an easy way to vary certain poses without having to manually put them in one at a time, and have some variety when your ghost goes back to its neutral pose in SurfaceRestore.
//***********************************************************************
blanklist
{
"List object 1"
"List object 2"
"List object 3"
"List object 4"
"List object 5"
}
blanklist2
{
"List object 1"
"List object 2"
"List object 3"
"List object 4"
"List object 5"
"List object 6"
"List object 7"
"List object 8"
}
blanklist3
{
"List object 1"
"List object 2"
"List object 3"
"List object 4"
}
blanklist4
{
"List object 1"
"List object 2"
}
//This envelope in particular I think is fun. You can use this in dialogue to pretend like your ghost is looking through your user's files!
usersfolder
{
"%(username)'s Recycle Bin"
"%(username)'s Document folder"
"%(username)'s secret folder"
}
//Now, this next envelope is unique. I've called it a double envelope at times, but this is actually technically an array. Note that it has a word, a comma, then another word. This is essentially a list being stored in this envelope. You can call one of the values by using brackets around the number of the list entry. So, the first value (the Korean word) would be %(lessonkor[0]) since all arrays start at 0. The second value (the definition) would be %(lessonkor[1]). If you have a longer array, like "word,word,word,word,word", you can keep calling values by changing the numbers, like %(lessonkor[5]) or %(lessonkor[10]). Arrays can be very powerful and useful for storing a lot of information in a condensed space, but I must level with you, I'm not very good at arrays or figuring out how to use them. :B They can be VERY useful though, if you can wrap your head around how they work. An example of pulling information from this array can be seen in aitalk.dic.
lessonkor
{
"사과(sa-gua),apple"
"노동(no-dong),labor"
"손가락(son-ga-rak),finger"
"마르크스(ma-r-k-s),Marx"
"자본주의(ja-bon-ju-yi),capitalism"
}
//You can also format your envelopes like this as one line separated by semicolons, but personally I think the spaced lists above look nicer. It's up to you however you want to set them up.
blanklistparagraph
{
"List paragraph 1"; "List paragraph 2"; "List paragraph 3"; "List paragraph 4"; "List paragraph 5";
}
//**** Don't touch this ***************************************************************
//This is code stuff and nothing for you to worry about, just save the .dic and move on! You're done!
On_\person
{
person
}

BIN
ghost/master/yaya.dll Normal file

Binary file not shown.

45
ghost/master/yaya.txt Normal file
View File

@ -0,0 +1,45 @@
//These define what character set your ghost will be using. Don't touch any of them.
charset, UTF-8
charset.dic, UTF-8
charset.output, UTF-8
charset.file, UTF-8
charset.save, UTF-8
charset.extension, UTF-8
//---- Dictionary Files ---------------------------------------------------------------------
//These are the .dic files your ghost will be using. You can add new .dic files or take them away as you like, just always make sure to test your ghost to make sure it still works if you do. This can be finicky.
//I would recommend adding the initials of your ghost to the front of your .dic files, such as hs_string or hs_bootend, particularly if you're going to be editing multiple ghosts at once, or studying other ghost's files to see how they work. It'll help you keep the files straight in Notepad++. You don't have to though, that's optional. If you do, make sure to change the filenames here too, so if you changed the filename to hs_string, make sure you come back here and change the line here to dic,hs_string.
dicdir, yaya_base
dic, string.dic
dic, aitalk.dic
dic, bootend.dic
dic, mouse.dic
dic, etc.dic
dic, menu.dic
dic, word.dic
dic, commu.dic
dic, nameteach.dic
dic, anchor.dic
//---- Log Location -------------------------------------------------------------------------
//I'm not entirely sure what this does, but basically don't touch it.
//log, ayame.log
msglang,english
//Don't touch anything in here.
//------------------------------------------------------------------------------
//実行ログ
//実行ログをayame.logに記録します。開発時には記録しておいたほうが良いです。
//------------------------------------------------------------------------------
// log, ayame.log
ignoreiolog, ID: OnSecondChange //OnSecondChange無視
ignoreiolog, ID: OnMouse //OnMouse系無視

View File

@ -0,0 +1,4 @@
dic, config.dic, UTF-8
dic, shiori3.dic, UTF-8
dicif, optional.dic, UTF-8
dicif, compatible.dic, UTF-8

View File

@ -0,0 +1,216 @@
//******************************************************************************
//SHIORI/3.0制御スクリプト for YAYA
//互換処理
//******************************************************************************
// aya5.dll設定(旧)
#globaldefine AYAINFO_VERSION 0
#globaldefine AYAINFO_CHARSET 1
#globaldefine AYAINFO_PATH 2
#globaldefine AYAINFO_NAME 3
#globaldefine AYAINFO_AUTHOR 4
// 旧互換性保持のためのシステム関数補完(読み替えのみで対応可能なもの)
#globaldefine SETSEPARATOR SETDELIM
#globaldefine TONUMBER2 TOINT
#globaldefine TOSTRING2 TOSTR
#globaldefine TONUMBER CVINT
#globaldefine TOSTRING CVSTR
#globaldefine ISFUNCTION ISFUNC
#globaldefine BINSTRTONUM BINSTRTOI
#globaldefine HEXSTRTONUM HEXSTRTOI
#globaldefine ERASEVARIABLE ERASEVAR
#globaldefine MSTRLEN STRLEN
#globaldefine MSTRSTR STRSTR
#globaldefine MSUBSTR SUBSTR
#globaldefine MERASE ERASE
#globaldefine MINSERT INSERT
#globaldefine NAMETOVALUE EVAL
#globaldefine CALLBYNAME EVAL
//******************************************************************************
//文 version 4 システム関数 / システム変数の補完
//汎用関数
//******************************************************************************
ASC
{
if !_argc; ' '
elseif GETTYPE(_argv[0]) != 1; ' '
elseif _argv[0] < 0 || _argv[0] > 0x7f; ' '
else; CHR(_argv[0])
}
//----
IASC
{
if !_argc; -1
elseif GETTYPE(_argv[0]) != 3; -1
elseif !STRLEN(_argv[0]); -1
else; CHRCODE(_argv[0])
}
//----
ISINSIDE
{
if _argc < 3; 0
elseif (_argv[1] <= _argv[0] && _argv[0] <= _argv[2]) ||/
(_argv[2] <= _argv[0] && _argv[0] <= _argv[1]); 1
else; 0
}
//----
ISREAL
{
if !_argc; 0
elseif GETTYPE(_argv[0]) == 2; 1
else; 0
}
//----
ISINTEGER
{
if !_argc; 0
elseif GETTYPE(_argv[0]) == 1; 1
else; 0
}
//******************************************************************************
//文 version 4 システム関数 / システム変数の補完
//REQ系関数
//******************************************************************************
//----
REQ.KEY
{
if !_argc; return
switch GETTYPE(_i = _argv[0]) {
// エラー
''
// 位置指定
var.req.key[_i]
// 位置指定(実数) 整数化して処理
var.req.key[TOINT(_i)]
// 文字列はエラー
''
}
}
//----
REQ.HEADER
{
REQ.KEY(_argv)
}
//----
REQ.VALUE
{
if !_argc; return
switch GETTYPE(_i = _argv[0]) {
// エラー
''
// 位置指定
var.req.value[_i]
// 位置指定(実数) 整数化して処理
var.req.value[TOINT(_i)]
// 名前指定
{
_sz = ARRAYSIZE(var.req.key)
for _j = 0; _j < _sz; _j++ {
if (var.req.key[_j] == _i) {
var.req.value[_j]
break
}
}
}
}
}
//******************************************************************************
//文 version 4 システム関数 / システム変数の補完
//LIB系関数
//******************************************************************************
LIB.KEY
{
if !_argc; return
switch GETTYPE(_i = _argv[0]) {
// エラー
''
// 位置指定
var.lib.key[_i]
// 位置指定(実数) 整数化して処理
var.lib.key[TOINT(_i)]
// 文字列はエラー
''
}
}
//----
LIB.HEADER
{
LIB.KEY(_argv)
}
//----
LIB.VALUE
{
if !_argc; return
switch GETTYPE(_i = _argv[0]) {
// エラー
''
// 位置指定
var.lib.value[_i]
// 位置指定(実数) 整数化して処理
var.lib.value[TOINT(_i)]
// 名前指定
{
_sz = ARRAYSIZE(var.lib.key)
for _j = 0; _j < _sz; _j++ {
if (var.lib.key[_j] == _i) {
var.lib.value[_j]
break
}
}
}
}
}
//******************************************************************************
// 文 version 4 以前の変数/関数の補完
//******************************************************************************
restore_old_variables
{
// ascii
ascii = IARRAY
for _i = 0; _i <= 0x7f; _i++ {
ascii ,= CHR(_i)
}
}

View File

@ -0,0 +1,60 @@
/*---------------------------------------------------------------------------------------
* SHIORI/3.0設定スクリプト for YAYA
* --------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------
* 初期設定値
* --------------------------------------------------------------------------------------*/
/* AIトーク関連 -------------------------------------------------------------------------*/
/*
TALK_INTERVAL AIトーク間隔の初期値[秒]
COM_RATIO AIトーク中に占めるコミュニケート開始の割合[%]
*/
#globaldefine TALK_INTERVAL 180
#globaldefine COM_RATIO 0
/* インストール済みゴーストリスト構築関連 -----------------------------------------------*/
/*
IGLIST_ACCEL
1にするとSSP/CROW時にはNOTIFY installedghostnameで
インストール済ゴーストリストを構築するようになります。
sakura/kero名リストは作成されませんが高速です
0だとファイル走査にて構築します。
インストール済みゴーストが多いと時間がかかります。
IGLIST_MAX
ファイル走査にてゴーストリストを構築する際、取得する
数の上限を指定します。-1で制限なし(すべて取得)です。
0とすると取得しません。
*/
#globaldefine SHIORI3FW.IGLIST_ACCEL 1
#globaldefine SHIORI3FW.IGLIST_MAX 0
/* リクエスト解析・レスポンス構築関連 ---------------------------------------------------*/
/*
SHIORI3FW.RES_REF_MAX
res_referenceの上限
SHIORI3FW.AUTO_DATA_CONVERT
1にするとAYA5と同等の処理になります。
-SAORIの戻り値などの自動タイプ変換・自動的に\0x01をカンマにする等の処理が入ります。
0にするとそれらの処理を行いません。
SHIORI3FW.REF_ACCEL
1にすると、reference0 といった変数を作成せず、reference[0] という形で
アクセスするようになります。若干のスピードアップが見込めます。
0にすると、reference0 といった変数を作成します(過去互換処理)
*/
#globaldefine SHIORI3FW.RES_REF_MAX 32
#globaldefine SHIORI3FW.AUTO_DATA_CONVERT 0
#globaldefine SHIORI3FW.REF_ACCEL 0
/*
See: https://github.com/YAYA-shiori/yaya-dic/issues/19
enabling Delayed EVAL will make your ghost more vulnerable to unsuspecting people using it to attack users' computers
make sure this switch is turned off if you can
*/
#globaldefine SHIORI3FW.ENABLE_DELAYED_EVAL 0

View File

@ -0,0 +1,351 @@
//******************************************************************************
//SHIORI/3.0制御スクリプト for YAYA
//オプション関数
//******************************************************************************
#define ESCAPE_TAG_1 CHR(0x3,0x3)
#define ESCAPE_TAG_2 CHR(0x4,0x4)
//******************************************************************************
//初期化・後始末
//******************************************************************************
OnSystemLoad.SHIORI3FW.OPTIONAL
{
}
OnSystemUnload.SHIORI3FW.OPTIONAL
{
ERASEVAR('SHIORI3FW.FMOCache')
ERASEVAR('SHIORI3FW.SakuraNameList')
ERASEVAR('SHIORI3FW.FMOTable')
}
//******************************************************************************
//さくらスクリプトタグ除去
//******************************************************************************
//------------------------------------------------------------------------------
// 関数名:SHIORI3FW.EscapeDangerousTags
// 機能 :危険なタグのみをエスケープ(\付加)する。
// 引数 :argv0=テキスト
//------------------------------------------------------------------------------
SHIORI3FW.EscapeDangerousTags{
_txt=_argv[0]
_txt=REPLACE(_txt,'\\',ESCAPE_TAG_1)
_txt=REPLACE(_txt,'\%',ESCAPE_TAG_2)
_txt=RE_REPLACE(_txt, /
'\\(?=(!\[(' + /
'updatebymyself|vanishbymyself|enter,passivemode|' + /
'leave,passivemode|lock,repaint|unlock,repaint|biff|' + /
'open,browser|open,mailer|raise)' + /
'.*?\]|\\j\[))' , /
'\\')
_txt=REPLACE(_txt,ESCAPE_TAG_2,'\%')
_txt=REPLACE(_txt,ESCAPE_TAG_1,'\\')
_txt
}
//------------------------------------------------------------------------------
// 関数名:SHIORI3FW.EscapeAllTags
// 機能 :全てのさくらスクリプトタグをエスケープ(\付加)する。
// 引数 :argv0=テキスト
//------------------------------------------------------------------------------
SHIORI3FW.EscapeAllTags{
_txt=_argv[0]
_txt=REPLACE(_txt,'\\',ESCAPE_TAG_1)
_txt=REPLACE(_txt,'\%',ESCAPE_TAG_2)
_txt=REPLACE(_txt,'\','\\')
_txt=REPLACE(_txt,'%','\%')
_txt=REPLACE(_txt,ESCAPE_TAG_2,'\%')
_txt=REPLACE(_txt,ESCAPE_TAG_1,'\\')
_txt
}
//------------------------------------------------------------------------------
// 関数名:SHIORI3FW.TranslateSystemChar
// 機能 :演算子などシステム予約文字を別のものに置き換える
// 引数 :argv0=テキスト argv1=置き換え対象(省略時_)
//------------------------------------------------------------------------------
SHIORI3FW.TranslateSystemChar
{
_c = '_'
if _argc >= 2 {
_c = _argv[1]
}
_text = TOSTR(_argv[0])
_text = RE_REPLACE(_text,"[ !%(CHR(0x22))%(CHR(0x25))#$&()*+,\-/:;<=>?@\[\]`{|}~]",_c)
_text
}
//------------------------------------------------------------------------------
// 関数名:SHIORI3FW.InitBalloons
// 機能 :バルーン完全初期化スクリプトを自動生成する
//------------------------------------------------------------------------------
SHIORI3FW.InitBalloons
{
_tx = ''
_n = ARRAYSIZE(SHIORI3FW.HWnd)
for _i = 0 ; _i < _n ; _i++ {
if SHIORI3FW.HWnd[_i] != 0 {
_tx += "\p[%(_i)]\c\b[-1]"
}
}
_tx
}
//******************************************************************************
// FMO関連
//******************************************************************************
//------------------------------------------------------------------------------
//関数名:SHIORI3FW.IsGhostExist(ゴースト名(sakuraname)[,fmoname])
//機能 :指定されたゴーストが存在するか調べる
//    存在しなければ0、存在すれば1を返す
//------------------------------------------------------------------------------
SHIORI3FW.IsGhostExist
{
_ghostname=_argv[0]
SHIORI3FW.RefreshFMOTable(_argv[1])
_result=ASEARCH(_ghostname,SHIORI3FW.SakuraNameList)
if _result == -1 {
0
}else{
1
}
}
//------------------------------------------------------------------------------
//関数名:SHIORI3FW.RefreshFMOTable(FMO名称,無視するエントリのHWND)
//機能 :READFMOによってFMOテーブルを作る。
/*
FMOはキャッシュされ、変わっていなければ解析は行われない。
FMO名称を省略すると自動的に'Sakura'になる。
無視するエントリのHWNDを省略すると、SHIORI3FW.HWnd[0] 変数が利用される。
(つまり自動的に自身の情報は含まれなくなる)
グローバル変数:SHIORI3FW.FMOCache FMOの内容のキャッシュ(単純ダンプ)
グローバル変数:SHIORI3FW.FMOTable FMOのテーブル(簡易配列。内容は以下)
id|name|keroname|hwnd|kerohwnd|path|ghostpath,
id|name|keroname|hwnd|kerohwnd|path|ghostpath,
...
グローバル変数:SHIORI3FW.SakuraNameList sakuranameを列挙した汎用配列
また、いわゆる「非ゴースト」FMOエントリ(一時起動等)はこの時点で排除される。
*/
//------------------------------------------------------------------------------
SHIORI3FW.RefreshFMOTable : void
{
_fmoname=TOSTR(_argv[0])
if _fmoname == '' {
_fmoname='Sakura'
}
_result=''
if _fmoname == 'SakuraUnicode'
_result=READFMO(_fmoname,'UTF-8')
else
_result=READFMO(_fmoname)
if SHIORI3FW.FMOCache == _result {
//変わっていなければ即座に戻る
return
}
//FMOの内容をキャッシュする
SHIORI3FW.FMOCache=_result
SHIORI3FW.FMOTable=''
SHIORI3FW.SakuraNameList=IARRAY
_ignorehwnd=TOSTR(_argv[1])
if _ignorehwnd == '' {
_ignorehwnd = SHIORI3FW.HWnd[0]
}
//\r\nで分割
_array = SPLIT(_result,C_CRLF)
_arraynum=ARRAYSIZE(_array)
//変数初期化
_fmotable_temp=''
_id=''
_oldid=''
_name=''
_keroname=''
_hwnd=''
_kerohwnd=''
_path=''
_ghostpath=''
//結果を擬似2次配列にストア
//ssp_fmo_header_000024dc_005c094e.hwnd,6031694
//<------------------id----------> key value
for _i=0 ; _i<_arraynum-1 ; _i++ {
//一時起動ゴーストかどうか?
_buf=_array[_i]
_id=_buf[0,'.']
if 'SSTPVIEWER-' _in_ _id || 'ssp_fmo_header_dummyentry' _in_ _id || 'SSSB' _in_ _id{
//一時起動なのでなにもしない
}else{
if _oldid == '' {
_oldid = _id
}
//IDが変わったら一時保存を書き出し
if _oldid != _id {
_fmotable_temp+="%(_oldid)|%(_name)|%(_keroname)|%(_hwnd)|%(_kerohwnd)|%(_path)|%(_ghostpath),"
_oldid = _id
_name=''
_keroname=''
_hwnd=''
_kerohwnd=''
_path=''
_ghostpath=''
}
_kvpair=_buf[1,'.']
_key=_kvpair[0,C_BYTE1]
_val=_kvpair[1,C_BYTE1]
//各値を一時保存
case _key {
when 'hwnd' {_hwnd=_val}
when 'name' {_name=_val}
when 'keroname' {_keroname=_val}
when 'path' {_path=_val}
when 'kerohwnd' {_kerohwnd=_val}
when 'ghostpath'{_ghostpath=_val}
}
}
}
//最後のエントリを書き出し
_fmotable_temp += "%(_id)|%(_name)|%(_keroname)|%(_hwnd)|%(_kerohwnd)|%(_path)|%(_ghostpath)"
//無視するHWNDを取り除き、同時にSakuraNameListを作成
_count_temp=ARRAYSIZE(_fmotable_temp)
for _i=0;_i<_count_temp;_i++ {
_tablestr=_fmotable_temp[_i]
_tablehwnd=_tablestr[3,'|']
if _tablehwnd != _ignorehwnd {
SHIORI3FW.FMOTable += _tablestr+','
SHIORI3FW.SakuraNameList=(SHIORI3FW.SakuraNameList,_tablestr[1,'|'])
}
}
//最後がカンマなら取り除く
if SUBSTR(SHIORI3FW.FMOTable,STRLEN(SHIORI3FW.FMOTable)-1,1)==',' {
SHIORI3FW.FMOTable=SUBSTR(SHIORI3FW.FMOTable,0,STRLEN(SHIORI3FW.FMOTable)-1)
}
}
//******************************************************************************
// テキスト処理
//******************************************************************************
//------------------------------------------------------------------------------
// 関数名:SHIORI3FW.MakeJustText
// 機能 :指定した長さになるまでスペースを埋める / 省略する
// 引数 :argv0=テキスト argv1=文字数(半角換算)
//------------------------------------------------------------------------------
//---- 後ろにスペースを補完する関数 (from和音)
SHIORI3FW.MakeLongText
{
_menuitem = _argv[0]
_len = _argv[1] - GETSTRBYTES(_menuitem,127)
if _len <= 0 {
_menuitem
return
}
_space = ' '
_menuitem += SUBSTR(_space,0,_len)
_menuitem
}
//---- 適当な長さで切る -------------------------------------------
SHIORI3FW.MakeShortText
{
if _argc < 2 {
''
return
}
_src = _argv[0]
_cut = TOINT(_argv[1])
_text = ''
if GETSTRBYTES(_argv[0],127) <= _cut {
_argv[0]
return
}
_num = STRLEN(_src)
_lendiff = 0//後で保存するためにスコープを一つ下げるためのダミー代入
while 1 {
_text = SUBSTR(_argv[0],0,_num)
_lendiff = _cut - GETSTRBYTES(_text,127) - 2
if _lendiff >= 0 {
break
}
_num -= 1
if _num <= 0 {
''
return
}
}
if _lendiff > 0 {
_text += '...'
}
else {
_text += '..'
}
_text
}
//---- 長さをきっちり調節
SHIORI3FW.MakeJustText
{
_text = SHIORI3FW.MakeLongText(_argv[0],_argv[1])
if _text != _argv[0] {//短すぎた
_text
return
}
_text = SHIORI3FW.MakeShortText(_argv[0],_argv[1])
_text
}
//******************************************************************************
// その他
//******************************************************************************
//---- HTTPコード->日本語 _argv[0]にコード
SHIORI3FW.HTTPCodeToMessage
{
case _argv[0] {
when '403' {
'アクセス拒否'
}
when '404','410' {
'ファイル無し'
}
when '500','502','503' {
'サーバ側の不調'
}
when 'timeout' {
'タイムアウト'
}
when 'fileio' {
'ファイル書き込みエラー'
}
when 'artificial' {
'手動中断'
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
//savefile_charset,UTF-8
aitalkinterval,300,",",
communicateratio,0,",",
ghostupmin_last,9082,",",
ghostuptimes,48,",",
SHIORI3FW.LastSurface,0:10,",",
SHIORI3FW.IsVisible,1:1,",",
SHIORI3FW.ShellNameOld,"Lyuma default",",",
SHIORI3FW.ShellName,"Lyuma default",",",
SHIORI3FW.ShellPath,"C:/Users/Denis-PC/Downloads/SSP/ghost/lyuma/shell/master/",",",
SHIORI3FW.BalloonNameOld,"Plasma Tablet",",",
SHIORI3FW.BalloonName,"Plasma Tablet",",",
SHIORI3FW.BalloonPath,"C:/Users/Denis-PC/Downloads/SSP/balloon/plasmatablet/",",",
username,"Master",",",
deleteshitai,"OFF",",",
ghostexlist,"Gaster_EsC_CtRl_CoDe_A0_EsC_CtRl_CoDe_A10",",",
ghostexcount,1,",",
sakurahwnd,"9439496_EsC_CtRl_CoDe_A4528964",",",
sakurablnhwnd,"4790730_EsC_CtRl_CoDe_A13243618",",",
isProgramAvailable,1,",",
isRunning,1,",",
programTitle,"C:\\Users\\Denis-PC\\Downloads\\SSP\\ghost\\lyuma\\ghost\\master\\aitalk.dic - Notepad++",",",
programInstancesRunning,1,",",
passhour,0,",",
passmin,0,",",
passsec,0,",",
stroke,0,",",
teachusername,0,",",
mikireflag,0,",",
birthdayprint,"????",",",
talktime,"5 minutes",",",
nowshell,"master",",",
displaybpp,32,",",
displaywidth,1920,",",
displayheight,1080,",",
wd,"Sun",",",
ap,"PM",",",
os_name,"Windows 11 25H2",",",
os_version,"10.0",",",
cpu_name,"11th Gen Intel(R) Core(TM) i5-11400H @ 2.70GHz",",",
cpu_clockex,"2700.000",",",
AlreadyResponded,1,",",
tempname,"Master",",",
appTitle,"leylines - Apache NetBeans IDE 23",",",
isNetBeansRunning,0,",",
eclipse,0,",",
npp,1,",",
javaruns,0,",",
javaAppTitle,"leylines - Apache NetBeans IDE 23",",",
NetbeansOpen,0,",",
Netbeans,"IME",",",

9
install.txt Normal file
View File

@ -0,0 +1,9 @@
charset,UTF-8
type,ghost
name,Lyuma
directory,lyuma
//This tells the program what balloon your ghost will be using. You should only uncomment this line if you're bundling a balloon with your ghost. Meaning, inside your ghost folder, you have ghost, shell, and your balloon's folder (like z_simple, balloontime, newsreport). If your balloon folder in there, it will install with your ghost. If you do NOT have a balloon included with your ghost, then leave this line commented.
//balloon.directory,z_simple

8
readme.txt Normal file
View File

@ -0,0 +1,8 @@
--Readme--
A bodyguard foxgirl ghost.
You're all she has left. Take a good care of her.
Repo: https://git.coders-teaparty.cafe/sova/lyuma/
Author: sova
ping Maggistrator#1995 on discord if she breaks

111
shell/master/descript.txt Normal file
View File

@ -0,0 +1,111 @@
//There's a lot more going on in the descript.txt for a shell than for your ghost in general, as you can probably tell. I'll try to break it down.
//Free or Bound
//This determines whether or not your ghost can be moved freely around the desktop or if it's stuck to the bottom or top of the desktop. The three values you can use here are free, bottom, and top. If your ghost is cut off at the chest or something, then you'd want it to be stuck to the bottom of the screen. Likewise if you're doing a hanging ghost, like Glados or Flowey or something, then you'd want to use top. Right now, this is set to free, meaning the ghost can be moved around freely by the user.
seriko.alignmenttodesktop,free
//Use_self_alpha
//This makes it so you don't have to use pna files for your shell. Saves a ton of time and effort.
seriko.use_self_alpha,1
//General Information
//A few things here, a lot fairly similar to the descript.txt for your ghost. charset and type will be unchanged. Replace name with the name for your shell and put in your name for the craftman and the url.
charset,UTF-8
type,shell
name,Lyuma default
craftman,sova
craftmanurl,https://coders-teaparty.cafe/
//Balloon Co-ordinates
//These basically define where your balloon starts for your main character (sakura) and your secondary character (kero). While you're testing your ghost, you'll notice that moving the balloons around shows you a set of coordinates on the bottom. Move your balloons where you want them, write down the coordinates, and copy them here. Otherwise, you can just leave them at 0. Your user will adjust them as they need to, so I wouldn't sweat this too much.
//Alignment means which way you want your balloon to be facing. There are three options here: right, left, or none. If you choose right or left, the balloon will ALWAYS face right or left. If you put none, however, the balloon will flip sides whenever it hits the side of the screen. For example, if you drag your ghost with a right balloon all the way to the right side of your screen, it'll flip the balloon to the left side. I generally prefer putting it to none because it's convenient to me to flip balloons as I need to, but this is up to you.
sakura.balloon.offsetx,0
sakura.balloon.offsety,0
kero.balloon.offsetx,0
kero.balloon.offsety,0
sakura.balloon.alignment,none
kero.balloon.alignment,none
//Shiori Icon
//Don't mess with any of this.
shiori.logo.filename,resources\niseshiori.png
shiori.logo.x,16
shiori.logo.y,256
//Menu Font Color
//Like it says, this is the font color for the right-click SSP menu. r g b stand for red blue green, adjust the values to get the color you want. This'll probably take some trial and error.
menu.background.font.color.r,0
menu.background.font.color.g,0
menu.background.font.color.b,0
//Menu Highlighted Text Color
//See above
menu.foreground.font.color.r,255
menu.foreground.font.color.g,255
menu.foreground.font.color.b,255
//Menu Greyed Out Font Color
//For options that aren't selectable for some reason.
menu.disable.font.color.r,222
menu.disable.font.color.g,222
menu.disable.font.color.b,222
//Menu Separate Color
//The color of the tiny line that separates the sections on the menu.
menu.separator.color.r,240
menu.separator.color.g,240
menu.separator.color.b,240
//Menu Background Image Alignment
//If you have images you want to set for your menu, this determines the alignment of the background and foreground pictures. You can put in lefttop, righttop, or centertop, and bottom or top for the sidebar. You'd be replacing righttop or bottom with whatever alignment you prefer.
menu.background.alignment,righttop
menu.foreground.alignment,righttop
menu.sidebar.alignment,bottom
//Menu Background Image Location
//The location of the files you want to use for your background images. You'd be replacing menu_background.png with whatever the name is for your background image, and so on. If you've just saved images over mine, you won't have to adjust this at all I think.
menu.background.bitmap.filename,menu_background.png
menu.foreground.bitmap.filename,menu_foreground.png
menu.sidebar.bitmap.filename,menu_sidebar.png
//--Dress-up Code
//Clothing can be a little complicated, so I'd recommend reading the clothing page on the walkthrough before coming back here. I'll leave a bit of cindysuke's clothing code in here just as an example. If you're going to use these lines, make sure to uncomment them by removing the slashes.
//As a brief overview, sakura (the main character), has a clothing item called "glasses" that's in a section called "face". The second character, kero, has two items, one called "glasses" in the "face" section and one called "hairpins" that's in the "hair" section. What you call these sections and items of clothing is up to you if you're actually doing this. Note the numbers after bindgroup though! We're going to be using them in just a second.
//sakura.bindgroup51.name,face,glasses
//kero.bindgroup55.name,face,glasses
//kero.bindgroup57.name,hair,hairpins
//Dress-Up Menu Organization
//This sets up how the clothing appears in the dress-up menu. You can see the main character only has one item, while the second has two split by a dash. Note that it uses the same numbers defined above for each item.
//sakura.menuitem0,51
//kero.menuitem0,55
//kero.menuitem1,-
//kero.menuitem2,57

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -0,0 +1,19 @@
Charset,UTF-8
__system_settings_version__,2
balloon,C:\Users\Denis-PC\Downloads\SSP\balloon\plasmatablet\
Char1.balloon.isleft,1
scriptbox.left,960
Char0.ratio.x,0,959375000
Char0.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
Char0.ratio.y,1,004629630
Char0.balloon.isleft,1
Char.VirtualDesktop,5d1be626-0563-4e74-b79d-89ffdb19ff93
Char1.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
scriptbox.top,510
seriko.scaling.percent.x,100
seriko.scaling.balloon.percent.x,100
seriko.scaling.percent.y,100
seriko.scaling.balloon.percent.y,100
Char1.ratio.x,0,867187500
Char1.ratio.y,0,960185185
__system_written_flag_do_not_remove__,written

View File

@ -0,0 +1,19 @@
Charset,UTF-8
__system_settings_version__,2
balloon,C:\Users\Denis-PC\Downloads\SSP\balloon\plasmatablet\
Char1.balloon.isleft,1
scriptbox.left,960
Char0.ratio.x,0,959375000
Char0.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
Char0.ratio.y,1,004629630
Char0.balloon.isleft,1
Char.VirtualDesktop,5d1be626-0563-4e74-b79d-89ffdb19ff93
Char1.ratio.devid,Z1g/qX4t03xfxkC0GwGPGw==
scriptbox.top,510
seriko.scaling.percent.x,100
seriko.scaling.balloon.percent.x,100
seriko.scaling.percent.y,100
seriko.scaling.balloon.percent.y,100
Char1.ratio.x,0,867187500
Char1.ratio.y,0,960185185
__system_written_flag_do_not_remove__,written

21
shell/master/read me.txt Normal file
View File

@ -0,0 +1,21 @@
Hey there! It's me Zar and I'm going to level with you, setting up surfaces.txt sucks. I've left a lot of commentary in the file itself, but it may give you a lot of trouble at first. Make sure to read the walkthrough site carefully! All my commentary in surfaces.txt is reproduced there, and may be easier to read than just a straight text file.
This ghost template is simple on purpose too make it as easy as possible for a new ghost developer, so it doesn't really touch on a lot of the more complicated things you can do with surfaces.txt. I explain some tricks within surfaces.txt itself, but you don't have to use them if you don't want to. Advanced users may want to keep them in mind though, and check the more in-depth pages about surfaces.txt on the walkthrough page. Which is here, just in case you got this from somewhere else (?)!
http://www.ashido.com/ukagaka/
Some more handy resources about surfaces.txt can be found where FLELE shell makers congregate, namely at shell-collectors on devart. So here are a few links to some tutorials about surfaces.txt that may come in handy, you may want to read these and then come back and tackle surfaces.txt with new ideas if you're feeling adventurous.
http://shell-collectors.deviantart.com/art/How-to-Make-a-FLELE-Shell-256095495
http://shell-collectors.deviantart.com/art/Flele-Coding-Tutorial-173914239
http://shell-collectors.deviantart.com/art/Flele-Coding-Tutorial-2-1-180479304
http://shell-collectors.deviantart.com/art/Flele-Coding-Tut-3-pt-1-of-2-194386056
http://shell-collectors.deviantart.com/art/Flele-Coding-Tut-3-pt-2-of-2-196349241
Other resources listed on the walkthrough site are (and these are all in Japanese for the record, so you may have to use Google translate)...
http://usada.sakura.vg/contents/seriko.html
http://disc2.s56.xrea.com/manual/manual_animation.html
http://ssp.shillest.net/ukadoc/manual/descript_shell_surfaces.html
If you're looking to do more in-depth work with shells, these are definitely the places you'll want to go to get more info.

BIN
shell/master/surface0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
shell/master/surface10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

559
shell/master/surfaces.txt Normal file
View File

@ -0,0 +1,559 @@
//---------------------------Surfaces.txt--------------------------
//Images are brought together into a thing I generally refer to as a pose, but what is defined in the shell and this text file as a Surface. Each Surface can contain any number of images in it doing any number of things. These Surfaces are what is being called when you use the \s[] tag when writing dialogue. For example, you could create a pose with three images under Surface5, and then in dialogue, you would call that pose made of three images with \s[5]. That's the basic jist of how this file works.
//I wrote up some pages about making images and surfaces.txt on the walkthrough (http://www.ashido.com/ukagaka/) so I highly recommend you read those as well.
//I will reiterate that you should be editing these in Notepad++, and in particular, you should set the Language to C (or Java I guess) to properly highlight all the text. It will make things A LOT EASIER for you, trust me! It will also help you keep track of your brackets in case you forget some. If you click on a line with a bracket in Notepad++, it should highlight where the other bracket ends, or turn purple if there's no finishing bracket (which you should definitely fix!)
//It will also highlight my commented lines in green, so you'll know where they are. Any line beginning with // is a commented line that the code will not read. It's just for your reference!
//There are a lot of crazy tricks you can do with surfaces.txt if you're creative and determined, but you won't have to worry about any of them (although I will include some commented out examples for my own reference). The easiest, easiest way to do this file is simply to replace the images I've already made. There should be around 10 poses for each character defined in surfaces.txt. They break down like this.
//0 - Girl's default pose. This is made up of a few images.
//surface0.png, her full default frame with her eyes and mouth in place to layer stuff on.
//surface1001.png, her half-closed eyes
//surface1002.png, her closed eyes. These two frames are used to make her blinking animation.
//surface1101.png, her half-open mouth
//surface1102.png, her open mouth. These two frames are used for her talking animation.
//1 - Girl's embarrassed pose.
//From here on, each pose is a single still image. This is surface1501.png
//2 - Girl's surprised pose.
//surface1502.png
//3 - Girl's worried pose.
//surface1503.png
//4 - Girl's sad/disappointed pose.
//surface1504.png
//5 - Girl's smiling pose.
//surface1505.png
//6 - Girl's contented pose.
//surface1506.png
//7 - Girl's angry pose.
//surface1507.png
//8 - Girl's thoughtful pose.
//surface1508.png
//9 - Girl's bored pose.
//surface1509.png
//10 - Triangle's default pose. Like Girl, this pose is broken up into multiple pieces because it has an animation.
//surface10.png, his default base frame to layer stuff on.
//surface2001.png, his half-closed eyes.
//surface2002.png, his closed eyes. These are for his blinking animation.
//11 - Triangle's embarrassed pose. Like above, these are single still frames.
//surface2501.png
//12 - Triangle's surprised pose.
//surface2502.png
//13 - Triangle's worried pose.
//surface2503.png
//14 - Triangle's sad/disappointed pose.
//surface2504.png
//15 - Triangle's smiling pose.
//surface2505.png
//16 - Triangle's contented pose.
//surface2506.png
//17 - Triangle's angry pose.
//surface2507.png
//18 - Triangle's thoughtful pose.
//surface2508.png
//19 - Triangle's bored pose.
//surface2509.png
//If you look at the image files themselves, you'll see that all the images for Girl are in the 1000 range, and the images for Triangle are in the 2000. ALL YOU NEED TO DO is draw your character with whatever expression you want and save it over the appropriate file. That way, you won't have to adjust any of the coding in surfaces.txt itself, you'll just be replacing the images. You should read through this file anyway though to get an idea of how it works.
//However, there is one snag here! Girl's default pose has blinking eyes and a moving mouth, and for that, you'll need to study the files for that pose very carefully. Note that the different eye frames and mouth frames are separate files and only have the eyes and the mouths in them. You'll have to do the same. All you have to do is select around your eyes, inverse, delete everything, and save it for each eye frame, and likewise for the mouth frames. I talk about this in a bit more detail in the making images section of the walkthrough page. Hopefully it won't be too hard. If worse comes to worse and you just can't get it to work, you can delete the blinking and talking sequences from surface0 if you have to.
//(Basically, what surfaces.txt does is overlay the mouth or eye frames on top of your base image to make the animation. That's why all you want in that overlaid frame is the eyes or the mouth.)
//Likewise, if you want to add blinking eyes and a moving mouth to your other poses, you'll have to do the same thing as with the default pose - make individual frames for the eyes and mouth, copy and paste the code for the blinking/mouth sections in surface0 to the other surface you want to add them to, and replace the file numbers where appropriate.
//You can change the size of the images if you want to draw a much bigger character than I did! If you do that though, MAKE SURE ALL YOUR IMAGES FOR THAT CHARACTER ARE THE SAME SIZE. So if Girl's image dimensions are 400x400, and you draw a Main Character that's 800x800, MAKE SURE ALL the images for your main character are also 800x800! This applies to the side character too, ALL the images for your side character should be the same dimensions! If your side character is 250x250, all side character images should be 250x250!
//The main character and the side character DON'T have to be the same size though, so you can have a tiny sidekick and a huge dude if you want, like... I dunno, Gillian Seed and Metal Gear Mk. II for example, or Torin and Boggle. The image dimensions just need to be consistent throughout for each character, because believe me, it will make things MUCH, MUCH easier for you from this point on if you do that.
//ONE MORE NOTE - If you are planning on doing a single person ghost without a sidekick character at all, all you have to do is save a blank png over all the files for the secondary character, ESPECIALLY Surface10.png. Then just don't write any dialogue for the secondary character in the .dic files. Problem solved. You can also just delete all the pngs for Triangle but DON'T delete Surface10.png though.
//More advanced users can even rewrite the poses in this file originally intended for the secondary character, 11-19, for their main character instead if you need to and save main character poses over the second character ones, AS LONG AS Surface10.png is blank.
//--The Main Character's Poses---------------------------------------------------------
surface0
//surface0 is the basic default pose for your main character. I'll include a few examples of things you can do in this pose, but you won't have to use any of them if you don't want to. They're mostly for (my) reference and advanced users for the most part.
{
collision0,57,22,112,46,Head
collision1,65,50,105,91,Face
//Collisions define "hot spots" on your ghost where the user can pet or double click them (as defined in mouse.dic). You can see that there are two collisions here, collision0 and collision1. You can add more by copypasting and raising the number, like collision2, collision3, collision4, and so on.
//The four numbers after that are x/y coordinates. Specifically, the first two numbers are the x/y coordinates of the TOP LEFT corner of your hotspot. The third and fourth numbers are the coordinates of the BOTTOM RIGHT corner of the hotspot. Essentially, this is outlining a rectangle.
//There are a few ways of finding the coordinates for the collisions of your ghost. One easy way is to use the Coordin4 program that's linked to on the walkthrough site, in the "Surfaces.txt and Descript.txt" page. It's easy and quick, and I'd recommend giving it a try!
//The other option is to draw a rectangle on top of your image in whatever art program you're using, then manually finding the coordinates for the top left and bottom right corners. There are some visual examples of this on the same walkthrough page above.
//After that, you have to name the area you highlighted. In collision0's case, the area is named "Head". If you go into mouse.dic, you'll see that this name is referenced when the mouse is over that area or interacting with it. Remember what word you use for what area. You can call the areas whatever you want, just make sure it's consistent between surfaces.txt and mouse.dic.
//Then basically repeat this for any other collisions you may want to set up. You can have as many collisions as you want for as many places on your ghost as you want!
//Collisions only apply to the Surface they're in, unless they're appended using surface.append at the bottom of this file. This means you can have certain collisions that only appear in certain poses, like giving your character a high five when their hand is up. You can be creative with these.
//If you REALLY can't figure out collisions and just can't get them to work, you can delete the two collision lines. This will make your ghost un-pettable though and much of what you defined in mouse.dic won't work. Their menus should still function though I think. But if you are desperate, this is an option.
element0,overlay,surface0.png,0,0
//Here is the line of code that defines the base image we'll be using for the ghost. If you aren't just replacing my images and moving on, you'll want to replace the surface0.png part with whatever image file you're using as your base pose. But really, your base default pose should ALWAYS be surface0.png for your main character. There are very few situations where this line would need to be changed in any way. Likewise, I wouldn't change it from surface10 for your secondary character's default pose either.
//*********************Advanced User Info*******************************
//These text boxes are meant for those who have an interest in expanding or using more complicated functions in their ghost. Also for my own reference in the future since I plan on using this template too, haha. If you have no interest in any of this and just want to keep things as simple as possible, feel free to skip these boxes.
//A note about element - you can have multiple elements! You can layer them on top of each other if you want, and they'll be there permanently in the pose. So for example, you could do something like this
//element0,overlay,surface0.png,0,0
//element1,overlay,surface9.png,0,0
//Where surface0 could be the body, and surface9 could be the head. I don't normally use this very often, but if you want to have something always on your ghost and don't want to use a runonce interval, this may be the way to do it. It could work for things like having a body that doesn't change and a head that changes expressions, for example.
//An element also doesn't need to be the first frame of an animation, it can also be the last one. This can come in handy for certain animations that only run once.
//***********************************************************************
//--Blinking---------------------------------------------------------------------------
//Here's the animation block to set up a random blink.
//0interval,random,4
//0pattern0,-1,10,overlay,0,0
//0pattern1,1002,5,overlayfast,0,0
//0pattern2,1001,10,overlayfast,0,0
//0pattern3,-1,3,overlay,0,0
//For those just replacing my images, you won't have to mess with any of this. Just be sure that your blink frames look like my blink frames. For those who are going to reuse this block or do their own thing, all you need to do is replace 1001 and 1002 with the file numbers of your new blink frames. Everything else can stay exactly the same.
//If you want to know more about the exact mechanics of how these lines of animation work, I'd recommend reading the page on the walkthrough site about SERIKO coding, which breaks it down piece by piece. I'll touch on it a little here though.
//You can think of an "interval" as a set block defining an animation, like a blink in this case, and you'll notice each interval is followed by a number of lines starting with "pattern". The pattern lines are the frames that make up the animation. I've seen this described once like interval is a paragraph, and pattern are the lines of the paragraph.
//Each interval/pattern block has a number - in this case, it's 0, so it's 0interval and 0pattern. Patterns have a second number though, identifying what frame it is. So, 0pattern1, 0pattern2, 0pattern3, and so on. After [#]pattern[#] is the filename you're using for that frame, like surface1002, or surface1001. After that is the delay on the frame before it - 5. The word after that is the animation method you're using for the frame, in this case a mix of overlay and overlayfast, and the last two numbers are the x/y coordinates of the images - 0,0.
//Other animation methods besides overlay and overlayfast are base, move, and replace. More on those on the SERIKO page on the walkthrough, but I'll get into them a little later on in this file.
//--Talking-----------------------------------------------------------------------------
//This block deals with your ghost's mouth moving as it speaks to you.
//1interval,talk,4
//1pattern0,0,0,alternativestart,[2.3.4]
//You can see some unique things about this block. The interval is set to talk,4, which means it'll run for every four characters or so that appear in the balloon. You can change 4 to a different number but there's no reason to, I wouldn't do it myself.
//Below that line, you can see alternativestart, then some numbers in some brackets. What this does is that it will randomly select an interval with that number as it runs. Look below, do you see the intervals numbered 2, 3, and 4? Those are the intervals this animation will call. You can add numbers to those brackets or take them away if you want, so you could do things like [2.3.4.5] or [2.3] or whatever.
//2interval,never
//2pattern0,1102,10,overlay,0,0
//2pattern1,1101,13,overlay,0,0
//2pattern2,-1,10,overlay,0,0
//3interval,never
//3pattern0,1101,14,overlay,0,0
//3pattern1,-1,10,overlay,0,0
//4interval,never
//4pattern0,1102,14,overlay,0,0
//4pattern1,-1,10,overlay,0,0
//These three intervals handle the talk frames. For those who are doing their own thing or adding talk frames to their other Surfaces, all you need to do is copy and paste the talk blocks (1interval to 4interval) into the Surface you want and replace 1101 and 1102 with the appropriate file numbers for your new talk frames. You can also add more frames to your talking animation if you want. Those just replacing my images don't have to worry about any of this, as long as your mouth frames look like mine.
//IMPORTANT NOTE: IF YOU'RE DOING A PROFILE VIEW AND YOUR MOUTH IS MOVING OUTSIDE THE BODY then you're going to need to use Replace instead. I'm sorry for your loss. I'll get into Replace later. Your other option is to change your pose or move your mouth or do something to make sure your mouth's movement does not break your character's silhouette. If any furries are reading this, you will probably run into this problem a lot with any kind of side-view of a muzzle.
//IF YOU ABSOLUTELY CAN'T GET THE BLINKING/TALKING FRAMES TO LOOK RIGHT
//If it comes to that, you can delete those chunks of code and just leave surface0 like the other simple poses below. It'd look something like
//surface0
//{
//collision0,57,22,112,46,Head
//collision1,65,50,105,91,Face
//element0,overlay,surface0.png,0,0
//}
}
//Main Character Embarrassed pose
surface1
{
element0,overlay,surface1501.png,0,0
}
//Main Character Surprised pose
surface2
{
element0,overlay,surface1502.png,0,0
}
//Main Character Worried pose
surface3
{
element0,overlay,surface1503.png,0,0
}
//Main Character Sad/Disappointed pose
surface4
{
element0,overlay,surface1504.png,0,0
}
//Main Character Smiling pose
surface5
{
element0,overlay,surface1505.png,0,0
}
//Main Character Contented pose
surface6
{
element0,overlay,surface1506.png,0,0
}
//Main Character Angry pose
surface7
{
element1,overlay,surface1507.png,0,0
}
//Main Character Thoughtful Pose
surface8
{
element1,overlay,surface1508.png,0,0
}
//Main Character Bored pose
surface9
{
element1,overlay,surface1509.png,0,0
}
//--The Side Character's poses------------------
//I actually intended to do the same thing here with Triangle's default pose as I did with Girl, but then I remembered that he has no mouth, so he can't even use talking frames, haha. He can however use blinking frames! So I'm going to copy the same blinking chunk from surface0 and put it here.
surface10
{
collision0,58,199,85,218,Face
collision1,96,128,140,162,Point
//Here are Triangle's collisions. Because they are within Surface10, they only apply when he is in this pose. As mentioned above in surface0, you can set unique collisions for any Surface you like, or you can use surface.append at the end of this file to apply the same collisions to a wide range of surfaces.
element0,overlay,surface10.png,0,0
//Here is Triangle's base frame.
//Blinking
0interval,random,4
0pattern0,-1,10,overlay,0,0
0pattern1,2002,5,overlayfast,0,0
0pattern2,2001,10,overlayfast,0,0
0pattern3,-1,3,overlay,0,0
//Then all I did was change the file numbers to the right numbers for Triangle's blink. Done!
//If your second character has a mouth though and wants to use the talking frames, you'd want to borrow the code from surface0 for it. I'll put it here just to make it a bit easier to find, but I'll comment it out. If you're going to use it, erase the slashes // to uncomment it and put in the right file numbers for your mouth frames instead of 1102 and 1101. Done!
//1interval,talk,4
//1pattern0,0,0,alternativestart,[2.3.4]
//2interval,never
//2pattern0,1102,10,overlay,0,0
//2pattern0,1101,13,overlay,0,0
//2pattern1,-1,10,overlay,0,0
//3interval,never
//3pattern0,1101,14,overlay,0,0
//3pattern1,-1,10,overlay,0,0
//4interval,never
//4pattern0,1102,14,overlay,0,0
//4pattern1,-1,10,overlay,0,0
}
//And that's it for Triangle's default pose! Like with the main character poses above, all we have to do for the following surfaces is make sure they're pointing at the right file number!
//Side Character Embarrassed pose
surface11
{
element1,overlay,surface2501.png,0,0
}
//Side Character Surprised pose
surface12
{
element1,overlay,surface2502.png,0,0
}
//Side Character Worried pose
surface13
{
element1,overlay,surface2503.png,0,0
}
//Side Character Sad/Disappointed pose
surface14
{
element1,overlay,surface2504.png,0,0
}
//Side Character Smiling pose
surface15
{
element1,overlay,surface2505.png,0,0
}
//Side Character Contented pose
surface16
{
element1,overlay,surface2506.png,0,0
}
//Side Character Angry pose
surface17
{
element1,overlay,surface2507.png,0,0
}
//Side Character Thoughtful pose
surface18
{
element1,overlay,surface2508.png,0,0
}
//Side Character Bored pose
surface19
{
element1,overlay,surface2509.png,0,0
}
//And that's it! We're done! But before we go, there are a few more little things you may want to think about.
//--surface.append-------------------------------------------------------------------
//This function is primarily for advanced users, so you can skip it if it seems too scary to you. Otherwise, read on. It may be useful.
//Surface.append basically applies the coding within the brackets to the poses specified in the number range. Specifically in this case it applies to collisions. If the collision areas for your ghost don't change very much from pose to pose, then you can set them here for multiple surfaces at once and save yourself some time.
//I'm not actually going to use surface.append since Girl and Triangle move around too much for their collisions to be that consistent between poses, but it's something could potentially come in handy for advanced users or ghost makers who have very stationary ghosts, so I'll leave it here and just append it to surfaces that don't exist so it won't get in the way. If you want to use this, study this example and see how it can apply to your own ghost.
surface.append500-590 //this is appending this code to Surface500 through Surface590.
//There are actually a few special ways you can refine this! For example, surface.append500-590,205 would append the code to Surface500 to Surface590, as well as Surface205.
//surface.append500-590,205,!507-509 it would do the same, except it would skip Surfaces507 through 509.
//you can have multiple surface.appends as well, if you want to append one set of code to one range of surfaces and another to another. For example, one set of collisions to your main character and one to your side character.
{
collision0,15,16,111,48,Face
collision1,40,50,102,84,Point
//Because this is under surface.append, that means that these collisions are being set for every surface between the number range specified, in this case every Surface from 500 to 590. Make sure to put surface.append at the end of your file, so it can append the values to surfaces that exist.
//--bind-------------------------------------------------------------------------------
//Bind is an interval function only used for dress-up items, therefore if your ghost has no dress-up items, you will not need to bind anything and can safely disregard this. See the walkthrough page about clothing for more details about bind. I'll comment these out since the template won't have clothing items.
//51interval,bind
//51pattern0,999,2,add,0,0
//One final note on bind, note that it is also under surface.append along with the collisions up there. Meaning that this clothing would bind across those multiple surfaces just like the collisions. You can set up bind individually for a pose I think, but I honestly haven't messed around with it very much.
//You can use surface.append to technically apply anything across multiple poses, I'm pretty sure... even images. I haven't messed with this too much myself, but I'm pretty sure it's possible. As with many things with ghosts, this can come in handy if you're creative.
}
//--Unique Collision cursors------------------
//If you messed with the default Emily ghost at all, you may have noticed that when your cursor was over her chest, it changed to a sort of gripping hand instead of a pointer finger. "How do I do that?" you may wonder. Setting up sakura.cursor is how!
//sakura.cursor
//{
//mouseup0,Head,system:hand
//mousedown0,Head,system:finger
//mouseup1,Face,system:hand
//mousedown1,Face,system:grip
//}
//What this does is change the mouse cursor. You can see it's split into mouseup and mousedown, and it uses the names you gave your Collisions up there. So when the mouse is hovering over Girl's head, it uses the system cursor that looks like a hand. When you click and hold, it looks like a finger. You can uncomment these lines to see for yourself. Likewise, when you hover your mouse over Girl's face, it looks like a hand, and when you click down, it looks like a gripping hand. You can keep adding unique cursors for all your collisions by sequentially numbering them, like mouseup/down2, mouseup/down3, and so on.
//The system cursors you can use for this are "arrow", "cross", "no", "hand", "grip", "finger", "wait", "text", "move", and "help". You can probably guess at what they look like. Feel free to use whatever cursor you think would best match your collision.
//To set this up for the secondary character, just change sakura to kero, as usual.
//--Tooltips------------------
//Maybe you'd like a tooltip to pop up when your user is hovering over a hitbox on your ghost. It works much the same as above!
//sakura.tooltips
//{
//Head,This is Girl's head.
//Face,This is Girl's face.
//}
//Basically put the name of your collision first, then what you want the tooltip to say. Uncomment this function and hover over Girl's hotspots and you can see how it works. It may be handy for warning your users about punching your ghost or something, or for silly reasons, I dunno. It's up to you!
//Like above, replace sakura with kero for the secondary character.
//--Surface.alias------------------
//There is another function along the same lines of surface.append and it's surface.alias. What it does is assign a range of numbers to a single number or word that can be called using \s[]. So here's an example.
//sakura.surface.alias
//{
//6666,[1229,1230,1231,1235]
//}
//What this means is that I could then go \s[6666] in dialogue and it would call any of these four Surfaces in the brackets. You can do words as well, like creepy,[1229,1230,1231,1235], and then you could call it with \s[creepy]. This may sound like a convenient shortcut to using words instead of numbers for your ghost's expressions, but I'd probably stick with numbers, really. It just feels like it'd backfire on you eventually.
//You can do the same thing with the side character by using kero instead of sakura.
//kero.surface.alias
//{
//6667,[1228,1232,1233]
//6668,[1228,1232,1233,1234]
//}
//And as you can see, you can have multiple surface aliases set up at any point. In this example, kero has both 6667 and 6668 defined as a range of Surfaces. So \s[6667] would call one of those three Surfaces, and \s[6668] would call one of those four Surfaces.
//---
//Now, if you don't think this is enough Surfaces and want to add more, all you have to do is copy and paste a chunk of Surface code, give it a new number, and then do whatever you want with it. You can define Surfaces all the way up to 999 without running into problems, so go crazy with them if you want! Some of my ghosts have a ridiculous amount of Surfaces because I have no self-control.
//Of course, to add new poses, you need to draw new frames for those poses. And I say again, make sure all your frames for a character are the same size if you can! It's so much easier to just put 0,0 than find specific coordinates. Unless you've run into the replace problem with mouths, in which case there's not much you can do about that.
//Once you add a new pose, save your surfaces.txt file and reload your shell using the Development Panel Reload option, or by just reloading your ghost entirely via Utilities - Reload Ghost. You can use Surface Test in the Development Panel to check your new Surface and see if it works and looks right! I always recommend testing your Surfaces, and it's usually pretty easy and simple. If it doesn't look right, tweak surfaces.txt, save, and try again.
//The length of this file is limited only by your imagination!
//*********************More on SERIKO coding*******************************
//I mentioned up above talking about some SERIKO functions for advanced users, so here I'll explain how some of them work. You can read about these on the SERIKO page on the walkthrough as well with (presumably) easier formatting on the eyes lol.
//--Random things
//You can have random things appear for a little while and then disappear using the random interval. This could be anything from a thought to an expression to a bird to a movement or whatever.
//6interval,random,60 //here the interval is set to random with a value of 60, meaning every 60ms there's a chance this will randomly happen.
//6pattern0,0404,0,overlayfast,0,0
//6pattern1,-1,5000,overlayfast,0,0
//This is much the same as the lines above. You'd replace 0404 with whatever image you'd be using. 5000 is the delay on the frame, so this stays on the screen for about 5 seconds. You can replace that value with whatever you want to change the timing, and change the number after random at the top to adjust how often it might occur.
//Note that at the end the image file number it calls is -1. -1 returns to the base default pose, so you'll want to end most unique or new animations with this to bring your ghost back to normal.
//--Other Animation Options
//There are a few other options you can have for interval animations. We've already seen bind, talk, random, and never so far. Some other ones are always, sometimes, runonce, and rarely. Their names are fairly self-explanatory I'd imagine, but I'll do some really quick examples from my other surfaces.txt files here.
//20interval,always
//20pattern0,182,0,overlay,0,0
//20pattern1,183,0,overlay,0,0
//20pattern2,184,0,overlay,0,0
//This would always run this animation. always intervals only work for animations with more than one frame! If you want to have a single frame that's always present, you'll want to use runonce instead. Otherwise you'll get some annoying shell errors.
//6interval,sometimes
//6pattern0,604,13,replace,0,96
//6pattern1,606,14,replace,0,96
//6pattern2,605,14,replace,0,96
//6pattern3,-1,10,overlay,0,0
//This would run this animation sometimes. Again, note how it ends with on a -1 frame.
//0interval,runonce
//0pattern0,41,13,replace
//0pattern1,42,19,replace
//This would run the animation once and stop on the last frame. You can use this with a single frame to have one image stay in place. This is handy for layering, like if you want to have a head or an arm over other parts of your body. You can set the higher interval for the arm to runonce, then it will stick.
//20interval,rarely
//20pattern0,286,0,base
//20pattern0,288,0,replace,0,0
//20pattern1,287,15,replace,0,0
//20pattern2,-1,25,overlay,0,0
//This would run the animation rarely.
//So you see, fairly straightforward. You can use these animation options to set up other things for your Surface to do. Since I mentioned furries above, you could, say... have a sometimes animation for a tail waving or something. Or a rarely animation for someone coughing, or runonce for someone falling over.
//Interval Stacking
//This is definitely for advanced users, so if you're not interested in the HARD STUFF, you can move on, haha.
//Basically, what you can do with a surface is add a bunch of intervals that are never called (thus the never tag). Then when you are calling the pose with \s, you can add an \i tag with the right number to bring up that interval. What is the actual use of this? This is a perfect way to do eyebrows, for one. You can set up a variety of eyebrows for the same Surface under different intervals, set them all to never, and then just call them in the one pose with \s[0]\i[8] or whatever i number you need. You can also use multiple \i tags to call multiple intervals at the same time to layer effects, like \s[0]\i[5]\i[8]\i[22]. I used this in Hunter and Smoker to layer things like Hunter's ears, her eyes, and her eyebrows to create a ton of different expressions within the same pose.
//I am absolutely positive I will use this method with all my future ghosts since it saves SO MUCH SPACE because I make like a BILLION poses for everyone, but whether or not anyone else ever will, I have no idea. But that's basically how it works.
//This example bit of code here is an eyebrow frame set to never.
//8interval,never
//8pattern0,224,0,overlayfast,0,0
//--Stopping Intervals
//This is a huge part of interval stacking above, although you can use it for other things.
//So, I mentioned Hunter's ears. I wanted them to be able to move around with her mood, and I finally figured out a way to do it - I made her base element with no ears, and then set her default ears to "runonce". The problem was, how do I change the ear position if her default ears are always on? Through the use of a SERIKO function called stop, that's how. Basically, I would stop the always default ear interval and start the new one. I'm just going to straight up copy a snip of the code from there into here to look at. See how interval 21 stops 20. You can do the same thing with start instead of stop to start an interval - this can come in handy for stopping and starting different talk animations if you have smiling/serious talk frames in one pose.
//Ears back
//20interval,runonce
//20pattern0,182,0,overlay,0,0
//Ears neutral
//21interval,never
//21pattern0,0,0,stop,20 //the interval it's stopping as at the end, in this case it stops interval 20
//21pattern0,172,0,overlay,0,0
//There are a lot of ways you can use this. For example, in Hunter's battle-ready animation, she'd always be bouncing on her heels normally, but I put in a stop check for her talk interval so she'd stay still and her mouth frames wouldn't get all screwy. Perhaps others can think of other creative ways to use this feature.
//--Layering
//You can think of the intervals in a Surface as layers in a PSD file. The top layers will go on top of the other layers. You can use this to layer certain animations underneath others. If you layer a blink animation below... I dunno, a hair-blowing animation or a sweatdrop or something, the blink should go beneath the other layer and they shouldn't conflict. Hopefully. It's tricky to set-up, so you may need to go through some trial and error.
//As such you should always be mindful of the placement of your layers. Hair layers should go above eye layers, for example.
//This does NOT apply to replace, which does not care about layering and will pre-empt almost all other SERIKO functions like Always or Random. Which sucks. Be careful when using Replace.
//--Base
//Base is a newer interval setting I only figured out while doing the Gordon FLELE. Basically, what base does is change the base of your pose from one file to another, which has some limited application, but can come in handy. The best example is from Gordon - He was standing at a three-quarter view with one arm in front of him and one arm behind him. Moving the arm in front of him was easy, it just required layering that arm above all the others. Moving the arm BEHIND him was harder, because his body was the base frame and you can't move things behind that. To get it to work, I would use base to temporarily change the base to his back arm, then change it back after it had moved. To snag a bit of code from his surfaces.txt file...
//Left arm half out
//21interval,never
//21pattern4,0504,0,base,0,0
//21pattern5,-1,800,base,0,0
//Always make sure to set the base back to the original image with -1 at the end. It might be easier to just have the body in a higher layer than your back arms though... but that's just the application I found for this. It might be just what you need for whatever you're doing.
//--Replace
//Alright, here we go. Replace basically does what it says - it replaces the image (or part of the image) with another image. Have you noticed so far that the last two numbers of all the pattern lines have almost always been 0,0? Go ahead, scroll up again and look. Almost always 0,0. That's because if all your images are the same size (and they definitely should be, this is the very reason why you should be doing that), they will always line up properly with each other, and you'll almost never have to put anything but 0,0.
//Unless you're using replace.
//Actually that's not entirely true. If you're replacing the ENTIRE image with a new one, then you can leave replace as 0,0. That can be handy for full body animations like... someone getting hit, for example. You could have four unique frames of them falling to the ground, and you'd use replace for each of those frames to change the entire image each time.
//However, most of the time (at least in my experience) you're going to be using replace for smaller things, primarily mouths in profile view I'm going to guess. And if you're going to be doing that, you're going to need to find yourself some coordinates. Do you remember setting up collisions up there? This is much the same thing. First, let's pull up a bit of replace code. I'll use one from Hunter and Smoker as an example. Here's one of Smoker's talking animations where she's in profile. You can see the frames for this on the surfaces.txt page of the walkthrough.
//talking
//1interval,talk,4
//1pattern0,0,0,alternativestart,[2.3.4]
//2interval,never
//2pattern0,708,13,replace,0,72
//2pattern1,-1,10,overlay,0,0
//3interval,never
//3pattern0,709,14,replace,0,72
//3pattern1,-1,10,overlay,0,0
//4interval,never
//4pattern0,709,14,replace,0,72
//4pattern1,708,14,replace,0,72
//4pattern2,-1,10,overlay,0,0
//You'll see at first that it's very similar to the talk function we set up above. However, there is a distinct difference. Overlay has been replaced with replace, and the final number is different. Those two numbers are the x,y coordinates for that image, and tell it where it needs to replace.
//In the interest of making this as simple as possible, and avoiding a problem I ran into when I cropped things too tightly, what you're going to do is go into your image with your profile talk frames. You are going to draw a rectangle that VERTICALLY just about covers your mouth frames, and HORIZONTALLY spans your entire image. Then you'll crop your image down to that rectangle. What this will create is an image that is the same WIDTH as your base image, but a different HEIGHT. Save those images as your mouth frames.
//Since your new mouth frame is the same width as your base image, you can leave it as 0. How do you find the second number then? The second number is the Y value, and it's the top of your rectangle. Undo your crop so your image is its base size again, hold your cursor at the top of your rectangle, and look at the coordinates in Photoshop info or MSPaint or whatever. Write down that Y number, and put it in here. Test your shell and see if the mouth frames line up properly. If they're a pixel too high or low, adjust the number until they line up right.
//You'll notice the last line in each interval, the one with -1 and with the remaining overlay tag, is still set to 0,0. That's because that's the animation returning to normal. You don't have to mess with that line. Just replace the 708 709 whatever numbers in the replace lines with what you're using.
//"But Zar!" you exclaim. "If I go all the way horizontally, then I run into my eye frames, and the blinking animation doesn't look right because replace doesn't care about me!" in which cause ouch, because that sucks and means you're going to have to get a little more into this.
//Alright, this time, draw your same rectangle over your mouth frames. THIS TIME, however, don't stretch it all the way across. Draw it as close to your mouth frames as you can without filling up the entire rectangle. Specifically, leave at least ONE PIXEL blank in the top left corner if you possibly can. If you don't that pixel will flicker during the animation and if you're like me it will slowly drive you insane.
//Once you've drawn your rectangle, take your cursor and find the coordinates again. This time, look for the y coordinate at the top of the rectangle, and x at the left side of it if I remember right. Write them down, come back over here, and fill out the last two numbers of each line as appropriate. Go back to your image, crop it down to your rectangle, and save your mouth frames. Test. Adjust. Repeat until it looks right.
//You can see now why I recommended keeping your mouth frames inside your silhouette as much as you can. If you are running into the blink problem, you can try putting your blink interval above your talk interval. So if your talk intervals are 1-4 for example, you could put blink as 5interval instead. That could fix your problem! Maybe. Surfaces.txt can be annoying.
//As a side note, replace will go over bound items like dress-up items, so keep this in mind if you're making clothes for your ghost.
//Replace will also take precedent over most other animation methods like Random or Always. For example, if you set up something to always play in the background, like... let's say, a fire was behind your character, and at some point you wanted to use replace on the main body of your character to say, make them move their arm. Replace will then shut off the Always interval and do its own thing, no matter how you layer it. It works okay with Overlay though. Basically, you'll need to mess with it a bit yourself to see when it works and when it doesn't.
//--Move
//The last of the animation functions and one that's really fairly simple. Move just moves the frame around your screen. This is handy when you want to move your character but don't want to draw a ton of frames for it.
//Here's an example from my Hunter and Smoker file. This is when Hunter would get hit in battle. She'd slide backwards a little bit.
//sliding back slightly
//0interval,runonce
//0pattern0,0,15,move,1,0
//0pattern1,0,5,move,2,0
//0pattern2,0,7,move,3,0
//0pattern3,0,10,move,4,0
//0pattern2,0,15,move,5,0
//As you saw above with the replace option, the last two numbers of any line are the x and y values. In this case, Hunter is sliding horizontally across the ground, so I changed the first number, the x. Over the course of five frames, she slides about five pixels back. You can adjust the timing by changing the number before move in each of them.
//You can use this to move your character around wherever you want. Horizontally, vertically, both at the same time, and at any speed you want. If you just set it to one frame with no delay, they'll just teleport over there.
//However, your character will stay where they moved unless you move them back, they go into another pose, or OnSurfaceRestore moves them back I think (see aitalk.dic). So you may want to set up some reverse move frames to bring them back to 0,0.
//One really handy use for move is making things bob up and down (like a thought bubble) without having to draw new frames for it.
//***********************************************************************

View File

@ -0,0 +1,47 @@
//This tiny file clears out the pieces of a surface in the Surface Test option in the Developer's panel. All the numbers that have an asterisk near them. Basically, eye or mouth frames that aren't part of a surface as defined in surfaces.txt. It just makes it easier for you to find a defined surface in Surface Test. You can also use it to assign surfaces nicknames in the surface test!
//You don't need to touch this part.
charset,UTF-8
version,1
option,DisableNoDefineSurfaces
//I talk about this a little more on the site itself, but I'll go over it here too. Here's an example of surfacetable.txt set up with unique groups.
//group,G
//{
//scope,0
//0,Default
//1,IdleLeft
//2,IdleRight
//3,Phonecheck
//5,Left
//6,Right
//7,Forward
//8,Wave
//9,Crossed
//10,Null
//30,Armhold
//31,FaceForward
//}
//First, we define a group. Then we give that group a name, in this case, G. You generally have VERY little space to read with the Surface Test, so you'll want these group names to be pretty short. But you can adjust and change it as you try this out.
//Once we defined the group, we open up some brackets to put in our values. That first line defines whether the group applies to the main character of the ghost or the sidekick. It's not a super meaningful distinction, in my experience, but there's no harm in including it. 0 means the surfaces are associated with the main character, and 1 is associated with the side character, as usual.
//After that, we have the surface number, and a nickname. In this case, Surface0, and I gave it the nickname "default". So when you load up Surface Test, you'll see that 0 will have (G/Default) next to it. After that, all you have to do is add all the surface numbers you have defined, then give them whatever name will be most useful to you. Boom!
//You can define multiple groups with different names if that helps you keep things straight. You can have a group for Main poses, a group for Special poses, a group for Lying Down poses... how you use this to keep your files organized is up to you. You will see as you begin giving surfaces nicknames and reloading and checking the Surface Test whether or not your names are too short or too long or not descriptive enough or what have you. You'll just have to figure out your own schema.
//You can also use this to disable surfaces you don't want to appear in the surfacetable.txt list. Now, disabling a group of surfaces is pretty simple. You don't have to add a disabled group if you don't need one. But if you do, here's how.
//group,__disabled
//{
//9999,__parts
//}
//In this case, we made a group called __disabled. Any surfaces you don't want to appear in Surface Test, you can put into the __disabled group. I don't think nicknames are really necessary for them, I just called this one __parts for no reason, but it probably doesn't hurt.
//Once you've set up this file, you're all set! You should see the changes in the surface test immediately once you reload your shell.

BIN
shell/master/thumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
thumbnail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

81
updates.txt Normal file
View File

@ -0,0 +1,81 @@
file,ghost/master/aitalk.dic3abec1e404417fd317ceb73acf33ffe0size=38522
file,ghost/master/anchor.dic56bbd05dec8002e08c50f9074deda54asize=4922
file,ghost/master/aya5.dll7737614f08f642a0261a4f81917ed77asize=198144
file,ghost/master/aya5.txt2ed462a7033d35c6d9397dd1803eaa28size=1267
file,ghost/master/bootend.dic509254cbce358ad53d2d34e7cd0d961bsize=38990
file,ghost/master/commu.dice8aecf682cfdeb1065aadc102eb669ebsize=1545
file,ghost/master/descript.txt03b165949bdd3133350f403207749f33size=2451
file,ghost/master/etc.dic5480ebfe4f9c6da4575c1ea0c4646c9asize=34388
file,ghost/master/gomi.dll51fe9597398db01e684a0f9d52c63242size=13312
file,ghost/master/gt_template.ico9b275939dbf11bd2ec5f4ef3e00fa06asize=1148
file,ghost/master/mciaudior.dllb1082bccd2aac2017f7936baf2d967b3size=29696
file,ghost/master/menu.dic8eff4ef2f64423ffcb2a4113acf532desize=32752
file,ghost/master/mouse.dica5ed9de92b59846712781ea54fb1ee45size=12195
file,ghost/master/nameteach.dica144a305b1f3c6a9208e18d7e1dcc21csize=8619
file,ghost/master/saori_cpuid.dlld13370aee8e579fe2517d789dba7c45esize=225280
file,ghost/master/shiori3.dic58b4b947e0aa6741018aa8861f862ebfsize=34827
file,ghost/master/string.dic4426fac5717e78dd605ba40f69d5f84dsize=9436
file,ghost/master/word.dic1921585b5cfcf3279184b544c4164a37size=6063
file,install.txt8a3f799789ce72a9684605ffd5cc11a4size=680
file,readme.txtcb336bd90cc70f2f21a1b257218b0cc6size=395
file,shell/default_shell/descript.txt99c56195a55846037db35aa6c89fd895size=5286
file,shell/default_shell/menu_background.pngee82ad72761d4837c3334f61ade1fbc5size=2775
file,shell/default_shell/menu_foreground.pnge0d10ee3534c5391c8e97a0897dc77a9size=2775
file,shell/default_shell/menu_sidebar.png7c405dcca0c16de439fcf21b4efecbb7size=7225
file,shell/default_shell/read me.txt855c908f8863b8a773dbb37ea1cf451asize=1838
file,shell/default_shell/surface0.pna8db2e7cd6580c90459c3a5d215b15d04size=7202
file,shell/default_shell/surface0.png18d3dc83a1ee78c27ab4095e63cf362dsize=17629
file,shell/default_shell/surface10.pnacae60b6a3665fc040f41aa0112b03891size=3537
file,shell/default_shell/surface10.pngf1347c38e4e02e5fa2ab0bc1d325a7c2size=4187
file,shell/default_shell/surface1000.png43fcc1badac8488c409587e3c6c7ce18size=4130
file,shell/default_shell/surface1001.png4537e386ca077ae4afb238ce2e501c42size=4106
file,shell/default_shell/surface1002.png51cf9c6937efc7b331b554984ef1e841size=3956
file,shell/default_shell/surface1100.png293959a52fd2c725c4d51b5d611d6e2csize=2575
file,shell/default_shell/surface1101.png024329002f6cb026d1cffa9dabdf2ec6size=2677
file,shell/default_shell/surface1102.png19f8aee616bae415fa8527953d1aeb77size=2733
file,shell/default_shell/surface1501.pna465f5936870d1b1fb53b9179a95e99a6size=6891
file,shell/default_shell/surface1501.pnge07d88f63fdbb5ca6579a852ff982d75size=16730
file,shell/default_shell/surface1502.pnab57df3575edfb8bbfcf8aab0d76fb8f4size=8647
file,shell/default_shell/surface1502.png63390a888531184ed6ec4d743b8e79acsize=21790
file,shell/default_shell/surface1503.pnaf7665607c0c65b1536d697dd1e1e4e32size=7496
file,shell/default_shell/surface1503.pngd800add782f77fdd6cfc4cbc11b1113asize=18466
file,shell/default_shell/surface1504.pna81aefe387a4269a89aefdb707a8f9091size=6044
file,shell/default_shell/surface1504.png9928fe1e9bc8dfb13cbb7fbba59bbde0size=15691
file,shell/default_shell/surface1505.pna9bd798e7811d28eeaeb685bedea7df04size=7096
file,shell/default_shell/surface1505.png586e2f1f55823c5692bfdae10d47c348size=17345
file,shell/default_shell/surface1506.pnadf0d82506894b675fe3e673f906a609bsize=7295
file,shell/default_shell/surface1506.png490a29b13be538e711f5a242e414f8fdsize=16935
file,shell/default_shell/surface1507.pnaa6c7828f11677a27010614bf8ed56b09size=7845
file,shell/default_shell/surface1507.pngdd0e79c5f854dd8513a2c24904c7ac7dsize=19573
file,shell/default_shell/surface1508.pna1b854563a7cfee7feac56410e288c923size=6829
file,shell/default_shell/surface1508.png68e1f524eae0bb8bb72b6b094fb8602esize=16708
file,shell/default_shell/surface1509.pnaf7d0b3e22d36a112e347b1111fb4e1d4size=6804
file,shell/default_shell/surface1509.pngbabc5ad41e504c0f308ba7957637b3cbsize=17108
file,shell/default_shell/surface2000.pna33345d7c3ba8b23323cda5bb9aa61f94size=2893
file,shell/default_shell/surface2000.pnge09f8d0641d29b5c469158b1e27b9d60size=3175
file,shell/default_shell/surface2001.pna33345d7c3ba8b23323cda5bb9aa61f94size=2893
file,shell/default_shell/surface2001.pngdcda5475d214354c66d6bedef6f03148size=3192
file,shell/default_shell/surface2002.pna33345d7c3ba8b23323cda5bb9aa61f94size=2893
file,shell/default_shell/surface2002.png7b513b7089b727827c4f223f5de1032csize=3179
file,shell/default_shell/surface2501.pna3e4f1a343d5d63777c3577e3ff69ac30size=3518
file,shell/default_shell/surface2501.pngffc302dac41904efb061edfc7a2bad0esize=4731
file,shell/default_shell/surface2502.pna728dc3f0c5c142f0a082c82ca5031380size=3835
file,shell/default_shell/surface2502.pnge328b8e90c7995383b08fe943092e1b8size=5085
file,shell/default_shell/surface2503.pna134e56b7e7696258163368dee84bd77dsize=3628
file,shell/default_shell/surface2503.png6b4daf0ba84052c4966ff9ec0ddac30csize=4710
file,shell/default_shell/surface2504.pnafd64691eabd34532e617e4bfd21aab37size=3579
file,shell/default_shell/surface2504.png38d15a5612a60bcd92b373e585bd7ed6size=4381
file,shell/default_shell/surface2505.pnad5ff2272170107c66fddae559604601fsize=3929
file,shell/default_shell/surface2505.png2b197381b9e38fba86554bd498df3580size=4782
file,shell/default_shell/surface2506.pna04096f0e9d47a65c471104ba0c37b8e7size=3612
file,shell/default_shell/surface2506.png562b0262cb9620e47bda23f84bd798b4size=4252
file,shell/default_shell/surface2507.pna3d6cc833dcd91f6f2c1602f2105b158asize=3707
file,shell/default_shell/surface2507.pngd95a99c2f4f4d1b6af442aa809ded3bfsize=4527
file,shell/default_shell/surface2508.pna84c1cf5bd2df84242c51b0f96afc0201size=3458
file,shell/default_shell/surface2508.png6e94830f867e783f4e26bba4bff9145bsize=4324
file,shell/default_shell/surface2509.pna04096f0e9d47a65c471104ba0c37b8e7size=3612
file,shell/default_shell/surface2509.pnge6e43f21dafd057ab890c67e1346df80size=4262
file,shell/default_shell/surfaces.txtf9a43fae269c315270cefe08da7a4005size=42945
file,shell/default_shell/thumbnail.png9993d1bdfb6f26b9886d13f69d0a22b8size=24167
file,Template Readme - READ ME FIRST!.txtb7af188866ba330858f3a6bdf8b56edbsize=2921
file,thumbnail.pngaaac9f3a86600c8e3f01dfb3e3986aa2size=24459