Merge branch 'master' into fishing
Conflicts: stardew-access/CustomSoundEffects.csmaster
commit
5fa9fd5eca
|
@ -0,0 +1,504 @@
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. 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 not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the 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
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "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
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY 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
|
||||||
|
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Libraries
|
||||||
|
|
||||||
|
If you develop a new library, and you want it to be of the greatest
|
||||||
|
possible use to the public, we recommend making it free software that
|
||||||
|
everyone can redistribute and change. You can do so by permitting
|
||||||
|
redistribution under these terms (or, alternatively, under the terms of the
|
||||||
|
ordinary General Public License).
|
||||||
|
|
||||||
|
To apply these terms, attach the following notices to the library. It is
|
||||||
|
safest to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least the
|
||||||
|
"copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the library's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library 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
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||||
|
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1990
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
That's all there is to it!
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
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.
|
|
@ -0,0 +1,32 @@
|
||||||
|
PIXABAY LICENSE CERTIFICATE
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
This document confirms the download of an audio file pursuant to the Pixabay License as defined in the Pixabay Terms of Service available at https://https://pixabay.com/service/terms/
|
||||||
|
|
||||||
|
Licensor's Username:
|
||||||
|
https://pixabay.com/users/pixabay-1/
|
||||||
|
|
||||||
|
Licensee:
|
||||||
|
TheOneWhoKnocks
|
||||||
|
|
||||||
|
Audio File Title:
|
||||||
|
Invalid Selection
|
||||||
|
|
||||||
|
Audio File URL:
|
||||||
|
https://pixabay.com/sound-effects/invalid-selection-39351/
|
||||||
|
|
||||||
|
Audio File ID:
|
||||||
|
39351
|
||||||
|
|
||||||
|
Date of download:
|
||||||
|
2023-02-20 05:52:26 UTC
|
||||||
|
|
||||||
|
Pixabay GmbH c/o Lacore Rechtsanwälte LLP
|
||||||
|
Berliner Freiheit 2, 10785 Berlin, Germany
|
||||||
|
|
||||||
|
Pixabay is a user-contributed stock content website. The above-named Licensor is responsible for this audio file. Pixabay monitors uploaded audio files only to a reasonable extent. Pixabay cannot be held responsible for the acts or omissions of its users and does not represent or warrant that any required third-party consents or licenses have been obtained.
|
||||||
|
|
||||||
|
For any queries related to this document please contact Pixabay via info@pixabay.com.
|
||||||
|
|
||||||
|
|
||||||
|
==== THIS IS NOT A TAX RECEIPT OR INVOICE ====
|
|
@ -1,4 +1,5 @@
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using stardew_access.Features;
|
||||||
using stardew_access.Patches;
|
using stardew_access.Patches;
|
||||||
using StardewModdingAPI;
|
using StardewModdingAPI;
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
|
@ -327,18 +328,18 @@ namespace stardew_access
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildingNAnimalMenuPatches.marked[index] = new Vector2((int)Game1.player.getTileX(), (int)Game1.player.getTileY());
|
BuildingOperations.marked[index] = new Vector2((int)Game1.player.getTileX(), (int)Game1.player.getTileY());
|
||||||
MainClass.InfoLog($"Location {(int)Game1.player.getTileX()}x {(int)Game1.player.getTileY()}y added at {index} index.");
|
MainClass.InfoLog($"Location {(int)Game1.player.getTileX()}x {(int)Game1.player.getTileY()}y added at {index} index.");
|
||||||
});
|
});
|
||||||
|
|
||||||
helper.ConsoleCommands.Add("marklist", "List all marked positions.", (string commmand, string[] args) =>
|
helper.ConsoleCommands.Add("marklist", "List all marked positions.", (string commmand, string[] args) =>
|
||||||
{
|
{
|
||||||
string toPrint = "";
|
string toPrint = "";
|
||||||
for (int i = 0; i < BuildingNAnimalMenuPatches.marked.Length; i++)
|
for (int i = 0; i < BuildingOperations.marked.Length; i++)
|
||||||
{
|
{
|
||||||
if (BuildingNAnimalMenuPatches.marked[i] != Vector2.Zero)
|
if (BuildingOperations.marked[i] != Vector2.Zero)
|
||||||
{
|
{
|
||||||
toPrint = $"{toPrint}\n Index {i}: {BuildingNAnimalMenuPatches.marked[i].X}x {BuildingNAnimalMenuPatches.marked[i].Y}y";
|
toPrint = $"{toPrint}\n Index {i}: {BuildingOperations.marked[i].X}x {BuildingOperations.marked[i].Y}y";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +356,7 @@ namespace stardew_access
|
||||||
|
|
||||||
helper.ConsoleCommands.Add("buildsel", "Select the building index which you want to upgrade/demolish/paint", (string commmand, string[] args) =>
|
helper.ConsoleCommands.Add("buildsel", "Select the building index which you want to upgrade/demolish/paint", (string commmand, string[] args) =>
|
||||||
{
|
{
|
||||||
if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu && Game1.activeClickableMenu is not AnimalQueryMenu) || !BuildingNAnimalMenuPatches.isOnFarm)
|
if ((Game1.activeClickableMenu is not CarpenterMenu && Game1.activeClickableMenu is not PurchaseAnimalsMenu && Game1.activeClickableMenu is not AnimalQueryMenu) || !CarpenterMenuPatch.isOnFarm)
|
||||||
{
|
{
|
||||||
MainClass.InfoLog($"Cannot select building.");
|
MainClass.InfoLog($"Cannot select building.");
|
||||||
return;
|
return;
|
||||||
|
@ -380,12 +381,12 @@ namespace stardew_access
|
||||||
string? positionIndexInString = args.ElementAtOrDefault(1);
|
string? positionIndexInString = args.ElementAtOrDefault(1);
|
||||||
int positionIndex = 0;
|
int positionIndex = 0;
|
||||||
|
|
||||||
if (BuildingNAnimalMenuPatches.isMoving)
|
if (CarpenterMenuPatch.isMoving)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (BuildingNAnimalMenuPatches.isConstructing || BuildingNAnimalMenuPatches.isMoving)
|
if (CarpenterMenuPatch.isConstructing || CarpenterMenuPatch.isMoving)
|
||||||
{
|
{
|
||||||
if (BuildingNAnimalMenuPatches.availableBuildings[index] == null)
|
if (BuildingOperations.availableBuildings[index] == null)
|
||||||
{
|
{
|
||||||
MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
|
MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
|
||||||
return;
|
return;
|
||||||
|
@ -406,9 +407,9 @@ namespace stardew_access
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (BuildingNAnimalMenuPatches.isConstructing && !BuildingNAnimalMenuPatches.isUpgrading)
|
else if (CarpenterMenuPatch.isConstructing && !CarpenterMenuPatch.isUpgrading)
|
||||||
{
|
{
|
||||||
if (BuildingNAnimalMenuPatches.marked[index] == Vector2.Zero)
|
if (BuildingOperations.marked[index] == Vector2.Zero)
|
||||||
{
|
{
|
||||||
MainClass.InfoLog($"No marked position found at {index} index.");
|
MainClass.InfoLog($"No marked position found at {index} index.");
|
||||||
return;
|
return;
|
||||||
|
@ -416,7 +417,7 @@ namespace stardew_access
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (BuildingNAnimalMenuPatches.availableBuildings[index] == null)
|
if (BuildingOperations.availableBuildings[index] == null)
|
||||||
{
|
{
|
||||||
MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
|
MainClass.InfoLog($"No building found with index {index}. Use buildlist.");
|
||||||
return;
|
return;
|
||||||
|
@ -427,19 +428,19 @@ namespace stardew_access
|
||||||
|
|
||||||
if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
||||||
{
|
{
|
||||||
BuildingNAnimalMenuPatches.PurchaseAnimal(BuildingNAnimalMenuPatches.availableBuildings[index]);
|
BuildingOperations.PurchaseAnimal(BuildingOperations.availableBuildings[index]);
|
||||||
}
|
}
|
||||||
else if (Game1.activeClickableMenu is AnimalQueryMenu)
|
else if (Game1.activeClickableMenu is AnimalQueryMenu)
|
||||||
{
|
{
|
||||||
BuildingNAnimalMenuPatches.MoveAnimal(BuildingNAnimalMenuPatches.availableBuildings[index]);
|
BuildingOperations.MoveAnimal(BuildingOperations.availableBuildings[index]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (BuildingNAnimalMenuPatches.isConstructing && !BuildingNAnimalMenuPatches.isUpgrading) { response = BuildingNAnimalMenuPatches.Contstruct(BuildingNAnimalMenuPatches.marked[index]); }
|
if (CarpenterMenuPatch.isConstructing && !CarpenterMenuPatch.isUpgrading) { response = BuildingOperations.Contstruct(BuildingOperations.marked[index]); }
|
||||||
else if (BuildingNAnimalMenuPatches.isMoving) { response = BuildingNAnimalMenuPatches.Move(BuildingNAnimalMenuPatches.availableBuildings[index], BuildingNAnimalMenuPatches.marked[positionIndex]); }
|
else if (CarpenterMenuPatch.isMoving) { response = BuildingOperations.Move(BuildingOperations.availableBuildings[index], BuildingOperations.marked[positionIndex]); }
|
||||||
else if (BuildingNAnimalMenuPatches.isDemolishing) { response = BuildingNAnimalMenuPatches.Demolish(BuildingNAnimalMenuPatches.availableBuildings[index]); }
|
else if (CarpenterMenuPatch.isDemolishing) { response = BuildingOperations.Demolish(BuildingOperations.availableBuildings[index]); }
|
||||||
else if (BuildingNAnimalMenuPatches.isUpgrading) { response = BuildingNAnimalMenuPatches.Upgrade(BuildingNAnimalMenuPatches.availableBuildings[index]); }
|
else if (CarpenterMenuPatch.isUpgrading) { response = BuildingOperations.Upgrade(BuildingOperations.availableBuildings[index]); }
|
||||||
else if (BuildingNAnimalMenuPatches.isPainting) { response = BuildingNAnimalMenuPatches.Paint(BuildingNAnimalMenuPatches.availableBuildings[index]); }
|
else if (CarpenterMenuPatch.isPainting) { response = BuildingOperations.Paint(BuildingOperations.availableBuildings[index]); }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response != null)
|
if (response != null)
|
||||||
|
@ -517,7 +518,7 @@ namespace stardew_access
|
||||||
string? name = buildings[i].nameOfIndoorsWithoutUnique;
|
string? name = buildings[i].nameOfIndoorsWithoutUnique;
|
||||||
name = (name == "null") ? buildings[i].buildingType.Value : name;
|
name = (name == "null") ? buildings[i].buildingType.Value : name;
|
||||||
|
|
||||||
BuildingNAnimalMenuPatches.availableBuildings[buildingIndex] = buildings[i];
|
BuildingOperations.availableBuildings[buildingIndex] = buildings[i];
|
||||||
toPrint = $"{toPrint}\nIndex {buildingIndex}: {name}: At {buildings[i].tileX}x and {buildings[i].tileY}y";
|
toPrint = $"{toPrint}\nIndex {buildingIndex}: {name}: At {buildings[i].tileX}x and {buildings[i].tileY}y";
|
||||||
++buildingIndex;
|
++buildingIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ namespace stardew_access
|
||||||
|
|
||||||
soundEffects.Add("drop_item", TYPE.Sound);
|
soundEffects.Add("drop_item", TYPE.Sound);
|
||||||
soundEffects.Add("colliding", TYPE.Sound);
|
soundEffects.Add("colliding", TYPE.Sound);
|
||||||
|
soundEffects.Add("invalid-selection", TYPE.Sound);
|
||||||
|
|
||||||
soundEffects.Add("bobber_target_up", TYPE.Sound);
|
soundEffects.Add("bobber_target_up", TYPE.Sound);
|
||||||
soundEffects.Add("bobber_target_down", TYPE.Sound);
|
soundEffects.Add("bobber_target_down", TYPE.Sound);
|
||||||
|
|
|
@ -0,0 +1,366 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using stardew_access.Patches;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Buildings;
|
||||||
|
using StardewValley.Locations;
|
||||||
|
using StardewValley.Objects;
|
||||||
|
|
||||||
|
namespace stardew_access.Features
|
||||||
|
{
|
||||||
|
internal class BuildingOperations
|
||||||
|
{
|
||||||
|
internal static Building?[] availableBuildings = new Building[100];
|
||||||
|
internal static Vector2[] marked = new Vector2[10];
|
||||||
|
|
||||||
|
public static string? Demolish(Building? toDemolish)
|
||||||
|
{
|
||||||
|
if (toDemolish == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
string? response = null;
|
||||||
|
// This code is taken from the game's code (CarpenterMenu.cs::654)
|
||||||
|
Farm farm = (Farm)Game1.getLocationFromName("Farm");
|
||||||
|
Action buildingLockFailed = delegate
|
||||||
|
{
|
||||||
|
if (CarpenterMenuPatch.isDemolishing)
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_LockFailed");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Action continueDemolish = delegate
|
||||||
|
{
|
||||||
|
if (CarpenterMenuPatch.isDemolishing && toDemolish != null && farm.buildings.Contains(toDemolish))
|
||||||
|
{
|
||||||
|
if ((int)toDemolish.daysOfConstructionLeft.Value > 0 || (int)toDemolish.daysUntilUpgrade.Value > 0)
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_DuringConstruction");
|
||||||
|
}
|
||||||
|
else if (toDemolish.indoors.Value != null && toDemolish.indoors.Value is AnimalHouse && ((AnimalHouse)toDemolish.indoors.Value).animalsThatLiveHere.Count > 0)
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_AnimalsHere");
|
||||||
|
}
|
||||||
|
else if (toDemolish.indoors.Value != null && toDemolish.indoors.Value.farmers.Any())
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_PlayerHere");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (toDemolish.indoors.Value != null && toDemolish.indoors.Value is Cabin)
|
||||||
|
{
|
||||||
|
foreach (Farmer current in Game1.getAllFarmers())
|
||||||
|
{
|
||||||
|
if (current.currentLocation != null && current.currentLocation.Name == ((Cabin)toDemolish.indoors.Value).GetCellarName())
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_PlayerHere");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toDemolish.indoors.Value is Cabin && ((Cabin)toDemolish.indoors.Value).farmhand.Value.isActive())
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_FarmhandOnline");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toDemolish.BeforeDemolish();
|
||||||
|
Chest? chest = null;
|
||||||
|
if (toDemolish.indoors.Value is Cabin)
|
||||||
|
{
|
||||||
|
List<Item> list = ((Cabin)toDemolish.indoors.Value).demolish();
|
||||||
|
if (list.Count > 0)
|
||||||
|
{
|
||||||
|
chest = new Chest(playerChest: true);
|
||||||
|
chest.fixLidFrame();
|
||||||
|
chest.items.Set(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (farm.destroyStructure(toDemolish))
|
||||||
|
{
|
||||||
|
_ = (int)toDemolish.tileY.Value;
|
||||||
|
_ = (int)toDemolish.tilesHigh.Value;
|
||||||
|
Game1.flashAlpha = 1f;
|
||||||
|
toDemolish.showDestroyedAnimation(Game1.getFarm());
|
||||||
|
Game1.playSound("explosion");
|
||||||
|
Utility.spreadAnimalsAround(toDemolish, farm);
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null)
|
||||||
|
DelayedAction.functionAfterDelay(CarpenterMenuPatch.carpenterMenu.returnToCarpentryMenu, 1500);
|
||||||
|
// freeze = true;
|
||||||
|
if (chest != null)
|
||||||
|
{
|
||||||
|
farm.objects[new Vector2((int)toDemolish.tileX.Value + (int)toDemolish.tilesWide.Value / 2, (int)toDemolish.tileY.Value + (int)toDemolish.tilesHigh.Value / 2)] = chest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (toDemolish != null)
|
||||||
|
{
|
||||||
|
if (toDemolish.indoors.Value != null && toDemolish.indoors.Value is Cabin && !Game1.IsMasterGame)
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_LockFailed");
|
||||||
|
toDemolish = null;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null && !CarpenterMenuPatch.carpenterMenu.CanDemolishThis(toDemolish))
|
||||||
|
{
|
||||||
|
toDemolish = null;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null && !Game1.IsMasterGame && !CarpenterMenuPatch.carpenterMenu.hasPermissionsToDemolish(toDemolish))
|
||||||
|
{
|
||||||
|
toDemolish = null;
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toDemolish != null && toDemolish.indoors.Value is Cabin)
|
||||||
|
{
|
||||||
|
Cabin cabin = (Cabin)toDemolish.indoors.Value;
|
||||||
|
if (cabin.farmhand.Value != null && (bool)cabin.farmhand.Value.isCustomized.Value)
|
||||||
|
{
|
||||||
|
Game1.currentLocation.createQuestionDialogue(Game1.content.LoadString("Strings\\UI:Carpenter_DemolishCabinConfirm", cabin.farmhand.Value.Name), Game1.currentLocation.createYesNoResponses(), delegate (Farmer f, string answer)
|
||||||
|
{
|
||||||
|
if (answer == "Yes")
|
||||||
|
{
|
||||||
|
Game1.activeClickableMenu = CarpenterMenuPatch.carpenterMenu;
|
||||||
|
Game1.player.team.demolishLock.RequestLock(continueDemolish, buildingLockFailed);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null)
|
||||||
|
DelayedAction.functionAfterDelay(CarpenterMenuPatch.carpenterMenu.returnToCarpentryMenu, 1000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toDemolish != null)
|
||||||
|
{
|
||||||
|
Game1.player.team.demolishLock.RequestLock(continueDemolish, buildingLockFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? Contstruct(Vector2 position)
|
||||||
|
{
|
||||||
|
string? response = null;
|
||||||
|
// This code is taken from the game's code (CarpenterMenu.cs::874)
|
||||||
|
Game1.player.team.buildLock.RequestLock(delegate
|
||||||
|
{
|
||||||
|
if (CarpenterMenuPatch.isOnFarm && Game1.locationRequest == null)
|
||||||
|
{
|
||||||
|
if (tryToBuild(position))
|
||||||
|
{
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null)
|
||||||
|
{
|
||||||
|
CarpenterMenuPatch.carpenterMenu.CurrentBlueprint.consumeResources();
|
||||||
|
DelayedAction.functionAfterDelay(CarpenterMenuPatch.carpenterMenu.returnToCarpentryMenuAfterSuccessfulBuild, 2000);
|
||||||
|
}
|
||||||
|
// freeze = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantBuild");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Game1.player.team.buildLock.ReleaseLock();
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool tryToBuild(Vector2 position)
|
||||||
|
{
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu == null)
|
||||||
|
return false;
|
||||||
|
return ((Farm)Game1.getLocationFromName("Farm")).buildStructure(CarpenterMenuPatch.carpenterMenu.CurrentBlueprint, position, Game1.player, CarpenterMenuPatch.isMagicalConstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? Upgrade(Building? toUpgrade)
|
||||||
|
{
|
||||||
|
string? response = null;
|
||||||
|
// This code is taken from the game's code (CarpenterMenu.cs::775)
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null && toUpgrade != null && CarpenterMenuPatch.carpenterMenu.CurrentBlueprint.name != null && toUpgrade.buildingType.Equals(CarpenterMenuPatch.carpenterMenu.CurrentBlueprint.nameOfBuildingToUpgrade))
|
||||||
|
{
|
||||||
|
CarpenterMenuPatch.carpenterMenu.CurrentBlueprint.consumeResources();
|
||||||
|
toUpgrade.daysUntilUpgrade.Value = 2;
|
||||||
|
toUpgrade.showUpgradeAnimation(Game1.getFarm());
|
||||||
|
Game1.playSound("axe");
|
||||||
|
DelayedAction.functionAfterDelay(CarpenterMenuPatch.carpenterMenu.returnToCarpentryMenuAfterSuccessfulBuild, 1500);
|
||||||
|
// freeze = true;
|
||||||
|
// Game1.multiplayer.globalChatInfoMessage("BuildingBuild", Game1.player.Name, Utility.AOrAn(carpenterMenu.CurrentBlueprint.displayName), carpenterMenu.CurrentBlueprint.displayName, Game1.player.farmName.Value);
|
||||||
|
}
|
||||||
|
else if (toUpgrade != null)
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantUpgrade_BuildingType");
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? Paint(Building? toPaint)
|
||||||
|
{
|
||||||
|
string? response = null;
|
||||||
|
// This code is taken from the game's code (CarpenterMenu.cs::793)
|
||||||
|
Farm farm_location = Game1.getFarm();
|
||||||
|
if (toPaint != null)
|
||||||
|
{
|
||||||
|
if (!toPaint.CanBePainted())
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null && !CarpenterMenuPatch.carpenterMenu.HasPermissionsToPaint(toPaint))
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint_Permission");
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
toPaint.color.Value = Color.White;
|
||||||
|
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null)
|
||||||
|
CarpenterMenuPatch.carpenterMenu.SetChildMenu(new StardewValley.Menus.BuildingPaintMenu(toPaint));
|
||||||
|
}
|
||||||
|
/* TODO Add painting of farm house
|
||||||
|
else if (farm_location.GetHouseRect().Contains(Utility.Vector2ToPoint(new Vector2(toPaint.tileX, toPaint.tileY))))
|
||||||
|
{
|
||||||
|
if (!carpenterMenu.CanPaintHouse())
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint");
|
||||||
|
}
|
||||||
|
else if (!carpenterMenu.HasPermissionsToPaint(null))
|
||||||
|
{
|
||||||
|
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint_Permission");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
carpenterMenu.SetChildMenu(new BuildingPaintMenu("House", () => (farm_location.paintedHouseTexture != null) ? farm_location.paintedHouseTexture : Farm.houseTextures, farm_location.houseSource.Value, farm_location.housePaintColor.Value));
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? Move(Building? buildingToMove, Vector2 position)
|
||||||
|
{
|
||||||
|
string? response = null;
|
||||||
|
// This code is taken from the game's code (CarpenterMenu.cs::829)
|
||||||
|
if (buildingToMove != null)
|
||||||
|
{
|
||||||
|
string? name = buildingToMove.nameOfIndoorsWithoutUnique;
|
||||||
|
name = (name == "null") ? buildingToMove.buildingType.Value : name;
|
||||||
|
|
||||||
|
if ((int)buildingToMove.daysOfConstructionLeft.Value > 0)
|
||||||
|
{
|
||||||
|
buildingToMove = null;
|
||||||
|
return "Building under construction, cannot move";
|
||||||
|
}
|
||||||
|
if (CarpenterMenuPatch.carpenterMenu != null && !CarpenterMenuPatch.carpenterMenu.hasPermissionsToMove(buildingToMove))
|
||||||
|
{
|
||||||
|
buildingToMove = null;
|
||||||
|
return "You don't have permission to move this building";
|
||||||
|
}
|
||||||
|
Game1.playSound("axchop");
|
||||||
|
|
||||||
|
if (((Farm)Game1.getLocationFromName("Farm")).buildStructure(buildingToMove, position, Game1.player))
|
||||||
|
{
|
||||||
|
if (buildingToMove is ShippingBin)
|
||||||
|
{
|
||||||
|
((ShippingBin)buildingToMove).initLid();
|
||||||
|
}
|
||||||
|
if (buildingToMove is GreenhouseBuilding)
|
||||||
|
{
|
||||||
|
Game1.getFarm().greenhouseMoved.Value = true;
|
||||||
|
}
|
||||||
|
buildingToMove.performActionOnBuildingPlacement();
|
||||||
|
buildingToMove = null;
|
||||||
|
Game1.playSound("axchop");
|
||||||
|
DelayedAction.playSoundAfterDelay("dirtyHit", 50);
|
||||||
|
DelayedAction.playSoundAfterDelay("dirtyHit", 150);
|
||||||
|
|
||||||
|
response = $"{buildingToMove} moved to {position.X}x {position.Y}y";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game1.playSound("cancel");
|
||||||
|
response = $"Cannot move building to {position.X}x {position.Y}y";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PurchaseAnimal(Building? selection)
|
||||||
|
{
|
||||||
|
if (selection == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (PurchaseAnimalsMenuPatch.purchaseAnimalsMenu == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = (selection.tileX.Value * Game1.tileSize) - Game1.viewport.X;
|
||||||
|
int y = (selection.tileY.Value * Game1.tileSize) - Game1.viewport.Y;
|
||||||
|
|
||||||
|
if (PurchaseAnimalsMenuPatch.animalBeingPurchased != null && !selection.buildingType.Value.Contains(PurchaseAnimalsMenuPatch.animalBeingPurchased.buildingTypeILiveIn.Value))
|
||||||
|
{
|
||||||
|
string warn = Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11326", PurchaseAnimalsMenuPatch.animalBeingPurchased.displayType);
|
||||||
|
MainClass.ScreenReader.Say(warn, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((AnimalHouse)selection.indoors.Value).isFull())
|
||||||
|
{
|
||||||
|
string warn = Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11321");
|
||||||
|
MainClass.ScreenReader.Say(warn, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PurchaseAnimalsMenuPatch.purchaseAnimalsMenu.receiveLeftClick(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MoveAnimal(Building? selection)
|
||||||
|
{
|
||||||
|
if (selection == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (AnimalQueryMenuPatch.animalQueryMenu == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (AnimalQueryMenuPatch.animalBeingMoved == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The following code is taken from the game's source code [AnimalQueryMenu.cs::receiveLeftClick]
|
||||||
|
if (selection.buildingType.Value.Contains(AnimalQueryMenuPatch.animalBeingMoved.buildingTypeILiveIn.Value))
|
||||||
|
{
|
||||||
|
if (((AnimalHouse)selection.indoors.Value).isFull())
|
||||||
|
{
|
||||||
|
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_BuildingFull");
|
||||||
|
MainClass.ScreenReader.Say(warn, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selection.Equals(AnimalQueryMenuPatch.animalBeingMoved.home))
|
||||||
|
{
|
||||||
|
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_AlreadyHome");
|
||||||
|
MainClass.ScreenReader.Say(warn, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
((AnimalHouse)AnimalQueryMenuPatch.animalBeingMoved.home.indoors.Value).animalsThatLiveHere.Remove(AnimalQueryMenuPatch.animalBeingMoved.myID.Value);
|
||||||
|
if (((AnimalHouse)AnimalQueryMenuPatch.animalBeingMoved.home.indoors.Value).animals.ContainsKey(AnimalQueryMenuPatch.animalBeingMoved.myID.Value))
|
||||||
|
{
|
||||||
|
((AnimalHouse)selection.indoors.Value).animals.Add(AnimalQueryMenuPatch.animalBeingMoved.myID.Value, AnimalQueryMenuPatch.animalBeingMoved);
|
||||||
|
((AnimalHouse)AnimalQueryMenuPatch.animalBeingMoved.home.indoors.Value).animals.Remove(AnimalQueryMenuPatch.animalBeingMoved.myID.Value);
|
||||||
|
}
|
||||||
|
AnimalQueryMenuPatch.animalBeingMoved.home = selection;
|
||||||
|
AnimalQueryMenuPatch.animalBeingMoved.homeLocation.Value = new Vector2((int)selection.tileX.Value, (int)selection.tileY.Value);
|
||||||
|
((AnimalHouse)selection.indoors.Value).animalsThatLiveHere.Add(AnimalQueryMenuPatch.animalBeingMoved.myID.Value);
|
||||||
|
AnimalQueryMenuPatch.animalBeingMoved.makeSound();
|
||||||
|
Game1.globalFadeToBlack(AnimalQueryMenuPatch.animalQueryMenu.finishedPlacingAnimal);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_CantLiveThere");
|
||||||
|
MainClass.ScreenReader.Say(warn, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,212 @@
|
||||||
|
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Features
|
||||||
|
{
|
||||||
|
internal class InventoryUtils
|
||||||
|
{
|
||||||
|
internal static string hoveredItemQueryKey = "";
|
||||||
|
internal static int prevSlotIndex = -999;
|
||||||
|
|
||||||
|
internal static bool narrateHoveredSlot(InventoryMenu inventoryMenu, List<ClickableComponent> inventory, IList<Item> actualInventory, int x, int y,
|
||||||
|
bool giveExtraDetails = false, int hoverPrice = -1, int extraItemToShowIndex = -1, int extraItemToShowAmount = -1,
|
||||||
|
bool handleHighlightedItem = false, String highlightedItemPrefix = "", String highlightedItemSuffix = "")
|
||||||
|
{
|
||||||
|
if (narrateHoveredSlotAndReturnIndex(inventoryMenu, inventory, actualInventory, x, y,
|
||||||
|
giveExtraDetails = false, hoverPrice = -1, extraItemToShowIndex = -1, extraItemToShowAmount = -1,
|
||||||
|
handleHighlightedItem = false, highlightedItemPrefix = "", highlightedItemSuffix = "") == -999)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int narrateHoveredSlotAndReturnIndex(InventoryMenu inventoryMenu, List<ClickableComponent> inventory, IList<Item> actualInventory, int x, int y,
|
||||||
|
bool giveExtraDetails = false, int hoverPrice = -1, int extraItemToShowIndex = -1, int extraItemToShowAmount = -1,
|
||||||
|
bool handleHighlightedItem = false, String highlightedItemPrefix = "", String highlightedItemSuffix = "")
|
||||||
|
{
|
||||||
|
for (int i = 0; i < inventory.Count; i++)
|
||||||
|
{
|
||||||
|
if (!inventory[i].containsPoint(x, y)) continue;
|
||||||
|
|
||||||
|
if ((i + 1) > actualInventory.Count || actualInventory[i] == null)
|
||||||
|
{
|
||||||
|
// For empty slot
|
||||||
|
checkAndSpeak("Empty Slot", i);
|
||||||
|
prevSlotIndex = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isHighlighted = inventoryMenu.highlightMethod(actualInventory[i]);
|
||||||
|
|
||||||
|
string namePrefix = handleHighlightedItemPrefix(isHighlighted, highlightedItemPrefix);
|
||||||
|
string nameSuffix = $"{handleHighlightedItemSuffix(isHighlighted, highlightedItemSuffix)}{handleUnHighlightedItem(isHighlighted, i)}";
|
||||||
|
string name = $"{namePrefix}{actualInventory[i].DisplayName}{nameSuffix}";
|
||||||
|
int stack = actualInventory[i].Stack;
|
||||||
|
string quality = getQualityFromItem(actualInventory[i]);
|
||||||
|
string healthNStamine = getHealthNStaminaFromItem(actualInventory[i]);
|
||||||
|
string buffs = getBuffsFromItem(actualInventory[i]);
|
||||||
|
string description = actualInventory[i].getDescription();
|
||||||
|
string price = getPrice(hoverPrice);
|
||||||
|
string requirements = getExtraItemInfo(extraItemToShowIndex, extraItemToShowAmount);
|
||||||
|
|
||||||
|
if (giveExtraDetails)
|
||||||
|
{
|
||||||
|
if (stack > 1)
|
||||||
|
toSpeak = $"{stack} {name} {quality}, \n{requirements}, \n{price}, \n{description}, \n{healthNStamine}, \n{buffs}";
|
||||||
|
else
|
||||||
|
toSpeak = $"{name} {quality}, \n{requirements}, \n{price}, \n{description}, \n{healthNStamine}, \n{buffs}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (stack > 1)
|
||||||
|
toSpeak = $"{stack} {name} {quality}, \n{requirements}, \n{price}";
|
||||||
|
else
|
||||||
|
toSpeak = $"{name} {quality}, \n{requirements}, \n{price}";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
checkAndSpeak(toSpeak, i);
|
||||||
|
prevSlotIndex = i;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no slot is hovered
|
||||||
|
return -999;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkAndSpeak(String toSpeak, int hoveredInventoryIndex)
|
||||||
|
{
|
||||||
|
if (hoveredItemQueryKey == $"{toSpeak}:{hoveredInventoryIndex}") return;
|
||||||
|
|
||||||
|
hoveredItemQueryKey = $"{toSpeak}:{hoveredInventoryIndex}";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getQualityFromItem(Item item)
|
||||||
|
{
|
||||||
|
if (item is not StardewValley.Object || ((StardewValley.Object)item).Quality <= 0)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
int qualityIndex = ((StardewValley.Object)item).Quality;
|
||||||
|
if (qualityIndex == 1)
|
||||||
|
{
|
||||||
|
return "Silver quality";
|
||||||
|
}
|
||||||
|
else if (qualityIndex == 2 || qualityIndex == 3)
|
||||||
|
{
|
||||||
|
return "Gold quality";
|
||||||
|
}
|
||||||
|
else if (qualityIndex >= 4)
|
||||||
|
{
|
||||||
|
return "Iridium quality";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getHealthNStaminaFromItem(Item item)
|
||||||
|
{
|
||||||
|
if (item is not StardewValley.Object || ((StardewValley.Object)item).Edibility == -300)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
String toReturn = "";
|
||||||
|
int stamina_recovery = ((StardewValley.Object)item).staminaRecoveredOnConsumption();
|
||||||
|
toReturn += $"{stamina_recovery} Energy";
|
||||||
|
|
||||||
|
if (stamina_recovery < 0) return toReturn;
|
||||||
|
|
||||||
|
int health_recovery = ((StardewValley.Object)item).healthRecoveredOnConsumption();
|
||||||
|
toReturn += $"\n\t{health_recovery} Health";
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getBuffsFromItem(Item item)
|
||||||
|
{
|
||||||
|
if (item == null) return "";
|
||||||
|
if (item is not StardewValley.Object) return "";
|
||||||
|
if (((StardewValley.Object)item) == null) return "";
|
||||||
|
|
||||||
|
// These variables are taken from the game's code itself (IClickableMenu.cs -> 1016 line)
|
||||||
|
bool edibleItem = (int)((StardewValley.Object)item).Edibility != -300;
|
||||||
|
string[]? buffIconsToDisplay = (edibleItem && Game1.objectInformation[((StardewValley.Object)item).ParentSheetIndex].Split('/').Length > 7)
|
||||||
|
? item.ModifyItemBuffs(Game1.objectInformation[((StardewValley.Object)item).ParentSheetIndex].Split('/')[7].Split(' '))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (buffIconsToDisplay == null)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
String toReturn = "";
|
||||||
|
for (int j = 0; j < buffIconsToDisplay.Length; j++)
|
||||||
|
{
|
||||||
|
string buffName = ((Convert.ToInt32(buffIconsToDisplay[j]) > 0) ? "+" : "") + buffIconsToDisplay[j] + " ";
|
||||||
|
if (j <= 11)
|
||||||
|
{
|
||||||
|
buffName = Game1.content.LoadString("Strings\\UI:ItemHover_Buff" + j, buffName);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int count = int.Parse(buffName.Substring(0, buffName.IndexOf(' ')));
|
||||||
|
if (count != 0)
|
||||||
|
toReturn += $"{buffName}\n";
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getExtraItemInfo(int itemIndex, int itemAmount)
|
||||||
|
{
|
||||||
|
if (itemIndex == -1) return "";
|
||||||
|
|
||||||
|
string itemName = Game1.objectInformation[itemIndex].Split('/')[0];
|
||||||
|
|
||||||
|
if (itemAmount != -1)
|
||||||
|
return $"Required: {itemAmount} {itemName}";
|
||||||
|
else
|
||||||
|
return $"Required: {itemName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPrice(int price)
|
||||||
|
{
|
||||||
|
if (price == -1) return "";
|
||||||
|
|
||||||
|
return $"Sell Price: {price} g";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String handleHighlightedItemPrefix(bool isHighlighted, String prefix)
|
||||||
|
{
|
||||||
|
if (MainClass.Config.DisableInventoryVerbosity) return "";
|
||||||
|
if (!isHighlighted) return "";
|
||||||
|
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String handleHighlightedItemSuffix(bool isHighlighted, String suffix)
|
||||||
|
{
|
||||||
|
if (MainClass.Config.DisableInventoryVerbosity) return "";
|
||||||
|
if (!isHighlighted) return "";
|
||||||
|
|
||||||
|
return suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String handleUnHighlightedItem(bool isHighlighted, int hoveredInventoryIndex)
|
||||||
|
{
|
||||||
|
if (isHighlighted) return "";
|
||||||
|
|
||||||
|
if (prevSlotIndex != hoveredInventoryIndex)
|
||||||
|
Game1.playSound("invalid-selection");
|
||||||
|
|
||||||
|
if (MainClass.Config.DisableInventoryVerbosity) return "";
|
||||||
|
return " not usable here";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
prevSlotIndex = -999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,18 +77,17 @@ namespace stardew_access.Features
|
||||||
return getStaticTileInfoAtWithCategory(x, y).name;
|
return getStaticTileInfoAtWithCategory(x, y).name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (string? name, CATEGORY category) getStaticTileInfoAtWithCategory(int x, int y)
|
public (string? name, CATEGORY category) getStaticTileInfoAtWithCategory(int x, int y) {
|
||||||
{
|
|
||||||
List<JObject> allData = new List<JObject>();
|
List<JObject> allData = new List<JObject>();
|
||||||
|
|
||||||
if (customTilesData != null) allData.Add(customTilesData);
|
if (customTilesData != null) allData.Add(customTilesData);
|
||||||
if (staticTilesData != null) allData.Add(staticTilesData);
|
if (staticTilesData != null) allData.Add(staticTilesData);
|
||||||
|
|
||||||
foreach (JObject data in allData)
|
foreach (JObject data in allData) {
|
||||||
{
|
|
||||||
foreach (KeyValuePair<string, JToken?> location in data)
|
foreach (KeyValuePair<string, JToken?> location in data)
|
||||||
{
|
{
|
||||||
if (location.Key.Contains("||") && MainClass.ModHelper != null)
|
string locationName = location.Key;
|
||||||
|
if (locationName.Contains("||") && MainClass.ModHelper != null)
|
||||||
{
|
{
|
||||||
// Mod Specific Tiles
|
// Mod Specific Tiles
|
||||||
// We can add tiles that only get detected when the specified mod is loaded.
|
// We can add tiles that only get detected when the specified mod is loaded.
|
||||||
|
@ -109,20 +108,35 @@ namespace stardew_access.Features
|
||||||
// .
|
// .
|
||||||
// .
|
// .
|
||||||
// }
|
// }
|
||||||
string uniqueModID = location.Key.Substring(location.Key.LastIndexOf("||") + 2);
|
string uniqueModID = locationName.Substring(locationName.LastIndexOf("||") + 2);
|
||||||
string locationName = location.Key.Remove(location.Key.LastIndexOf("||"));
|
locationName = locationName.Remove(locationName.LastIndexOf("||"));
|
||||||
bool isLoaded = MainClass.ModHelper.ModRegistry.IsLoaded(uniqueModID);
|
bool isLoaded = MainClass.ModHelper.ModRegistry.IsLoaded(uniqueModID);
|
||||||
|
|
||||||
if (!isLoaded) continue; // Skip if the specified mod is not loaded
|
if (!isLoaded) continue; // Skip if the specified mod is not loaded
|
||||||
if (!Game1.currentLocation.Name.ToLower().Equals(locationName.ToLower())) continue;
|
|
||||||
}
|
}
|
||||||
else if (!Game1.currentLocation.Name.ToLower().Equals(location.Key.ToLower())) continue;
|
|
||||||
|
|
||||||
if (location.Value != null)
|
if (locationName.Contains("_") && locationName.ToLower().StartsWith("farm_"))
|
||||||
|
{
|
||||||
|
string farmType = locationName.Substring(locationName.LastIndexOf("_") + 1);
|
||||||
|
int farmTypeIndex = getFarmTypeIndex(farmType);
|
||||||
|
locationName = locationName.Remove(locationName.LastIndexOf("_"));
|
||||||
|
|
||||||
|
if (farmTypeIndex != Game1.whichFarm) continue; // Skip if current farm type does not matches
|
||||||
|
// if (Game1.whichModFarm != null) MainClass.DebugLog($"{farmType} {Game1.whichModFarm.MapName}");
|
||||||
|
if (farmTypeIndex != 7 || Game1.whichModFarm == null || !farmType.ToLower().Equals(Game1.whichModFarm.MapName.ToLower())) continue; // Not tested but should work
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locationName.ToLower().Equals("town_joja") && Game1.MasterPlayer.mailReceived.Contains("JojaMember"))
|
||||||
|
{
|
||||||
|
locationName = "town";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Game1.currentLocation.Name.ToLower().Equals(locationName.ToLower())) continue;
|
||||||
|
if (location.Value == null) continue;
|
||||||
|
|
||||||
foreach (var tile in ((JObject)location.Value))
|
foreach (var tile in ((JObject)location.Value))
|
||||||
{
|
{
|
||||||
if (tile.Value == null)
|
if (tile.Value == null) continue;
|
||||||
continue;
|
|
||||||
|
|
||||||
JToken? tileXArray = tile.Value["x"];
|
JToken? tileXArray = tile.Value["x"];
|
||||||
JToken? tileYArray = tile.Value["y"];
|
JToken? tileYArray = tile.Value["y"];
|
||||||
|
@ -136,21 +150,21 @@ namespace stardew_access.Features
|
||||||
|
|
||||||
foreach (var item in tileXArray)
|
foreach (var item in tileXArray)
|
||||||
{
|
{
|
||||||
if (short.Parse(item.ToString()) == x)
|
if (short.Parse(item.ToString()) != x)
|
||||||
{
|
continue;
|
||||||
|
|
||||||
isXPresent = true;
|
isXPresent = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in tileYArray)
|
foreach (var item in tileYArray)
|
||||||
{
|
{
|
||||||
if (short.Parse(item.ToString()) == y)
|
if (short.Parse(item.ToString()) != y)
|
||||||
{
|
continue;
|
||||||
|
|
||||||
isYPresent = true;
|
isYPresent = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (isXPresent && isYPresent)
|
if (isXPresent && isYPresent)
|
||||||
{
|
{
|
||||||
|
@ -173,5 +187,20 @@ namespace stardew_access.Features
|
||||||
}
|
}
|
||||||
return (null, CATEGORY.Others);
|
return (null, CATEGORY.Others);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getFarmTypeIndex(string farmType)
|
||||||
|
{
|
||||||
|
return farmType.ToLower() switch
|
||||||
|
{
|
||||||
|
"default" => 0,
|
||||||
|
"riverlands" => 1,
|
||||||
|
"forest" => 2,
|
||||||
|
"mountains" => 3,
|
||||||
|
"combat" => 4,
|
||||||
|
"fourcorners" => 5,
|
||||||
|
"beach" => 6,
|
||||||
|
_ => 7,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,15 +455,19 @@ namespace stardew_access.Features
|
||||||
else if (Game1.currentLocation is FarmHouse farmHouse)
|
else if (Game1.currentLocation is FarmHouse farmHouse)
|
||||||
{
|
{
|
||||||
if (farmHouse.upgradeLevel >= 1)
|
if (farmHouse.upgradeLevel >= 1)
|
||||||
if (farmHouse.getKitchenStandingSpot().X == x && (farmHouse.getKitchenStandingSpot().Y - 1) == y) // Standing spot is where the player will stand
|
if (farmHouse.getKitchenStandingSpot().X == x && (farmHouse.getKitchenStandingSpot().Y - 1) == y)
|
||||||
return (CATEGORY.Interactables, "Kitchen");
|
return (CATEGORY.Interactables, "Stove");
|
||||||
|
else if ((farmHouse.getKitchenStandingSpot().X + 1) == x && (farmHouse.getKitchenStandingSpot().Y - 1) == y)
|
||||||
|
return (CATEGORY.Others, "Sink");
|
||||||
else if (farmHouse.fridgePosition.X == x && farmHouse.fridgePosition.Y == y)
|
else if (farmHouse.fridgePosition.X == x && farmHouse.fridgePosition.Y == y)
|
||||||
return (CATEGORY.Interactables, "Fridge");
|
return (CATEGORY.Interactables, "Fridge");
|
||||||
}
|
}
|
||||||
else if (Game1.currentLocation is IslandFarmHouse islandFarmHouse)
|
else if (Game1.currentLocation is IslandFarmHouse islandFarmHouse)
|
||||||
{
|
{
|
||||||
if ((islandFarmHouse.fridgePosition.X - 1) == x && islandFarmHouse.fridgePosition.Y == y)
|
if ((islandFarmHouse.fridgePosition.X - 2) == x && islandFarmHouse.fridgePosition.Y == y)
|
||||||
return (CATEGORY.Interactables, "Kitchen");
|
return (CATEGORY.Interactables, "Stove");
|
||||||
|
else if ((islandFarmHouse.fridgePosition.X - 1) == x && islandFarmHouse.fridgePosition.Y == y)
|
||||||
|
return (CATEGORY.Others, "Sink");
|
||||||
else if (islandFarmHouse.fridgePosition.X == x && islandFarmHouse.fridgePosition.Y == y)
|
else if (islandFarmHouse.fridgePosition.X == x && islandFarmHouse.fridgePosition.Y == y)
|
||||||
return (CATEGORY.Interactables, "Fridge");
|
return (CATEGORY.Interactables, "Fridge");
|
||||||
}
|
}
|
||||||
|
@ -520,7 +524,7 @@ namespace stardew_access.Features
|
||||||
}
|
}
|
||||||
else if (Game1.currentLocation is IslandWest islandWest)
|
else if (Game1.currentLocation is IslandWest islandWest)
|
||||||
{
|
{
|
||||||
if (islandWest.shippingBinPosition.X == x && islandWest.shippingBinPosition.Y == y)
|
if ((islandWest.shippingBinPosition.X == x || (islandWest.shippingBinPosition.X + 1) == x) && islandWest.shippingBinPosition.Y == y)
|
||||||
return (CATEGORY.Interactables, "Shipping Bin");
|
return (CATEGORY.Interactables, "Shipping Bin");
|
||||||
}
|
}
|
||||||
else if (Game1.currentLocation is IslandNorth islandNorth)
|
else if (Game1.currentLocation is IslandNorth islandNorth)
|
||||||
|
|
|
@ -16,220 +16,216 @@ namespace stardew_access
|
||||||
#region Dialogue Patches
|
#region Dialogue Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(DialogueBox), nameof(DialogueBox.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(DialogueBox), nameof(DialogueBox.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.DialoguePatch))
|
postfix: new HarmonyMethod(typeof(DialogueBoxPatch), nameof(DialogueBoxPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(DialogueBox), nameof(DialogueBox.receiveLeftClick)),
|
original: AccessTools.Method(typeof(DialogueBox), nameof(DialogueBox.receiveLeftClick)),
|
||||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.ClearDialogueString))
|
postfix: new HarmonyMethod(typeof(DialogueBoxPatch), nameof(DialogueBoxPatch.RecieveLeftClickPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawHoverText), new Type[] { typeof(SpriteBatch), typeof(string), typeof(SpriteFont), typeof(int), typeof(int), typeof(int), typeof(string), typeof(int), typeof(string[]), typeof(Item), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(float), typeof(CraftingRecipe), typeof(IList<Item>) }),
|
original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawHoverText), new Type[] { typeof(SpriteBatch), typeof(string), typeof(SpriteFont), typeof(int), typeof(int), typeof(int), typeof(string), typeof(int), typeof(string[]), typeof(Item), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(float), typeof(CraftingRecipe), typeof(IList<Item>) }),
|
||||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.HoverTextPatch))
|
postfix: new HarmonyMethod(typeof(IClickableMenuPatch), nameof(IClickableMenuPatch.DrawHoverTextPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(NPC), nameof(NPC.drawAboveAlwaysFrontLayer)),
|
original: AccessTools.Method(typeof(NPC), nameof(NPC.drawAboveAlwaysFrontLayer)),
|
||||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.drawAboveAlwaysFrontLayerPatch))
|
postfix: new HarmonyMethod(typeof(NPCPatch), nameof(NPCPatch.DrawAboveAlwaysFrontLayerPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Title Menu Patches
|
#region Title Menu Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(TitleMenu), nameof(TitleMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(TitleMenu), nameof(TitleMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.TitleMenuPatch))
|
postfix: new HarmonyMethod(typeof(TitleMenuPatch), nameof(TitleMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(LoadGameMenu.SaveFileSlot), nameof(LoadGameMenu.SaveFileSlot.Draw), new Type[] { typeof(SpriteBatch), typeof(int) }),
|
original: AccessTools.Method(typeof(LoadGameMenu.SaveFileSlot), nameof(LoadGameMenu.SaveFileSlot.Draw), new Type[] { typeof(SpriteBatch), typeof(int) }),
|
||||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.LoadGameMenuPatch))
|
postfix: new HarmonyMethod(typeof(LoadGameMenuPatch), nameof(LoadGameMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(CharacterCustomization), nameof(CharacterCustomization.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(CharacterCustomization), nameof(CharacterCustomization.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(CharacterCustomizationPatches.CharacterCustomizationMenuPatch))
|
postfix: new HarmonyMethod(typeof(CharacterCustomizationMenuPatch), nameof(CharacterCustomizationMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(CoopMenu), nameof(CoopMenu.update), new Type[] { typeof(GameTime) }),
|
original: AccessTools.Method(typeof(CoopMenu), nameof(CoopMenu.update), new Type[] { typeof(GameTime) }),
|
||||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.CoopMenuPatch))
|
postfix: new HarmonyMethod(typeof(CoopMenuPatch), nameof(CoopMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(AdvancedGameOptions), nameof(AdvancedGameOptions.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(AdvancedGameOptions), nameof(AdvancedGameOptions.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(TitleMenuPatches), nameof(TitleMenuPatches.AdvancedGameOptionsPatch))
|
postfix: new HarmonyMethod(typeof(AdvancedGameOptionsPatch), nameof(AdvancedGameOptionsPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Game Menu Patches
|
#region Game Menu Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(GameMenu), nameof(GameMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(GameMenu), nameof(GameMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.GameMenuPatch))
|
postfix: new HarmonyMethod(typeof(GameMenuPatch), nameof(GameMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(OptionsPage), nameof(OptionsPage.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(OptionsPage), nameof(OptionsPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.OptionsPagePatch))
|
postfix: new HarmonyMethod(typeof(OptionsPagePatch), nameof(OptionsPagePatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ExitPage), nameof(ExitPage.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ExitPage), nameof(ExitPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.ExitPagePatch))
|
postfix: new HarmonyMethod(typeof(ExitPagePatch), nameof(ExitPagePatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(CraftingPage), nameof(CraftingPage.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(CraftingPage), nameof(CraftingPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.CraftingPagePatch))
|
postfix: new HarmonyMethod(typeof(CraftingPagePatch), nameof(CraftingPagePatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(InventoryPage), nameof(InventoryPage.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(InventoryPage), nameof(InventoryPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.InventoryPagePatch))
|
postfix: new HarmonyMethod(typeof(InventoryPagePatch), nameof(InventoryPagePatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ItemGrabMenu), nameof(ItemGrabMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ItemGrabMenu), nameof(ItemGrabMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.ItemGrabMenuPatch))
|
postfix: new HarmonyMethod(typeof(ItemGrabMenuPatch), nameof(ItemGrabMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(GeodeMenu), nameof(GeodeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(GeodeMenu), nameof(GeodeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.GeodeMenuPatch))
|
postfix: new HarmonyMethod(typeof(GeodeMenuPatch), nameof(GeodeMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ShopMenu), nameof(ShopMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ShopMenu), nameof(ShopMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.ShopMenuPatch))
|
postfix: new HarmonyMethod(typeof(ShopMenuPatch), nameof(ShopMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(SocialPage), nameof(SocialPage.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(SocialPage), nameof(SocialPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.SocialPagePatch))
|
postfix: new HarmonyMethod(typeof(SocialPagePatch), nameof(SocialPagePatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(CollectionsPage), nameof(CollectionsPage.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(CollectionsPage), nameof(CollectionsPage.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(GameMenuPatches), nameof(GameMenuPatches.CollectionsPagePatch))
|
postfix: new HarmonyMethod(typeof(CollectionsPagePatch), nameof(CollectionsPagePatch.DrawPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Bundle Menu Patches
|
#region Bundle Menu Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(JunimoNoteMenu), nameof(JunimoNoteMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(JunimoNoteMenu), nameof(JunimoNoteMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(BundleMenuPatches), nameof(BundleMenuPatches.JunimoNoteMenuPatch))
|
postfix: new HarmonyMethod(typeof(JunimoNoteMenuPatch), nameof(JunimoNoteMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(JojaCDMenu), nameof(JojaCDMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(JojaCDMenu), nameof(JojaCDMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(BundleMenuPatches), nameof(BundleMenuPatches.JojaCDMenuPatch))
|
postfix: new HarmonyMethod(typeof(JojaCDMenuPatch), nameof(JojaCDMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Menu Patches
|
#region Menu Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(LetterViewerMenu), nameof(LetterViewerMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(LetterViewerMenu), nameof(LetterViewerMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(DialoguePatches), nameof(DialoguePatches.LetterViewerMenuPatch))
|
postfix: new HarmonyMethod(typeof(LetterViwerMenuPatch), nameof(LetterViwerMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ShippingMenu), nameof(ShippingMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ShippingMenu), nameof(ShippingMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ShippingMenuPatch))
|
postfix: new HarmonyMethod(typeof(ShippingMenuPatch), nameof(ShippingMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(LevelUpMenu), nameof(LevelUpMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(LevelUpMenu), nameof(LevelUpMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.LevelUpMenuPatch))
|
postfix: new HarmonyMethod(typeof(LevelUpMenuPatch), nameof(LevelUpMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ConfirmationDialog), nameof(ConfirmationDialog.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ConfirmationDialog), nameof(ConfirmationDialog.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ConfirmationDialogPatch))
|
postfix: new HarmonyMethod(typeof(ConfirmationDialogMenuPatch), nameof(ConfirmationDialogMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(TitleTextInputMenu), nameof(TitleTextInputMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(TitleTextInputMenu), nameof(TitleTextInputMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.TitleTextInputMenuPatch))
|
postfix: new HarmonyMethod(typeof(TitleTextInputMenuPatch), nameof(TitleTextInputMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(NamingMenu), nameof(NamingMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(NamingMenu), nameof(NamingMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.NamingMenuPatch))
|
postfix: new HarmonyMethod(typeof(NamingMenuPatch), nameof(NamingMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(MineElevatorMenu), nameof(MineElevatorMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(MineElevatorMenu), nameof(MineElevatorMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.MineElevatorMenuPatch))
|
postfix: new HarmonyMethod(typeof(MineElevatorMenuPatch), nameof(MineElevatorMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(LanguageSelectionMenu), nameof(LanguageSelectionMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(LanguageSelectionMenu), nameof(LanguageSelectionMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.LanguageSelectionMenuPatch))
|
postfix: new HarmonyMethod(typeof(LanguageSelectionMenuPatch), nameof(LanguageSelectionMenuPatch.DrawPatch))
|
||||||
);
|
|
||||||
|
|
||||||
harmony.Patch(
|
|
||||||
original: AccessTools.Method(typeof(MuseumMenu), nameof(MuseumMenu.receiveKeyPress), new Type[] { typeof(Keys) }),
|
|
||||||
prefix: new HarmonyMethod(typeof(DonationMenuPatches), nameof(DonationMenuPatches.MuseumMenuKeyPressPatch))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ChooseFromListMenu), nameof(ChooseFromListMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ChooseFromListMenu), nameof(ChooseFromListMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ChooseFromListMenuPatch))
|
postfix: new HarmonyMethod(typeof(ChooseFromListMenuPatch), nameof(ChooseFromListMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(TailoringMenu), nameof(TailoringMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(TailoringMenu), nameof(TailoringMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.TailoringMenuPatch))
|
postfix: new HarmonyMethod(typeof(TailoringMenuPatch), nameof(TailoringMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(PondQueryMenu), nameof(PondQueryMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(PondQueryMenu), nameof(PondQueryMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.PondQueryMenuPatch))
|
postfix: new HarmonyMethod(typeof(PondQueryMenuPatch), nameof(PondQueryMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ForgeMenu), nameof(ForgeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ForgeMenu), nameof(ForgeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ForgeMenuPatch))
|
postfix: new HarmonyMethod(typeof(ForgeMenuPatch), nameof(ForgeMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ItemListMenu), nameof(ItemListMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(ItemListMenu), nameof(ItemListMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ItemListMenuPatch))
|
postfix: new HarmonyMethod(typeof(ItemListMenuPatch), nameof(ItemListMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Quest Patches
|
#region Quest Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(SpecialOrdersBoard), nameof(SpecialOrdersBoard.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(SpecialOrdersBoard), nameof(SpecialOrdersBoard.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(QuestPatches), nameof(QuestPatches.SpecialOrdersBoardPatch))
|
postfix: new HarmonyMethod(typeof(SpecialOrdersBoardPatch), nameof(SpecialOrdersBoardPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(QuestLog), nameof(QuestLog.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(QuestLog), nameof(QuestLog.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(QuestPatches), nameof(QuestPatches.QuestLogPatch))
|
postfix: new HarmonyMethod(typeof(QuestLogPatch), nameof(QuestLogPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(Billboard), nameof(Billboard.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(Billboard), nameof(Billboard.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(QuestPatches), nameof(QuestPatches.BillboardPatch))
|
postfix: new HarmonyMethod(typeof(BillboardPatch), nameof(BillboardPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Chat Menu Patches
|
#region Chat Menu Patches
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(ChatBox), nameof(ChatBox.update), new Type[] { typeof(GameTime) }),
|
original: AccessTools.Method(typeof(ChatBox), nameof(ChatBox.update), new Type[] { typeof(GameTime) }),
|
||||||
postfix: new HarmonyMethod(typeof(ChatMenuPatches), nameof(ChatMenuPatches.ChatBoxPatch))
|
postfix: new HarmonyMethod(typeof(ChatBoxPatch), nameof(ChatBoxPatch.UpdatePatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region On Menu CLose Patch
|
#region On Menu CLose Patch
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.exitThisMenu)),
|
original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.exitThisMenu)),
|
||||||
postfix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.IClickableMenuOnExitPatch))
|
postfix: new HarmonyMethod(typeof(IClickableMenuPatch), nameof(IClickableMenuPatch.ExitThisMenuPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(Game1), nameof(Game1.exitActiveMenu)),
|
original: AccessTools.Method(typeof(Game1), nameof(Game1.exitActiveMenu)),
|
||||||
prefix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.Game1ExitActiveMenuPatch))
|
prefix: new HarmonyMethod(typeof(Game1Patch), nameof(Game1Patch.ExitActiveMenuPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -237,17 +233,17 @@ namespace stardew_access
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(CarpenterMenu), nameof(CarpenterMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(CarpenterMenu), nameof(CarpenterMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
prefix: new HarmonyMethod(typeof(BuildingNAnimalMenuPatches), nameof(BuildingNAnimalMenuPatches.CarpenterMenuPatch))
|
prefix: new HarmonyMethod(typeof(CarpenterMenuPatch), nameof(CarpenterMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(PurchaseAnimalsMenu), nameof(PurchaseAnimalsMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(PurchaseAnimalsMenu), nameof(PurchaseAnimalsMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
prefix: new HarmonyMethod(typeof(BuildingNAnimalMenuPatches), nameof(BuildingNAnimalMenuPatches.PurchaseAnimalsMenuPatch))
|
prefix: new HarmonyMethod(typeof(PurchaseAnimalsMenuPatch), nameof(PurchaseAnimalsMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(AnimalQueryMenu), nameof(AnimalQueryMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(AnimalQueryMenu), nameof(AnimalQueryMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(BuildingNAnimalMenuPatches), nameof(BuildingNAnimalMenuPatches.AnimalQueryMenuPatch))
|
postfix: new HarmonyMethod(typeof(AnimalQueryMenuPatch), nameof(AnimalQueryMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -255,24 +251,29 @@ namespace stardew_access
|
||||||
#region Donation Menus
|
#region Donation Menus
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(MuseumMenu), nameof(MuseumMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(MuseumMenu), nameof(MuseumMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(DonationMenuPatches), nameof(DonationMenuPatches.MuseumMenuPatch))
|
postfix: new HarmonyMethod(typeof(MuseumMenuPatch), nameof(MuseumMenuPatch.DrawPatch))
|
||||||
|
);
|
||||||
|
|
||||||
|
harmony.Patch(
|
||||||
|
original: AccessTools.Method(typeof(MuseumMenu), nameof(MuseumMenu.receiveKeyPress), new Type[] { typeof(Keys) }),
|
||||||
|
prefix: new HarmonyMethod(typeof(MuseumMenuPatch), nameof(MuseumMenuPatch.RecieveKeyPressPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(FieldOfficeMenu), nameof(FieldOfficeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(FieldOfficeMenu), nameof(FieldOfficeMenu.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(DonationMenuPatches), nameof(DonationMenuPatches.FieldOfficeMenuPatch))
|
postfix: new HarmonyMethod(typeof(FieldOfficeMenuPatch), nameof(FieldOfficeMenuPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Mini Games
|
#region Mini Games
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(Intro), nameof(Intro.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(Intro), nameof(Intro.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MiniGamesPatches), nameof(MiniGamesPatches.IntroPatch))
|
postfix: new HarmonyMethod(typeof(IntroPatch), nameof(IntroPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(GrandpaStory), nameof(GrandpaStory.draw), new Type[] { typeof(SpriteBatch) }),
|
original: AccessTools.Method(typeof(GrandpaStory), nameof(GrandpaStory.draw), new Type[] { typeof(SpriteBatch) }),
|
||||||
postfix: new HarmonyMethod(typeof(MiniGamesPatches), nameof(MiniGamesPatches.GrandpaStoryPatch))
|
postfix: new HarmonyMethod(typeof(GrandpaStoryPatch), nameof(GrandpaStoryPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
|
@ -284,12 +285,17 @@ namespace stardew_access
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(Game1), nameof(Game1.playSound)),
|
original: AccessTools.Method(typeof(Game1), nameof(Game1.playSound)),
|
||||||
prefix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.PlaySoundPatch))
|
prefix: new HarmonyMethod(typeof(Game1Patch), nameof(Game1Patch.PlaySoundPatch))
|
||||||
);
|
);
|
||||||
|
|
||||||
harmony.Patch(
|
harmony.Patch(
|
||||||
original: AccessTools.Method(typeof(InstanceGame), nameof(InstanceGame.Exit)),
|
original: AccessTools.Method(typeof(InstanceGame), nameof(InstanceGame.Exit)),
|
||||||
prefix: new HarmonyMethod(typeof(MenuPatches), nameof(MenuPatches.ExitEventPatch))
|
prefix: new HarmonyMethod(typeof(InstanceGamePatch), nameof(InstanceGamePatch.ExitPatch))
|
||||||
|
);
|
||||||
|
|
||||||
|
harmony.Patch(
|
||||||
|
original: AccessTools.Method(typeof(TextBox), nameof(TextBox.Draw)),
|
||||||
|
prefix: new HarmonyMethod(typeof(TextBoxPatch), nameof(TextBoxPatch.DrawPatch))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ namespace stardew_access
|
||||||
public Boolean Warning { get; set; } = true; // Toggles the warnings feature
|
public Boolean Warning { get; set; } = true; // Toggles the warnings feature
|
||||||
public Boolean TTS { get; set; } = true; // Toggles the screen reader/tts.
|
public Boolean TTS { get; set; } = true; // Toggles the screen reader/tts.
|
||||||
public Boolean TrackDroppedItems {get; set;} = true; // Toggles detecting the dropped items.
|
public Boolean TrackDroppedItems {get; set;} = true; // Toggles detecting the dropped items.
|
||||||
|
public Boolean DisableInventoryVerbosity {get; set;} = false; // If enabled, does not speaks 'not usable here' and 'donatable' in inventories
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public int MaximumFishingDifficulty { get; set; } = 999; // TODO Add doc
|
public int MaximumFishingDifficulty { get; set; } = 999; // TODO Add doc
|
||||||
|
|
|
@ -13,6 +13,7 @@ namespace stardew_access
|
||||||
public class MainClass : Mod
|
public class MainClass : Mod
|
||||||
{
|
{
|
||||||
#region Global Vars & Properties
|
#region Global Vars & Properties
|
||||||
|
|
||||||
#pragma warning disable CS8603
|
#pragma warning disable CS8603
|
||||||
private static int prevDate = -99;
|
private static int prevDate = -99;
|
||||||
private static ModConfig? config;
|
private static ModConfig? config;
|
||||||
|
@ -99,7 +100,6 @@ namespace stardew_access
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CS8603
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/*********
|
/*********
|
||||||
|
@ -128,14 +128,14 @@ namespace stardew_access
|
||||||
HarmonyPatches.Initialize(harmony);
|
HarmonyPatches.Initialize(harmony);
|
||||||
|
|
||||||
//Initialize marked locations
|
//Initialize marked locations
|
||||||
for (int i = 0; i < BuildingNAnimalMenuPatches.marked.Length; i++)
|
for (int i = 0; i < BuildingOperations.marked.Length; i++)
|
||||||
{
|
{
|
||||||
BuildingNAnimalMenuPatches.marked[i] = Vector2.Zero;
|
BuildingOperations.marked[i] = Vector2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < BuildingNAnimalMenuPatches.availableBuildings.Length; i++)
|
for (int i = 0; i < BuildingOperations.availableBuildings.Length; i++)
|
||||||
{
|
{
|
||||||
BuildingNAnimalMenuPatches.availableBuildings[i] = null;
|
BuildingOperations.availableBuildings[i] = null;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -210,54 +210,32 @@ namespace stardew_access
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#region Simulate left and right clicks
|
#region Simulate left and right clicks
|
||||||
if (Game1.activeClickableMenu != null)
|
if (Game1.activeClickableMenu != null && !TextBoxPatch.isAnyTextBoxActive)
|
||||||
{
|
{
|
||||||
bool isCustomizingCharacter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
|
bool isCustomizingCharacter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
|
||||||
|
|
||||||
#region Mouse Click Simulation
|
#region Mouse Click Simulation
|
||||||
// Main Keybinds
|
if (Config.LeftClickMainKey.JustPressed() || Config.LeftClickAlternateKey.JustPressed())
|
||||||
if (Config.LeftClickMainKey.JustPressed())
|
|
||||||
{
|
{
|
||||||
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||||
}
|
}
|
||||||
if (Config.RightClickMainKey.JustPressed())
|
|
||||||
{
|
|
||||||
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alternate Keybinds
|
if (Config.RightClickMainKey.JustPressed() || Config.RightClickAlternateKey.JustPressed())
|
||||||
if (!isCustomizingCharacter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.LeftClickAlternateKey.JustPressed()) // Excluding the character creation menu
|
|
||||||
{
|
|
||||||
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
|
||||||
}
|
|
||||||
if (!isCustomizingCharacter && Game1.activeClickableMenu is not AnimalQueryMenu && Config.RightClickAlternateKey.JustPressed()) // Excluding the character creation menu
|
|
||||||
{
|
{
|
||||||
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
Game1.activeClickableMenu.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Game1.currentMinigame != null)
|
if (Game1.currentMinigame != null && !TextBoxPatch.isAnyTextBoxActive)
|
||||||
{
|
{
|
||||||
bool isCustomizingCharacter = Game1.activeClickableMenu is CharacterCustomization || (TitleMenu.subMenu != null && TitleMenu.subMenu is CharacterCustomization);
|
|
||||||
|
|
||||||
#region Mouse Click Simulation
|
#region Mouse Click Simulation
|
||||||
// Main Keybinds
|
if (Config.LeftClickMainKey.JustPressed() || Config.LeftClickAlternateKey.JustPressed())
|
||||||
if (Config.LeftClickMainKey.JustPressed())
|
|
||||||
{
|
{
|
||||||
Game1.currentMinigame.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
Game1.currentMinigame.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||||
}
|
}
|
||||||
if (Config.RightClickMainKey.JustPressed())
|
|
||||||
{
|
|
||||||
Game1.currentMinigame.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alternate Keybinds
|
if (Config.RightClickMainKey.JustPressed() || Config.RightClickAlternateKey.JustPressed())
|
||||||
if (Config.LeftClickAlternateKey.JustPressed())
|
|
||||||
{
|
|
||||||
Game1.currentMinigame.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
|
||||||
}
|
|
||||||
if (Config.RightClickAlternateKey.JustPressed())
|
|
||||||
{
|
{
|
||||||
Game1.currentMinigame.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
Game1.currentMinigame.receiveRightClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,714 +0,0 @@
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using StardewValley;
|
|
||||||
using StardewValley.Buildings;
|
|
||||||
using StardewValley.Locations;
|
|
||||||
using StardewValley.Menus;
|
|
||||||
using StardewValley.Objects;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
|
||||||
{
|
|
||||||
internal class BuildingNAnimalMenuPatches
|
|
||||||
{
|
|
||||||
internal static Vector2[] marked = new Vector2[10];
|
|
||||||
internal static Building?[] availableBuildings = new Building[100];
|
|
||||||
internal static CarpenterMenu? carpenterMenu = null;
|
|
||||||
internal static bool isNarratingAnimalInfo = false;
|
|
||||||
internal static string animalQueryMenuQuery = " ";
|
|
||||||
internal static string carpenterMenuQuery = "", purchaseAnimalMenuQuery = "";
|
|
||||||
internal static bool isSayingBlueprintInfo = false;
|
|
||||||
internal static string prevBlueprintInfo = "";
|
|
||||||
internal static bool isOnFarm = false, isUpgrading = false, isDemolishing = false, isPainting = false, isConstructing = false, isMoving = false, isMagicalConstruction = false;
|
|
||||||
internal static bool firstTimeInNamingMenu = true;
|
|
||||||
internal static PurchaseAnimalsMenu? purchaseAnimalsMenu;
|
|
||||||
internal static AnimalQueryMenu? animalQueryMenu;
|
|
||||||
private static FarmAnimal? animalBeingPurchasedOrMoved = null;
|
|
||||||
|
|
||||||
internal static void AnimalQueryMenuPatch(AnimalQueryMenu __instance, bool ___confirmingSell, FarmAnimal ___animal, TextBox ___textBox, string ___parentName, bool ___movingAnimal)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); // For narrating animal details
|
|
||||||
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
|
||||||
string toSpeak = " ", details = " ";
|
|
||||||
|
|
||||||
isOnFarm = ___movingAnimal;
|
|
||||||
animalQueryMenu = __instance;
|
|
||||||
animalBeingPurchasedOrMoved = ___animal;
|
|
||||||
|
|
||||||
if (___textBox.Selected)
|
|
||||||
{
|
|
||||||
toSpeak = ___textBox.Text;
|
|
||||||
|
|
||||||
if (isEscPressed)
|
|
||||||
{
|
|
||||||
___textBox.Selected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (isPrimaryInfoKeyPressed & !isNarratingAnimalInfo)
|
|
||||||
{
|
|
||||||
string name = ___animal.displayName;
|
|
||||||
string type = ___animal.displayType;
|
|
||||||
int age = (___animal.GetDaysOwned() + 1) / 28 + 1;
|
|
||||||
string ageText = (age <= 1) ? Game1.content.LoadString("Strings\\UI:AnimalQuery_Age1") : Game1.content.LoadString("Strings\\UI:AnimalQuery_AgeN", age);
|
|
||||||
string parent = "";
|
|
||||||
if ((int)___animal.age.Value < (byte)___animal.ageWhenMature.Value)
|
|
||||||
{
|
|
||||||
ageText += Game1.content.LoadString("Strings\\UI:AnimalQuery_AgeBaby");
|
|
||||||
}
|
|
||||||
if (___parentName != null)
|
|
||||||
{
|
|
||||||
parent = Game1.content.LoadString("Strings\\UI:AnimalQuery_Parent", ___parentName);
|
|
||||||
}
|
|
||||||
|
|
||||||
details = $"Name: {name} Type: {type} \n\t Age: {ageText} {parent}";
|
|
||||||
animalQueryMenuQuery = " ";
|
|
||||||
|
|
||||||
isNarratingAnimalInfo = true;
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isNarratingAnimalInfo = false; });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
toSpeak = "OK button";
|
|
||||||
else if (__instance.sellButton != null && __instance.sellButton.containsPoint(x, y))
|
|
||||||
toSpeak = $"Sell for {___animal.getSellPrice()}g button";
|
|
||||||
else if (___confirmingSell && __instance.yesButton != null && __instance.yesButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Confirm selling animal";
|
|
||||||
else if (___confirmingSell && __instance.noButton != null && __instance.noButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Cancel selling animal";
|
|
||||||
else if (__instance.moveHomeButton != null && __instance.moveHomeButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Change home building button";
|
|
||||||
else if (__instance.allowReproductionButton != null && __instance.allowReproductionButton.containsPoint(x, y))
|
|
||||||
toSpeak = ((___animal.allowReproduction.Value) ? "Enabled" : "Disabled") + " allow reproduction button";
|
|
||||||
else if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
|
||||||
toSpeak = "Animal name text box";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (animalQueryMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
animalQueryMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say($"{details} {toSpeak}", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void PurchaseAnimalsMenuPatch(PurchaseAnimalsMenu __instance, bool ___onFarm, bool ___namingAnimal, TextBox ___textBox, FarmAnimal ___animalBeingPurchased)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
purchaseAnimalsMenu = __instance;
|
|
||||||
isOnFarm = ___onFarm;
|
|
||||||
animalBeingPurchasedOrMoved = ___animalBeingPurchased;
|
|
||||||
|
|
||||||
if (___onFarm && ___namingAnimal)
|
|
||||||
{
|
|
||||||
string toSpeak = "";
|
|
||||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Cancel Button";
|
|
||||||
}
|
|
||||||
else if (__instance.doneNamingButton != null && __instance.doneNamingButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "OK Button";
|
|
||||||
}
|
|
||||||
else if (__instance.randomButton != null && __instance.randomButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Random Name Button";
|
|
||||||
}
|
|
||||||
else if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Name Text Box";
|
|
||||||
string? value = ___textBox.Text;
|
|
||||||
if (value != "" && value != null && value != "null")
|
|
||||||
toSpeak = $"{toSpeak}, Value: {value}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (purchaseAnimalMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
purchaseAnimalMenuQuery = toSpeak;
|
|
||||||
|
|
||||||
if (firstTimeInNamingMenu)
|
|
||||||
{
|
|
||||||
toSpeak = $"Enter the name of animal in the name text box. {toSpeak}";
|
|
||||||
firstTimeInNamingMenu = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (___onFarm && !___namingAnimal)
|
|
||||||
{
|
|
||||||
firstTimeInNamingMenu = true;
|
|
||||||
}
|
|
||||||
else if (!___onFarm && !___namingAnimal)
|
|
||||||
{
|
|
||||||
firstTimeInNamingMenu = true;
|
|
||||||
if (__instance.hovered != null)
|
|
||||||
{
|
|
||||||
string toSpeak = "";
|
|
||||||
if (((StardewValley.Object)__instance.hovered.item).Type != null)
|
|
||||||
{
|
|
||||||
toSpeak = ((StardewValley.Object)__instance.hovered.item).Type;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string displayName = PurchaseAnimalsMenu.getAnimalTitle(__instance.hovered.hoverText);
|
|
||||||
int price = __instance.hovered.item.salePrice();
|
|
||||||
string description = PurchaseAnimalsMenu.getAnimalDescription(__instance.hovered.hoverText);
|
|
||||||
|
|
||||||
toSpeak = $"{displayName}, Price: {price}g, Description: {description}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (purchaseAnimalMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
purchaseAnimalMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void CarpenterMenuPatch(
|
|
||||||
CarpenterMenu __instance, bool ___onFarm, List<Item> ___ingredients, int ___price,
|
|
||||||
List<BluePrint> ___blueprints, int ___currentBlueprintIndex, bool ___upgrading, bool ___demolishing, bool ___moving,
|
|
||||||
bool ___painting, bool ___magicalConstruction)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
isOnFarm = ___onFarm;
|
|
||||||
carpenterMenu = __instance;
|
|
||||||
isMagicalConstruction = ___magicalConstruction;
|
|
||||||
if (!___onFarm)
|
|
||||||
{
|
|
||||||
isUpgrading = false;
|
|
||||||
isDemolishing = false;
|
|
||||||
isPainting = false;
|
|
||||||
isMoving = false;
|
|
||||||
isConstructing = false;
|
|
||||||
|
|
||||||
#region The blueprint menu
|
|
||||||
BluePrint currentBluprint = __instance.CurrentBlueprint;
|
|
||||||
if (currentBluprint == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
|
||||||
string ingredients = "";
|
|
||||||
string name = currentBluprint.displayName;
|
|
||||||
string upgradeName = currentBluprint.nameOfBuildingToUpgrade;
|
|
||||||
string description = currentBluprint.description;
|
|
||||||
string price = $"{___price}g";
|
|
||||||
string blueprintInfo;
|
|
||||||
int width = currentBluprint.tilesWidth;
|
|
||||||
int height = currentBluprint.tilesHeight;
|
|
||||||
|
|
||||||
#region Get ingredients
|
|
||||||
for (int i = 0; i < ___ingredients.Count; i++)
|
|
||||||
{
|
|
||||||
string itemName = ___ingredients[i].DisplayName;
|
|
||||||
int itemStack = ___ingredients[i].Stack;
|
|
||||||
string itemQuality = "";
|
|
||||||
|
|
||||||
int qualityValue = ((StardewValley.Object)___ingredients[i]).Quality;
|
|
||||||
if (qualityValue == 1)
|
|
||||||
{
|
|
||||||
itemQuality = "Silver quality";
|
|
||||||
}
|
|
||||||
else if (qualityValue == 2 || qualityValue == 3)
|
|
||||||
{
|
|
||||||
itemQuality = "Gold quality";
|
|
||||||
}
|
|
||||||
else if (qualityValue >= 4)
|
|
||||||
{
|
|
||||||
itemQuality = "Iridium quality";
|
|
||||||
}
|
|
||||||
|
|
||||||
ingredients = $"{ingredients}, {itemStack} {itemName} {itemQuality}";
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
blueprintInfo = $"{name}, Price: {price}, Ingredients: {ingredients}, Dimensions: {width} width and {height} height, Description: {description}";
|
|
||||||
|
|
||||||
if (isPrimaryInfoKeyPressed && !isSayingBlueprintInfo)
|
|
||||||
{
|
|
||||||
SayBlueprintInfo(blueprintInfo);
|
|
||||||
}
|
|
||||||
else if (prevBlueprintInfo != blueprintInfo)
|
|
||||||
{
|
|
||||||
prevBlueprintInfo = blueprintInfo;
|
|
||||||
SayBlueprintInfo(blueprintInfo);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Previous Blueprint";
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Next Blueprint";
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.demolishButton != null && __instance.demolishButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = $"Demolish Building" + (__instance.CanDemolishThis(___blueprints[___currentBlueprintIndex]) ? "" : ", cannot demolish building");
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Construct Building" + (___blueprints[___currentBlueprintIndex].doesFarmerHaveEnoughResourcesToBuild() ? "" : ", cannot cunstrut building, not enough resources to build.");
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.moveButton != null && __instance.moveButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Move Building";
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.paintButton != null && __instance.paintButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Paint Building";
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.cancelButton != null && __instance.cancelButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Cancel Button";
|
|
||||||
if (carpenterMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
carpenterMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (___demolishing)
|
|
||||||
isDemolishing = true;
|
|
||||||
else if (___upgrading)
|
|
||||||
isUpgrading = true;
|
|
||||||
else if (___painting)
|
|
||||||
isPainting = true;
|
|
||||||
else if (___moving)
|
|
||||||
isMoving = true;
|
|
||||||
else
|
|
||||||
isConstructing = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async void SayBlueprintInfo(string info)
|
|
||||||
{
|
|
||||||
isSayingBlueprintInfo = true;
|
|
||||||
MainClass.ScreenReader.Say(info, true);
|
|
||||||
await Task.Delay(300);
|
|
||||||
isSayingBlueprintInfo = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? Demolish(Building? toDemolish)
|
|
||||||
{
|
|
||||||
if (toDemolish == null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
string? response = null;
|
|
||||||
// This code is taken from the game's code (CarpenterMenu.cs::654)
|
|
||||||
Farm farm = (Farm)Game1.getLocationFromName("Farm");
|
|
||||||
Action buildingLockFailed = delegate
|
|
||||||
{
|
|
||||||
if (isDemolishing)
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_LockFailed");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Action continueDemolish = delegate
|
|
||||||
{
|
|
||||||
if (isDemolishing && toDemolish != null && farm.buildings.Contains(toDemolish))
|
|
||||||
{
|
|
||||||
if ((int)toDemolish.daysOfConstructionLeft.Value > 0 || (int)toDemolish.daysUntilUpgrade.Value > 0)
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_DuringConstruction");
|
|
||||||
}
|
|
||||||
else if (toDemolish.indoors.Value != null && toDemolish.indoors.Value is AnimalHouse && ((AnimalHouse)toDemolish.indoors.Value).animalsThatLiveHere.Count > 0)
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_AnimalsHere");
|
|
||||||
}
|
|
||||||
else if (toDemolish.indoors.Value != null && toDemolish.indoors.Value.farmers.Any())
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_PlayerHere");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (toDemolish.indoors.Value != null && toDemolish.indoors.Value is Cabin)
|
|
||||||
{
|
|
||||||
foreach (Farmer current in Game1.getAllFarmers())
|
|
||||||
{
|
|
||||||
if (current.currentLocation != null && current.currentLocation.Name == ((Cabin)toDemolish.indoors.Value).GetCellarName())
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_PlayerHere");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toDemolish.indoors.Value is Cabin && ((Cabin)toDemolish.indoors.Value).farmhand.Value.isActive())
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_FarmhandOnline");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toDemolish.BeforeDemolish();
|
|
||||||
Chest? chest = null;
|
|
||||||
if (toDemolish.indoors.Value is Cabin)
|
|
||||||
{
|
|
||||||
List<Item> list = ((Cabin)toDemolish.indoors.Value).demolish();
|
|
||||||
if (list.Count > 0)
|
|
||||||
{
|
|
||||||
chest = new Chest(playerChest: true);
|
|
||||||
chest.fixLidFrame();
|
|
||||||
chest.items.Set(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (farm.destroyStructure(toDemolish))
|
|
||||||
{
|
|
||||||
_ = (int)toDemolish.tileY.Value;
|
|
||||||
_ = (int)toDemolish.tilesHigh.Value;
|
|
||||||
Game1.flashAlpha = 1f;
|
|
||||||
toDemolish.showDestroyedAnimation(Game1.getFarm());
|
|
||||||
Game1.playSound("explosion");
|
|
||||||
Utility.spreadAnimalsAround(toDemolish, farm);
|
|
||||||
if (carpenterMenu != null)
|
|
||||||
DelayedAction.functionAfterDelay(carpenterMenu.returnToCarpentryMenu, 1500);
|
|
||||||
// freeze = true;
|
|
||||||
if (chest != null)
|
|
||||||
{
|
|
||||||
farm.objects[new Vector2((int)toDemolish.tileX.Value + (int)toDemolish.tilesWide.Value / 2, (int)toDemolish.tileY.Value + (int)toDemolish.tilesHigh.Value / 2)] = chest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (toDemolish != null)
|
|
||||||
{
|
|
||||||
if (toDemolish.indoors.Value != null && toDemolish.indoors.Value is Cabin && !Game1.IsMasterGame)
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantDemolish_LockFailed");
|
|
||||||
toDemolish = null;
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
if (carpenterMenu != null && !carpenterMenu.CanDemolishThis(toDemolish))
|
|
||||||
{
|
|
||||||
toDemolish = null;
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
if (carpenterMenu != null && !Game1.IsMasterGame && !carpenterMenu.hasPermissionsToDemolish(toDemolish))
|
|
||||||
{
|
|
||||||
toDemolish = null;
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toDemolish != null && toDemolish.indoors.Value is Cabin)
|
|
||||||
{
|
|
||||||
Cabin cabin = (Cabin)toDemolish.indoors.Value;
|
|
||||||
if (cabin.farmhand.Value != null && (bool)cabin.farmhand.Value.isCustomized.Value)
|
|
||||||
{
|
|
||||||
Game1.currentLocation.createQuestionDialogue(Game1.content.LoadString("Strings\\UI:Carpenter_DemolishCabinConfirm", cabin.farmhand.Value.Name), Game1.currentLocation.createYesNoResponses(), delegate (Farmer f, string answer)
|
|
||||||
{
|
|
||||||
if (answer == "Yes")
|
|
||||||
{
|
|
||||||
Game1.activeClickableMenu = carpenterMenu;
|
|
||||||
Game1.player.team.demolishLock.RequestLock(continueDemolish, buildingLockFailed);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (carpenterMenu != null)
|
|
||||||
DelayedAction.functionAfterDelay(carpenterMenu.returnToCarpentryMenu, 1000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (toDemolish != null)
|
|
||||||
{
|
|
||||||
Game1.player.team.demolishLock.RequestLock(continueDemolish, buildingLockFailed);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? Contstruct(Vector2 position)
|
|
||||||
{
|
|
||||||
string? response = null;
|
|
||||||
// This code is taken from the game's code (CarpenterMenu.cs::874)
|
|
||||||
Game1.player.team.buildLock.RequestLock(delegate
|
|
||||||
{
|
|
||||||
if (isOnFarm && Game1.locationRequest == null)
|
|
||||||
{
|
|
||||||
if (tryToBuild(position))
|
|
||||||
{
|
|
||||||
if (carpenterMenu != null)
|
|
||||||
{
|
|
||||||
carpenterMenu.CurrentBlueprint.consumeResources();
|
|
||||||
DelayedAction.functionAfterDelay(carpenterMenu.returnToCarpentryMenuAfterSuccessfulBuild, 2000);
|
|
||||||
}
|
|
||||||
// freeze = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantBuild");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Game1.player.team.buildLock.ReleaseLock();
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool tryToBuild(Vector2 position)
|
|
||||||
{
|
|
||||||
if (carpenterMenu == null)
|
|
||||||
return false;
|
|
||||||
return ((Farm)Game1.getLocationFromName("Farm")).buildStructure(carpenterMenu.CurrentBlueprint, position, Game1.player, isMagicalConstruction);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? Upgrade(Building? toUpgrade)
|
|
||||||
{
|
|
||||||
string? response = null;
|
|
||||||
// This code is taken from the game's code (CarpenterMenu.cs::775)
|
|
||||||
if (carpenterMenu != null && toUpgrade != null && carpenterMenu.CurrentBlueprint.name != null && toUpgrade.buildingType.Equals(carpenterMenu.CurrentBlueprint.nameOfBuildingToUpgrade))
|
|
||||||
{
|
|
||||||
carpenterMenu.CurrentBlueprint.consumeResources();
|
|
||||||
toUpgrade.daysUntilUpgrade.Value = 2;
|
|
||||||
toUpgrade.showUpgradeAnimation(Game1.getFarm());
|
|
||||||
Game1.playSound("axe");
|
|
||||||
DelayedAction.functionAfterDelay(carpenterMenu.returnToCarpentryMenuAfterSuccessfulBuild, 1500);
|
|
||||||
// freeze = true;
|
|
||||||
// Game1.multiplayer.globalChatInfoMessage("BuildingBuild", Game1.player.Name, Utility.AOrAn(carpenterMenu.CurrentBlueprint.displayName), carpenterMenu.CurrentBlueprint.displayName, Game1.player.farmName.Value);
|
|
||||||
}
|
|
||||||
else if (toUpgrade != null)
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CantUpgrade_BuildingType");
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? Paint(Building? toPaint)
|
|
||||||
{
|
|
||||||
string? response = null;
|
|
||||||
// This code is taken from the game's code (CarpenterMenu.cs::793)
|
|
||||||
Farm farm_location = Game1.getFarm();
|
|
||||||
if (toPaint != null)
|
|
||||||
{
|
|
||||||
if (!toPaint.CanBePainted())
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint");
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
if (carpenterMenu != null && !carpenterMenu.HasPermissionsToPaint(toPaint))
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint_Permission");
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
toPaint.color.Value = Color.White;
|
|
||||||
|
|
||||||
if (carpenterMenu != null)
|
|
||||||
carpenterMenu.SetChildMenu(new BuildingPaintMenu(toPaint));
|
|
||||||
}
|
|
||||||
/* TODO Add painting of farm house
|
|
||||||
else if (farm_location.GetHouseRect().Contains(Utility.Vector2ToPoint(new Vector2(toPaint.tileX, toPaint.tileY))))
|
|
||||||
{
|
|
||||||
if (!carpenterMenu.CanPaintHouse())
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint");
|
|
||||||
}
|
|
||||||
else if (!carpenterMenu.HasPermissionsToPaint(null))
|
|
||||||
{
|
|
||||||
response = Game1.content.LoadString("Strings\\UI:Carpenter_CannotPaint_Permission");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
carpenterMenu.SetChildMenu(new BuildingPaintMenu("House", () => (farm_location.paintedHouseTexture != null) ? farm_location.paintedHouseTexture : Farm.houseTextures, farm_location.houseSource.Value, farm_location.housePaintColor.Value));
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string? Move(Building? buildingToMove, Vector2 position)
|
|
||||||
{
|
|
||||||
string? response = null;
|
|
||||||
// This code is taken from the game's code (CarpenterMenu.cs::829)
|
|
||||||
if (buildingToMove != null)
|
|
||||||
{
|
|
||||||
string? name = buildingToMove.nameOfIndoorsWithoutUnique;
|
|
||||||
name = (name == "null") ? buildingToMove.buildingType.Value : name;
|
|
||||||
|
|
||||||
if ((int)buildingToMove.daysOfConstructionLeft.Value > 0)
|
|
||||||
{
|
|
||||||
buildingToMove = null;
|
|
||||||
return "Building under construction, cannot move";
|
|
||||||
}
|
|
||||||
if (carpenterMenu != null && !carpenterMenu.hasPermissionsToMove(buildingToMove))
|
|
||||||
{
|
|
||||||
buildingToMove = null;
|
|
||||||
return "You don't have permission to move this building";
|
|
||||||
}
|
|
||||||
Game1.playSound("axchop");
|
|
||||||
|
|
||||||
if (((Farm)Game1.getLocationFromName("Farm")).buildStructure(buildingToMove, position, Game1.player))
|
|
||||||
{
|
|
||||||
if (buildingToMove is ShippingBin)
|
|
||||||
{
|
|
||||||
((ShippingBin)buildingToMove).initLid();
|
|
||||||
}
|
|
||||||
if (buildingToMove is GreenhouseBuilding)
|
|
||||||
{
|
|
||||||
Game1.getFarm().greenhouseMoved.Value = true;
|
|
||||||
}
|
|
||||||
buildingToMove.performActionOnBuildingPlacement();
|
|
||||||
buildingToMove = null;
|
|
||||||
Game1.playSound("axchop");
|
|
||||||
DelayedAction.playSoundAfterDelay("dirtyHit", 50);
|
|
||||||
DelayedAction.playSoundAfterDelay("dirtyHit", 150);
|
|
||||||
|
|
||||||
response = $"{buildingToMove} moved to {position.X}x {position.Y}y";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Game1.playSound("cancel");
|
|
||||||
response = $"Cannot move building to {position.X}x {position.Y}y";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void PurchaseAnimal(Building? selection)
|
|
||||||
{
|
|
||||||
if (selection == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (purchaseAnimalsMenu == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int x = (selection.tileX.Value * Game1.tileSize) - Game1.viewport.X;
|
|
||||||
int y = (selection.tileY.Value * Game1.tileSize) - Game1.viewport.Y;
|
|
||||||
|
|
||||||
if (animalBeingPurchasedOrMoved != null && !selection.buildingType.Value.Contains(animalBeingPurchasedOrMoved.buildingTypeILiveIn.Value))
|
|
||||||
{
|
|
||||||
string warn = Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11326", animalBeingPurchasedOrMoved.displayType);
|
|
||||||
MainClass.ScreenReader.Say(warn, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((AnimalHouse)selection.indoors.Value).isFull())
|
|
||||||
{
|
|
||||||
string warn = Game1.content.LoadString("Strings\\StringsFromCSFiles:PurchaseAnimalsMenu.cs.11321");
|
|
||||||
MainClass.ScreenReader.Say(warn, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
purchaseAnimalsMenu.receiveLeftClick(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void MoveAnimal(Building? selection)
|
|
||||||
{
|
|
||||||
if (selection == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (animalQueryMenu == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (animalBeingPurchasedOrMoved == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// The following code is taken from the game's source code [AnimalQueryMenu.cs::receiveLeftClick]
|
|
||||||
if (selection.buildingType.Value.Contains(animalBeingPurchasedOrMoved.buildingTypeILiveIn.Value))
|
|
||||||
{
|
|
||||||
if (((AnimalHouse)selection.indoors.Value).isFull())
|
|
||||||
{
|
|
||||||
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_BuildingFull");
|
|
||||||
MainClass.ScreenReader.Say(warn, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (selection.Equals(animalBeingPurchasedOrMoved.home))
|
|
||||||
{
|
|
||||||
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_AlreadyHome");
|
|
||||||
MainClass.ScreenReader.Say(warn, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
((AnimalHouse)animalBeingPurchasedOrMoved.home.indoors.Value).animalsThatLiveHere.Remove(animalBeingPurchasedOrMoved.myID.Value);
|
|
||||||
if (((AnimalHouse)animalBeingPurchasedOrMoved.home.indoors.Value).animals.ContainsKey(animalBeingPurchasedOrMoved.myID.Value))
|
|
||||||
{
|
|
||||||
((AnimalHouse)selection.indoors.Value).animals.Add(animalBeingPurchasedOrMoved.myID.Value, animalBeingPurchasedOrMoved);
|
|
||||||
((AnimalHouse)animalBeingPurchasedOrMoved.home.indoors.Value).animals.Remove(animalBeingPurchasedOrMoved.myID.Value);
|
|
||||||
}
|
|
||||||
animalBeingPurchasedOrMoved.home = selection;
|
|
||||||
animalBeingPurchasedOrMoved.homeLocation.Value = new Vector2((int)selection.tileX.Value, (int)selection.tileY.Value);
|
|
||||||
((AnimalHouse)selection.indoors.Value).animalsThatLiveHere.Add(animalBeingPurchasedOrMoved.myID.Value);
|
|
||||||
animalBeingPurchasedOrMoved.makeSound();
|
|
||||||
Game1.globalFadeToBlack(animalQueryMenu.finishedPlacingAnimal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string warn = Game1.content.LoadString("Strings\\UI:AnimalQuery_Moving_CantLiveThere");
|
|
||||||
MainClass.ScreenReader.Say(warn, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,360 +0,0 @@
|
||||||
using StardewValley;
|
|
||||||
using StardewValley.Locations;
|
|
||||||
using StardewValley.Menus;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
|
||||||
{
|
|
||||||
internal class BundleMenuPatches
|
|
||||||
{
|
|
||||||
internal static string junimoNoteMenuQuery = "";
|
|
||||||
internal static string currentJunimoArea = "";
|
|
||||||
internal static string jojaCDMenuQuery = "";
|
|
||||||
internal static bool isUsingCustomButtons = false;
|
|
||||||
internal static int currentIngredientListItem = -1, currentIngredientInputSlot = -1, currentInventorySlot = -1;
|
|
||||||
|
|
||||||
#region Joja Mart Bundle/Quests
|
|
||||||
internal static void JojaCDMenuPatch(JojaCDMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = "";
|
|
||||||
|
|
||||||
for (int i = 0; i < __instance.checkboxes.Count; i++)
|
|
||||||
{
|
|
||||||
ClickableComponent c = __instance.checkboxes[i];
|
|
||||||
if (!c.containsPoint(x, y))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (c.name.Equals("complete"))
|
|
||||||
{
|
|
||||||
toSpeak = $"Completed {getNameFromIndex(i)}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toSpeak = $"{getNameFromIndex(i)} Cost: {__instance.getPriceFromButtonNumber(i)}g Description: {__instance.getDescriptionFromButtonNumber(i)}";
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jojaCDMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
jojaCDMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string getNameFromIndex(int i)
|
|
||||||
{
|
|
||||||
string name = i switch
|
|
||||||
{
|
|
||||||
0 => "Bus",
|
|
||||||
1 => "Minecarts",
|
|
||||||
2 => "Bridge",
|
|
||||||
3 => "Greenhouse",
|
|
||||||
4 => "Panning",
|
|
||||||
_ => "",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (name != "")
|
|
||||||
return $"{name} Project";
|
|
||||||
else
|
|
||||||
return "unkown";
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Community Center Bundles
|
|
||||||
internal static void JunimoNoteMenuPatch(JunimoNoteMenu __instance, bool ___specificBundlePage, int ___whichArea, Bundle ___currentPageBundle)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
if (!___specificBundlePage)
|
|
||||||
{
|
|
||||||
currentIngredientListItem = -1;
|
|
||||||
isUsingCustomButtons = false;
|
|
||||||
|
|
||||||
string areaName = __instance.scrambledText ? CommunityCenter.getAreaEnglishDisplayNameFromNumber(___whichArea) : CommunityCenter.getAreaDisplayNameFromNumber(___whichArea);
|
|
||||||
string reward = __instance.getRewardNameForArea(___whichArea);
|
|
||||||
|
|
||||||
if (__instance.scrambledText)
|
|
||||||
{
|
|
||||||
string toSpeak = "Scrambled Text";
|
|
||||||
if (junimoNoteMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
junimoNoteMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentJunimoArea != areaName)
|
|
||||||
{
|
|
||||||
currentJunimoArea = areaName;
|
|
||||||
MainClass.ScreenReader.Say($"Area {areaName}, {reward}", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < __instance.bundles.Count; i++)
|
|
||||||
{
|
|
||||||
if (__instance.bundles[i].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = $"{__instance.bundles[i].name} bundle";
|
|
||||||
if (junimoNoteMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
junimoNoteMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (__instance.presentButton != null && __instance.presentButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Present Button";
|
|
||||||
if (junimoNoteMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
junimoNoteMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (__instance.fromGameMenu)
|
|
||||||
{
|
|
||||||
if (__instance.areaNextButton.visible && __instance.areaNextButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Next Area Button";
|
|
||||||
if (junimoNoteMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
junimoNoteMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (__instance.areaBackButton.visible && __instance.areaBackButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "Previous Area Button";
|
|
||||||
if (junimoNoteMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
junimoNoteMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool isIPressed = MainClass.Config.BundleMenuIngredientsKey.JustPressed(); // For the ingredients
|
|
||||||
bool isCPressed = MainClass.Config.BundleMenuInventoryItemsKey.JustPressed(); // For the items in inventory
|
|
||||||
bool isPPressed = MainClass.Config.BundleMenuPurchaseButtonKey.JustPressed(); // For the Purchase Button
|
|
||||||
bool isVPressed = MainClass.Config.BundleMenuIngredientsInputSlotKey.JustPressed(); // For the ingredient input slots
|
|
||||||
bool isBackPressed = MainClass.Config.BundleMenuBackButtonKey.JustPressed(); // For the back button
|
|
||||||
bool isLeftShiftPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift);
|
|
||||||
|
|
||||||
if (isIPressed && !isUsingCustomButtons)
|
|
||||||
{
|
|
||||||
isUsingCustomButtons = true;
|
|
||||||
JunimoNoteCustomButtons(__instance, ___currentPageBundle, 0, isLeftShiftPressed);
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isUsingCustomButtons = false; });
|
|
||||||
}
|
|
||||||
else if (isVPressed && !isUsingCustomButtons)
|
|
||||||
{
|
|
||||||
isUsingCustomButtons = true;
|
|
||||||
JunimoNoteCustomButtons(__instance, ___currentPageBundle, 1, isLeftShiftPressed);
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isUsingCustomButtons = false; });
|
|
||||||
}
|
|
||||||
else if (isCPressed && !isUsingCustomButtons)
|
|
||||||
{
|
|
||||||
isUsingCustomButtons = true;
|
|
||||||
JunimoNoteCustomButtons(__instance, ___currentPageBundle, 2, isLeftShiftPressed);
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isUsingCustomButtons = false; });
|
|
||||||
}
|
|
||||||
else if (isBackPressed && __instance.backButton != null && !__instance.backButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
__instance.backButton.snapMouseCursorToCenter();
|
|
||||||
MainClass.ScreenReader.Say("Back Button", true);
|
|
||||||
}
|
|
||||||
else if (isPPressed && __instance.purchaseButton != null && !__instance.purchaseButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
__instance.purchaseButton.snapMouseCursorToCenter();
|
|
||||||
MainClass.ScreenReader.Say("Purchase Button", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void JunimoNoteCustomButtons(JunimoNoteMenu __instance, Bundle ___currentPageBundle, int signal, bool isLeftShiftPressed = false)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
switch (signal)
|
|
||||||
{
|
|
||||||
case 0: // For ingredient list
|
|
||||||
{
|
|
||||||
if (___currentPageBundle.ingredients.Count >= 0)
|
|
||||||
{
|
|
||||||
currentIngredientListItem = currentIngredientListItem + (isLeftShiftPressed ? -1 : 1);
|
|
||||||
if (currentIngredientListItem >= ___currentPageBundle.ingredients.Count)
|
|
||||||
if (isLeftShiftPressed)
|
|
||||||
currentIngredientListItem = ___currentPageBundle.ingredients.Count - 1;
|
|
||||||
else
|
|
||||||
currentIngredientListItem = 0;
|
|
||||||
|
|
||||||
if (currentIngredientListItem < 0)
|
|
||||||
if (isLeftShiftPressed)
|
|
||||||
currentIngredientListItem = ___currentPageBundle.ingredients.Count - 1;
|
|
||||||
else
|
|
||||||
currentIngredientListItem = 0;
|
|
||||||
|
|
||||||
ClickableTextureComponent c = __instance.ingredientList[currentIngredientListItem];
|
|
||||||
BundleIngredientDescription ingredient = ___currentPageBundle.ingredients[currentIngredientListItem];
|
|
||||||
|
|
||||||
Item item = new StardewValley.Object(ingredient.index, ingredient.stack, isRecipe: false, -1, ingredient.quality);
|
|
||||||
bool completed = false;
|
|
||||||
if (___currentPageBundle != null && ___currentPageBundle.ingredients != null && currentIngredientListItem < ___currentPageBundle.ingredients.Count && ___currentPageBundle.ingredients[currentIngredientListItem].completed)
|
|
||||||
{
|
|
||||||
completed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string toSpeak = item.DisplayName;
|
|
||||||
|
|
||||||
if (!completed)
|
|
||||||
{
|
|
||||||
int quality = ingredient.quality;
|
|
||||||
if (quality == 1)
|
|
||||||
{
|
|
||||||
toSpeak = $"Silver quality {toSpeak}";
|
|
||||||
}
|
|
||||||
else if (quality == 2 || quality == 3)
|
|
||||||
{
|
|
||||||
toSpeak = $"Gold quality {toSpeak}";
|
|
||||||
}
|
|
||||||
else if (quality >= 4)
|
|
||||||
{
|
|
||||||
toSpeak = $"Iridium quality {toSpeak}";
|
|
||||||
}
|
|
||||||
|
|
||||||
toSpeak = $"{ingredient.stack} {toSpeak}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (completed)
|
|
||||||
toSpeak = $"Completed {toSpeak}";
|
|
||||||
|
|
||||||
c.snapMouseCursorToCenter();
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 1: // For input slot list
|
|
||||||
{
|
|
||||||
if (__instance.ingredientSlots.Count >= 0)
|
|
||||||
{
|
|
||||||
currentIngredientInputSlot = currentIngredientInputSlot + (isLeftShiftPressed ? -1 : 1);
|
|
||||||
if (currentIngredientInputSlot >= __instance.ingredientSlots.Count)
|
|
||||||
if (isLeftShiftPressed)
|
|
||||||
currentIngredientInputSlot = __instance.ingredientSlots.Count - 1;
|
|
||||||
else
|
|
||||||
currentIngredientInputSlot = 0;
|
|
||||||
|
|
||||||
if (currentIngredientInputSlot < 0)
|
|
||||||
if (isLeftShiftPressed)
|
|
||||||
currentIngredientInputSlot = __instance.ingredientSlots.Count - 1;
|
|
||||||
else
|
|
||||||
currentIngredientInputSlot = 0;
|
|
||||||
|
|
||||||
ClickableTextureComponent c = __instance.ingredientSlots[currentIngredientInputSlot];
|
|
||||||
Item item = c.item;
|
|
||||||
string toSpeak;
|
|
||||||
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
toSpeak = $"Input Slot {currentIngredientInputSlot + 1}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toSpeak = item.DisplayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
c.snapMouseCursorToCenter();
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2: // For inventory slots
|
|
||||||
{
|
|
||||||
if (__instance.inventory != null && __instance.inventory.actualInventory.Count >= 0)
|
|
||||||
{
|
|
||||||
int prevSlotIndex = currentInventorySlot;
|
|
||||||
currentInventorySlot = currentInventorySlot + (isLeftShiftPressed ? -1 : 1);
|
|
||||||
if (currentInventorySlot >= __instance.inventory.actualInventory.Count)
|
|
||||||
if (isLeftShiftPressed)
|
|
||||||
currentInventorySlot = __instance.inventory.actualInventory.Count - 1;
|
|
||||||
else
|
|
||||||
currentInventorySlot = 0;
|
|
||||||
|
|
||||||
if (currentInventorySlot < 0)
|
|
||||||
if (isLeftShiftPressed)
|
|
||||||
currentInventorySlot = __instance.inventory.actualInventory.Count - 1;
|
|
||||||
else
|
|
||||||
currentInventorySlot = 0;
|
|
||||||
|
|
||||||
Item item = __instance.inventory.actualInventory[currentInventorySlot];
|
|
||||||
ClickableComponent c = __instance.inventory.inventory[currentInventorySlot];
|
|
||||||
string toSpeak;
|
|
||||||
if (item != null)
|
|
||||||
{
|
|
||||||
toSpeak = item.DisplayName;
|
|
||||||
|
|
||||||
if ((item as StardewValley.Object) != null)
|
|
||||||
{
|
|
||||||
int quality = ((StardewValley.Object)item).Quality;
|
|
||||||
if (quality == 1)
|
|
||||||
{
|
|
||||||
toSpeak = $"Silver quality {toSpeak}";
|
|
||||||
}
|
|
||||||
else if (quality == 2 || quality == 3)
|
|
||||||
{
|
|
||||||
toSpeak = $"Gold quality {toSpeak}";
|
|
||||||
}
|
|
||||||
else if (quality >= 4)
|
|
||||||
{
|
|
||||||
toSpeak = $"Iridium quality {toSpeak}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
toSpeak = $"{item.Stack} {toSpeak}";
|
|
||||||
|
|
||||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[currentInventorySlot]))
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} not usable here";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toSpeak = "Empty Slot";
|
|
||||||
}
|
|
||||||
c.snapMouseCursorToCenter();
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class JojaCDMenuPatch
|
||||||
|
{
|
||||||
|
internal static string jojaCDMenuQuery = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(JojaCDMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < __instance.checkboxes.Count; i++)
|
||||||
|
{
|
||||||
|
ClickableComponent c = __instance.checkboxes[i];
|
||||||
|
if (!c.containsPoint(x, y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (c.name.Equals("complete"))
|
||||||
|
{
|
||||||
|
toSpeak = $"Completed {getNameFromIndex(i)}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toSpeak = $"{getNameFromIndex(i)} Cost: {__instance.getPriceFromButtonNumber(i)}g Description: {__instance.getDescriptionFromButtonNumber(i)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jojaCDMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
jojaCDMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string getNameFromIndex(int i)
|
||||||
|
{
|
||||||
|
string name = i switch
|
||||||
|
{
|
||||||
|
0 => "Bus",
|
||||||
|
1 => "Minecarts",
|
||||||
|
2 => "Bridge",
|
||||||
|
3 => "Greenhouse",
|
||||||
|
4 => "Panning",
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (name != "")
|
||||||
|
return $"{name} Project";
|
||||||
|
else
|
||||||
|
return "unkown";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
jojaCDMenuQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,297 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Locations;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class JunimoNoteMenuPatch
|
||||||
|
{
|
||||||
|
internal static string junimoNoteMenuQuery = "";
|
||||||
|
internal static string currentJunimoArea = "";
|
||||||
|
internal static bool isUsingCustomKeyBinds = false;
|
||||||
|
internal static int currentIngredientListItem = -1, currentIngredientInputSlot = -1, currentInventorySlot = -1;
|
||||||
|
|
||||||
|
internal static void DrawPatch(JunimoNoteMenu __instance, bool ___specificBundlePage, int ___whichArea, Bundle ___currentPageBundle)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (narrateJunimoArea(__instance, ___specificBundlePage, ___whichArea, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
narrateBundlePage(__instance, ___specificBundlePage, ___currentPageBundle, x, y);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateJunimoArea(JunimoNoteMenu __instance, bool ___specificBundlePage, int ___whichArea, int x, int y)
|
||||||
|
{
|
||||||
|
if (___specificBundlePage)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentIngredientListItem = -1;
|
||||||
|
isUsingCustomKeyBinds = false;
|
||||||
|
|
||||||
|
string areaName = __instance.scrambledText ? CommunityCenter.getAreaEnglishDisplayNameFromNumber(___whichArea) : CommunityCenter.getAreaDisplayNameFromNumber(___whichArea);
|
||||||
|
string reward = __instance.getRewardNameForArea(___whichArea);
|
||||||
|
|
||||||
|
if (__instance.scrambledText)
|
||||||
|
{
|
||||||
|
string scrambledText = "Scrambled Text";
|
||||||
|
if (junimoNoteMenuQuery != scrambledText)
|
||||||
|
{
|
||||||
|
junimoNoteMenuQuery = scrambledText;
|
||||||
|
MainClass.ScreenReader.Say(scrambledText, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentJunimoArea != areaName)
|
||||||
|
{
|
||||||
|
currentJunimoArea = areaName;
|
||||||
|
MainClass.ScreenReader.Say($"Area {areaName}, {reward}", true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string toSpeak = "";
|
||||||
|
if (__instance.presentButton != null && __instance.presentButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Present Button";
|
||||||
|
}
|
||||||
|
else if (__instance.fromGameMenu && __instance.areaNextButton.visible && __instance.areaNextButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Next Area Button";
|
||||||
|
}
|
||||||
|
else if (__instance.fromGameMenu && __instance.areaBackButton.visible && __instance.areaBackButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Previous Area Button";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < __instance.bundles.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.bundles[i].containsPoint(x, y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
toSpeak = $"{__instance.bundles[i].name} bundle";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (junimoNoteMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
junimoNoteMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateBundlePage(JunimoNoteMenu __instance, bool ___specificBundlePage, Bundle ___currentPageBundle, int x, int y)
|
||||||
|
{
|
||||||
|
if (!___specificBundlePage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool isIPressed = MainClass.Config.BundleMenuIngredientsKey.JustPressed(); // For the ingredients
|
||||||
|
bool isCPressed = MainClass.Config.BundleMenuInventoryItemsKey.JustPressed(); // For the items in inventory
|
||||||
|
bool isPPressed = MainClass.Config.BundleMenuPurchaseButtonKey.JustPressed(); // For the Purchase Button
|
||||||
|
bool isVPressed = MainClass.Config.BundleMenuIngredientsInputSlotKey.JustPressed(); // For the ingredient input slots
|
||||||
|
bool isBackPressed = MainClass.Config.BundleMenuBackButtonKey.JustPressed(); // For the back button
|
||||||
|
bool isLeftShiftPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.LeftShift);
|
||||||
|
|
||||||
|
if (isIPressed && !isUsingCustomKeyBinds)
|
||||||
|
{
|
||||||
|
isUsingCustomKeyBinds = true;
|
||||||
|
cycleThroughIngredientList(__instance, ___currentPageBundle, isLeftShiftPressed);
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isUsingCustomKeyBinds = false; });
|
||||||
|
}
|
||||||
|
else if (isVPressed && !isUsingCustomKeyBinds)
|
||||||
|
{
|
||||||
|
isUsingCustomKeyBinds = true;
|
||||||
|
cycleThroughInputSlots(__instance, ___currentPageBundle, isLeftShiftPressed);
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isUsingCustomKeyBinds = false; });
|
||||||
|
}
|
||||||
|
else if (isCPressed && !isUsingCustomKeyBinds)
|
||||||
|
{
|
||||||
|
isUsingCustomKeyBinds = true;
|
||||||
|
cycleThroughInventorySlots(__instance, ___currentPageBundle, isLeftShiftPressed);
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isUsingCustomKeyBinds = false; });
|
||||||
|
}
|
||||||
|
else if (isBackPressed && __instance.backButton != null && !__instance.backButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
__instance.backButton.snapMouseCursorToCenter();
|
||||||
|
MainClass.ScreenReader.Say("Back Button", true);
|
||||||
|
}
|
||||||
|
else if (isPPressed && __instance.purchaseButton != null && !__instance.purchaseButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
__instance.purchaseButton.snapMouseCursorToCenter();
|
||||||
|
MainClass.ScreenReader.Say("Purchase Button", true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cycleThroughIngredientList(JunimoNoteMenu __instance, Bundle ___currentPageBundle, bool isLeftShiftPressed = false)
|
||||||
|
{
|
||||||
|
if (___currentPageBundle.ingredients.Count < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
currentIngredientListItem = currentIngredientListItem + (isLeftShiftPressed ? -1 : 1);
|
||||||
|
if (currentIngredientListItem >= ___currentPageBundle.ingredients.Count)
|
||||||
|
if (isLeftShiftPressed)
|
||||||
|
currentIngredientListItem = ___currentPageBundle.ingredients.Count - 1;
|
||||||
|
else
|
||||||
|
currentIngredientListItem = 0;
|
||||||
|
|
||||||
|
if (currentIngredientListItem < 0)
|
||||||
|
if (isLeftShiftPressed)
|
||||||
|
currentIngredientListItem = ___currentPageBundle.ingredients.Count - 1;
|
||||||
|
else
|
||||||
|
currentIngredientListItem = 0;
|
||||||
|
|
||||||
|
ClickableTextureComponent c = __instance.ingredientList[currentIngredientListItem];
|
||||||
|
BundleIngredientDescription ingredient = ___currentPageBundle.ingredients[currentIngredientListItem];
|
||||||
|
|
||||||
|
Item item = new StardewValley.Object(ingredient.index, ingredient.stack, isRecipe: false, -1, ingredient.quality);
|
||||||
|
bool completed = false;
|
||||||
|
if (___currentPageBundle != null && ___currentPageBundle.ingredients != null && currentIngredientListItem < ___currentPageBundle.ingredients.Count && ___currentPageBundle.ingredients[currentIngredientListItem].completed)
|
||||||
|
{
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string toSpeak = item.DisplayName;
|
||||||
|
|
||||||
|
if (completed)
|
||||||
|
{
|
||||||
|
toSpeak = $"Completed {toSpeak}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int quality = ingredient.quality;
|
||||||
|
if (quality == 1)
|
||||||
|
{
|
||||||
|
toSpeak = $"Silver quality {toSpeak}";
|
||||||
|
}
|
||||||
|
else if (quality == 2 || quality == 3)
|
||||||
|
{
|
||||||
|
toSpeak = $"Gold quality {toSpeak}";
|
||||||
|
}
|
||||||
|
else if (quality >= 4)
|
||||||
|
{
|
||||||
|
toSpeak = $"Iridium quality {toSpeak}";
|
||||||
|
}
|
||||||
|
|
||||||
|
toSpeak = $"{ingredient.stack} {toSpeak}";
|
||||||
|
}
|
||||||
|
|
||||||
|
c.snapMouseCursorToCenter();
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cycleThroughInputSlots(JunimoNoteMenu __instance, Bundle ___currentPageBundle, bool isLeftShiftPressed = false)
|
||||||
|
{
|
||||||
|
if (__instance.ingredientSlots.Count < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
currentIngredientInputSlot = currentIngredientInputSlot + (isLeftShiftPressed ? -1 : 1);
|
||||||
|
if (currentIngredientInputSlot >= __instance.ingredientSlots.Count)
|
||||||
|
if (isLeftShiftPressed)
|
||||||
|
currentIngredientInputSlot = __instance.ingredientSlots.Count - 1;
|
||||||
|
else
|
||||||
|
currentIngredientInputSlot = 0;
|
||||||
|
|
||||||
|
if (currentIngredientInputSlot < 0)
|
||||||
|
if (isLeftShiftPressed)
|
||||||
|
currentIngredientInputSlot = __instance.ingredientSlots.Count - 1;
|
||||||
|
else
|
||||||
|
currentIngredientInputSlot = 0;
|
||||||
|
|
||||||
|
ClickableTextureComponent c = __instance.ingredientSlots[currentIngredientInputSlot];
|
||||||
|
Item item = c.item;
|
||||||
|
string toSpeak;
|
||||||
|
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
toSpeak = $"Input Slot {currentIngredientInputSlot + 1}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toSpeak = item.DisplayName;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.snapMouseCursorToCenter();
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void cycleThroughInventorySlots(JunimoNoteMenu __instance, Bundle ___currentPageBundle, bool isLeftShiftPressed = false)
|
||||||
|
{
|
||||||
|
if (__instance.inventory == null || __instance.inventory.actualInventory.Count < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int prevSlotIndex = currentInventorySlot;
|
||||||
|
currentInventorySlot = currentInventorySlot + (isLeftShiftPressed ? -1 : 1);
|
||||||
|
if (currentInventorySlot >= __instance.inventory.actualInventory.Count)
|
||||||
|
if (isLeftShiftPressed)
|
||||||
|
currentInventorySlot = __instance.inventory.actualInventory.Count - 1;
|
||||||
|
else
|
||||||
|
currentInventorySlot = 0;
|
||||||
|
|
||||||
|
if (currentInventorySlot < 0)
|
||||||
|
if (isLeftShiftPressed)
|
||||||
|
currentInventorySlot = __instance.inventory.actualInventory.Count - 1;
|
||||||
|
else
|
||||||
|
currentInventorySlot = 0;
|
||||||
|
|
||||||
|
Item item = __instance.inventory.actualInventory[currentInventorySlot];
|
||||||
|
ClickableComponent c = __instance.inventory.inventory[currentInventorySlot];
|
||||||
|
string toSpeak;
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
toSpeak = item.DisplayName;
|
||||||
|
|
||||||
|
if ((item as StardewValley.Object) != null)
|
||||||
|
{
|
||||||
|
int quality = ((StardewValley.Object)item).Quality;
|
||||||
|
if (quality == 1)
|
||||||
|
{
|
||||||
|
toSpeak = $"Silver quality {toSpeak}";
|
||||||
|
}
|
||||||
|
else if (quality == 2 || quality == 3)
|
||||||
|
{
|
||||||
|
toSpeak = $"Gold quality {toSpeak}";
|
||||||
|
}
|
||||||
|
else if (quality >= 4)
|
||||||
|
{
|
||||||
|
toSpeak = $"Iridium quality {toSpeak}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toSpeak = $"{item.Stack} {toSpeak}";
|
||||||
|
|
||||||
|
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[currentInventorySlot]))
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} not usable here";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toSpeak = "Empty Slot";
|
||||||
|
}
|
||||||
|
c.snapMouseCursorToCenter();
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
JunimoNoteMenuPatch.currentIngredientListItem = -1;
|
||||||
|
JunimoNoteMenuPatch.currentIngredientInputSlot = -1;
|
||||||
|
JunimoNoteMenuPatch.currentInventorySlot = -1;
|
||||||
|
JunimoNoteMenuPatch.junimoNoteMenuQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,427 +0,0 @@
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using StardewModdingAPI;
|
|
||||||
using StardewValley;
|
|
||||||
using StardewValley.Menus;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
|
||||||
{
|
|
||||||
internal class DialoguePatches
|
|
||||||
{
|
|
||||||
internal static string currentLetterText = " ";
|
|
||||||
internal static string currentDialogue = " ";
|
|
||||||
internal static bool isDialogueAppearingFirstTime = true;
|
|
||||||
|
|
||||||
internal static void DialoguePatch(DialogueBox __instance, SpriteBatch b)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (__instance.transitioning)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (__instance.characterDialogue != null)
|
|
||||||
{
|
|
||||||
// For Normal Character dialogues
|
|
||||||
Dialogue dialogue = __instance.characterDialogue;
|
|
||||||
string speakerName = dialogue.speaker.displayName;
|
|
||||||
List<Response> responses = __instance.responses;
|
|
||||||
string toSpeak = " ";
|
|
||||||
string dialogueText = "";
|
|
||||||
string response = "";
|
|
||||||
bool hasResponses = dialogue.isCurrentDialogueAQuestion();
|
|
||||||
|
|
||||||
dialogueText = $"{speakerName} said {__instance.getCurrentString()}";
|
|
||||||
|
|
||||||
if (hasResponses)
|
|
||||||
{
|
|
||||||
if (__instance.selectedResponse >= 0 && __instance.selectedResponse < responses.Count)
|
|
||||||
response = $"{__instance.selectedResponse + 1}: {responses[__instance.selectedResponse].responseText}";
|
|
||||||
else
|
|
||||||
// When the dialogue is not finished writing then the selectedResponse is <0 and this results
|
|
||||||
// in the first response not being detcted, so this sets the first response option to be the default
|
|
||||||
// if the current dialogue is a question or has responses
|
|
||||||
response = $"1: {responses[0].responseText}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasResponses)
|
|
||||||
{
|
|
||||||
if (currentDialogue != response)
|
|
||||||
{
|
|
||||||
currentDialogue = response;
|
|
||||||
|
|
||||||
if (isDialogueAppearingFirstTime)
|
|
||||||
{
|
|
||||||
toSpeak = $"{dialogueText} \n\t {response}";
|
|
||||||
isDialogueAppearingFirstTime = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
toSpeak = response;
|
|
||||||
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (currentDialogue != dialogueText)
|
|
||||||
{
|
|
||||||
currentDialogue = dialogueText;
|
|
||||||
MainClass.ScreenReader.Say(dialogueText, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__instance.isQuestion)
|
|
||||||
{
|
|
||||||
// For Dialogues with responses/answers like the dialogue when we click on tv
|
|
||||||
string toSpeak = "";
|
|
||||||
string dialogueText = "";
|
|
||||||
string response = "";
|
|
||||||
bool hasResponses = false;
|
|
||||||
|
|
||||||
if (__instance.responses.Count > 0)
|
|
||||||
hasResponses = true;
|
|
||||||
|
|
||||||
dialogueText = __instance.getCurrentString();
|
|
||||||
|
|
||||||
if (hasResponses)
|
|
||||||
if (__instance.selectedResponse >= 0 && __instance.selectedResponse < __instance.responses.Count)
|
|
||||||
response = $"{__instance.selectedResponse + 1}: {__instance.responses[__instance.selectedResponse].responseText}";
|
|
||||||
else
|
|
||||||
// When the dialogue is not finished writing then the selectedResponse is <0 and this results
|
|
||||||
// in the first response not being detcted, so this sets the first response option to be the default
|
|
||||||
// if the current dialogue is a question or has responses
|
|
||||||
response = $"1: {__instance.responses[0].responseText}";
|
|
||||||
|
|
||||||
|
|
||||||
if (hasResponses)
|
|
||||||
{
|
|
||||||
if (currentDialogue != response)
|
|
||||||
{
|
|
||||||
currentDialogue = response;
|
|
||||||
|
|
||||||
if (isDialogueAppearingFirstTime)
|
|
||||||
{
|
|
||||||
toSpeak = $"{dialogueText} \n\t {response}";
|
|
||||||
isDialogueAppearingFirstTime = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
toSpeak = response;
|
|
||||||
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (currentDialogue != dialogueText)
|
|
||||||
{
|
|
||||||
currentDialogue = dialogueText;
|
|
||||||
MainClass.ScreenReader.Say(dialogueText, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Game1.activeClickableMenu is DialogueBox)
|
|
||||||
{
|
|
||||||
// Basic dialogues like `No mails in the mail box`
|
|
||||||
if (currentDialogue != __instance.getCurrentString())
|
|
||||||
{
|
|
||||||
currentDialogue = __instance.getCurrentString();
|
|
||||||
MainClass.ScreenReader.Say(__instance.getCurrentString(), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ClearDialogueString()
|
|
||||||
{
|
|
||||||
// CLears the currentDialogue string on closing dialog
|
|
||||||
currentDialogue = " ";
|
|
||||||
isDialogueAppearingFirstTime = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void HoverTextPatch(string? text, int moneyAmountToDisplayAtBottom = -1, string? boldTitleText = null, int extraItemToShowIndex = -1, int extraItemToShowAmount = -1, string[]? buffIconsToDisplay = null, Item? hoveredItem = null, CraftingRecipe? craftingIngredients = null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
#region Skip narrating hover text for certain menus
|
|
||||||
if (Game1.activeClickableMenu is TitleMenu && !(((TitleMenu)Game1.activeClickableMenu).GetChildMenu() is CharacterCustomization))
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is LetterViewerMenu || Game1.activeClickableMenu is QuestLog)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is Billboard)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is GeodeMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is InventoryPage)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is CraftingPage)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is OptionsPage)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is ExitPage)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is SocialPage)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ItemGrabMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ShopMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ConfirmationDialog)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is JunimoNoteMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is CarpenterMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is CraftingPage)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is AnimalQueryMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ConfirmationDialog)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ReadyCheckDialog)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is JojaCDMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is TailoringMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is PondQueryMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ForgeMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is ItemListMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is FieldOfficeMenu)
|
|
||||||
return;
|
|
||||||
else if (Game1.activeClickableMenu is MuseumMenu)
|
|
||||||
return;
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
string toSpeak = " ";
|
|
||||||
|
|
||||||
#region Add item count before title
|
|
||||||
if (hoveredItem != null && hoveredItem.HasBeenInInventory)
|
|
||||||
{
|
|
||||||
int count = hoveredItem.Stack;
|
|
||||||
if (count > 1)
|
|
||||||
toSpeak = $"{toSpeak} {count} ";
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add title if any
|
|
||||||
if (boldTitleText != null)
|
|
||||||
toSpeak = $"{toSpeak} {boldTitleText}\n";
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add quality of item
|
|
||||||
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).Quality > 0)
|
|
||||||
{
|
|
||||||
int quality = ((StardewValley.Object)hoveredItem).Quality;
|
|
||||||
if (quality == 1)
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} Silver quality";
|
|
||||||
}
|
|
||||||
else if (quality == 2 || quality == 3)
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} Gold quality";
|
|
||||||
}
|
|
||||||
else if (quality >= 4)
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} Iridium quality";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Narrate hovered required ingredients
|
|
||||||
if (extraItemToShowIndex != -1)
|
|
||||||
{
|
|
||||||
string itemName = Game1.objectInformation[extraItemToShowIndex].Split('/')[0];
|
|
||||||
|
|
||||||
if (extraItemToShowAmount != -1)
|
|
||||||
toSpeak = $"{toSpeak} Required: {extraItemToShowAmount} {itemName}";
|
|
||||||
else
|
|
||||||
toSpeak = $"{toSpeak} Required: {itemName}";
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add money
|
|
||||||
if (moneyAmountToDisplayAtBottom != -1)
|
|
||||||
toSpeak = $"{toSpeak} \nCost: {moneyAmountToDisplayAtBottom}g\n";
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add the base text
|
|
||||||
if (text == "???")
|
|
||||||
toSpeak = "unknown";
|
|
||||||
else
|
|
||||||
toSpeak = $"{toSpeak} {text}";
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add crafting ingredients
|
|
||||||
if (craftingIngredients != null)
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} \n{craftingIngredients.description}";
|
|
||||||
toSpeak = $"{toSpeak} \nIngredients\n";
|
|
||||||
|
|
||||||
craftingIngredients.recipeList.ToList().ForEach(recipe =>
|
|
||||||
{
|
|
||||||
int count = recipe.Value;
|
|
||||||
int item = recipe.Key;
|
|
||||||
string name = craftingIngredients.getNameFromIndex(item);
|
|
||||||
|
|
||||||
toSpeak = $"{toSpeak} ,{count} {name}";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add health & stamina
|
|
||||||
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).Edibility != -300)
|
|
||||||
{
|
|
||||||
int stamina_recovery = ((StardewValley.Object)hoveredItem).staminaRecoveredOnConsumption();
|
|
||||||
toSpeak = $"{toSpeak} {stamina_recovery} Energy\n";
|
|
||||||
if (stamina_recovery >= 0)
|
|
||||||
{
|
|
||||||
int health_recovery = ((StardewValley.Object)hoveredItem).healthRecoveredOnConsumption();
|
|
||||||
toSpeak = $"{toSpeak} {health_recovery} Health";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add buff items (effects like +1 walking speed)
|
|
||||||
if (buffIconsToDisplay != null)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < buffIconsToDisplay.Length; i++)
|
|
||||||
{
|
|
||||||
string buffName = ((Convert.ToInt32(buffIconsToDisplay[i]) > 0) ? "+" : "") + buffIconsToDisplay[i] + " ";
|
|
||||||
if (i <= 11)
|
|
||||||
{
|
|
||||||
buffName = Game1.content.LoadString("Strings\\UI:ItemHover_Buff" + i, buffName);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int count = int.Parse(buffName.Substring(0, buffName.IndexOf(' ')));
|
|
||||||
if (count != 0)
|
|
||||||
toSpeak = $"{toSpeak} {buffName}\n";
|
|
||||||
}
|
|
||||||
catch (Exception) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Narrate toSpeak
|
|
||||||
// To prevent it from getting conflicted by two hover texts at the same time, two seperate methods are used.
|
|
||||||
// For example, sometimes `Welcome to Pierre's` and the items in seeds shop get conflicted causing it to speak infinitely.
|
|
||||||
|
|
||||||
if (toSpeak.ToString() != " ")
|
|
||||||
{
|
|
||||||
if (Context.IsPlayerFree)
|
|
||||||
MainClass.ScreenReader.SayWithChecker(toSpeak.ToString(), true); // Normal Checker
|
|
||||||
else
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak.ToString(), true); // Menu Checker
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void LetterViewerMenuPatch(LetterViewerMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!__instance.IsActive())
|
|
||||||
return;
|
|
||||||
|
|
||||||
NarrateLetterContent(__instance);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void NarrateLetterContent(LetterViewerMenu __instance)
|
|
||||||
{
|
|
||||||
int x = Game1.getMousePosition().X, y = Game1.getMousePosition().Y;
|
|
||||||
#region Texts in the letter
|
|
||||||
string message = __instance.mailMessage[__instance.page];
|
|
||||||
|
|
||||||
string toSpeak = $"{message}";
|
|
||||||
|
|
||||||
if (__instance.ShouldShowInteractable())
|
|
||||||
{
|
|
||||||
if (__instance.moneyIncluded > 0)
|
|
||||||
{
|
|
||||||
string moneyText = Game1.content.LoadString("Strings\\UI:LetterViewer_MoneyIncluded", __instance.moneyIncluded);
|
|
||||||
toSpeak += $"\t\n\t ,Included money: {moneyText}";
|
|
||||||
}
|
|
||||||
else if (__instance.learnedRecipe != null && __instance.learnedRecipe.Length > 0)
|
|
||||||
{
|
|
||||||
string recipeText = Game1.content.LoadString("Strings\\UI:LetterViewer_LearnedRecipe", __instance.cookingOrCrafting);
|
|
||||||
toSpeak += $"\t\n\t ,Learned Recipe: {recipeText}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentLetterText != toSpeak)
|
|
||||||
{
|
|
||||||
currentLetterText = toSpeak;
|
|
||||||
|
|
||||||
// snap mouse to accept quest button
|
|
||||||
if (__instance.acceptQuestButton != null && __instance.questID != -1)
|
|
||||||
{
|
|
||||||
toSpeak += "\t\n Left click to accept quest.";
|
|
||||||
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
|
||||||
}
|
|
||||||
if (__instance.mailMessage.Count > 1)
|
|
||||||
toSpeak = $"Page {__instance.page + 1} of {__instance.mailMessage.Count}:\n\t{toSpeak}";
|
|
||||||
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Narrate items given in the mail
|
|
||||||
if (__instance.ShouldShowInteractable())
|
|
||||||
{
|
|
||||||
foreach (ClickableComponent c in __instance.itemsToGrab)
|
|
||||||
{
|
|
||||||
if (c.item == null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
string name = c.item.DisplayName;
|
|
||||||
|
|
||||||
if (c.containsPoint(x, y))
|
|
||||||
MainClass.ScreenReader.SayWithChecker($"Left click to collect {name}", false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Narrate buttons
|
|
||||||
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
|
||||||
MainClass.ScreenReader.SayWithChecker($"Previous page button", false);
|
|
||||||
|
|
||||||
if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
|
||||||
MainClass.ScreenReader.SayWithChecker($"Next page button", false);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void drawAboveAlwaysFrontLayerPatch(NPC __instance, string ___textAboveHead, int ___textAboveHeadTimer)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (___textAboveHeadTimer > 2900 && ___textAboveHead != null)
|
|
||||||
{
|
|
||||||
MainClass.ScreenReader.SayWithChecker($"{__instance.displayName} says {___textAboveHead}", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Error in patch:NPCShowTextAboveHeadPatch \n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,417 +0,0 @@
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using Microsoft.Xna.Framework.Content;
|
|
||||||
using StardewValley;
|
|
||||||
using StardewValley.Locations;
|
|
||||||
using StardewValley.Menus;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
|
||||||
{
|
|
||||||
internal class DonationMenuPatches
|
|
||||||
{
|
|
||||||
internal static string museumQueryKey = " ";
|
|
||||||
internal static string fieldOfficeMenuQuery = " ";
|
|
||||||
private static bool isMoving = false;
|
|
||||||
private static (int x, int y)[] donationTiles =
|
|
||||||
{
|
|
||||||
(26,5),(26,6),(26,7),(26,8),(26,9),(26,10),(26,11),
|
|
||||||
(29,5),(30,5),(31,5),(32,5),(33,5),(34,5),(35,5),(36,5),
|
|
||||||
(28,6),(29,6),(30,6),(31,6),(32,6),(33,6),(34,6),(35,6),(36,6),(37,6),
|
|
||||||
(28,9),(29,9),(30,9),(31,9),(32,9),(33,9),(34,9),(35,9),(36,9),
|
|
||||||
(28,10),(29,10),(30,10),(31,10),(32,10),(33,10),(34,10),(35,10),(36,10),
|
|
||||||
(30,13),(31,13),(32,13),(33,13),(34,13),
|
|
||||||
(30,14),(31,14),(32,14),(33,14),(34,14),
|
|
||||||
(28,15),(29,15),(30,15),(31,15),(32,15),(33,15),(34,15),(35,15),(36,15),
|
|
||||||
(28,16),(29,16),(30,16),(31,16),(32,16),(33,16),(34,16),(35,16),(36,16),
|
|
||||||
(39,6),(40,6),(41,6),(42,6),(43,6),(44,6),(45,6),(46,6),
|
|
||||||
(39,7),(40,7),(41,7),(42,7),(43,7),(44,7),(45,7),(46,7),
|
|
||||||
(48,5),(48,6),(48,7),
|
|
||||||
(42,15),(43,15),(44,15),(45,15),(46,15),(47,15),
|
|
||||||
(42,16),(43,16),(44,16),(45,16),(46,16),(47,16),
|
|
||||||
};
|
|
||||||
|
|
||||||
#region Museum
|
|
||||||
|
|
||||||
internal static bool MuseumMenuKeyPressPatch()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (isMoving)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!isMoving)
|
|
||||||
{
|
|
||||||
isMoving = true;
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isMoving = false; });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void MuseumMenuPatch(MuseumMenu __instance, bool ___holdingMuseumPiece)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
|
|
||||||
if (__instance.heldItem != null)
|
|
||||||
{
|
|
||||||
// Museum Inventory
|
|
||||||
string toSpeak = " ";
|
|
||||||
int tileX = (int)(Utility.ModifyCoordinateFromUIScale(x) + (float)Game1.viewport.X) / 64;
|
|
||||||
int tileY = (int)(Utility.ModifyCoordinateFromUIScale(y) + (float)Game1.viewport.Y) / 64;
|
|
||||||
LibraryMuseum libraryMuseum = (LibraryMuseum)Game1.currentLocation;
|
|
||||||
|
|
||||||
if (libraryMuseum.isTileSuitableForMuseumPiece(tileX, tileY))
|
|
||||||
toSpeak = $"slot {tileX}x {tileY}y";
|
|
||||||
|
|
||||||
if (museumQueryKey != toSpeak)
|
|
||||||
{
|
|
||||||
museumQueryKey = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Player Inventory
|
|
||||||
int i = narrateHoveredItemInInventory(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y);
|
|
||||||
if (i != -9999)
|
|
||||||
{
|
|
||||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); // For donating hovered item
|
|
||||||
|
|
||||||
if (isPrimaryInfoKeyPressed && __instance.inventory.actualInventory[i] != null)
|
|
||||||
{
|
|
||||||
foreach (var tile in donationTiles)
|
|
||||||
{
|
|
||||||
#region Manually donates the hovered item (https://github.com/veywrn/StardewValley/blob/3ff171b6e9e6839555d7881a391b624ccd820a83/StardewValley/Menus/MuseumMenu.cs#L206-L247)
|
|
||||||
int tileX = tile.x;
|
|
||||||
int tileY = tile.y;
|
|
||||||
|
|
||||||
if (((LibraryMuseum)Game1.currentLocation).isTileSuitableForMuseumPiece(tileX, tileY) && ((LibraryMuseum)Game1.currentLocation).isItemSuitableForDonation(__instance.inventory.actualInventory[i]))
|
|
||||||
{
|
|
||||||
int objectID = __instance.inventory.actualInventory[i].ParentSheetIndex;
|
|
||||||
int rewardsCount = ((LibraryMuseum)Game1.currentLocation).getRewardsForPlayer(Game1.player).Count;
|
|
||||||
((LibraryMuseum)Game1.currentLocation).museumPieces.Add(new Vector2(tileX, tileY), ((StardewValley.Object)__instance.inventory.actualInventory[i]).ParentSheetIndex);
|
|
||||||
Game1.playSound("stoneStep");
|
|
||||||
if (((LibraryMuseum)Game1.currentLocation).getRewardsForPlayer(Game1.player).Count > rewardsCount)
|
|
||||||
{
|
|
||||||
Game1.playSound("reward");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Game1.playSound("newArtifact");
|
|
||||||
}
|
|
||||||
Game1.player.completeQuest(24);
|
|
||||||
__instance.inventory.actualInventory[i].Stack--;
|
|
||||||
if (__instance.inventory.actualInventory[i].Stack <= 0)
|
|
||||||
{
|
|
||||||
__instance.inventory.actualInventory[i] = null;
|
|
||||||
}
|
|
||||||
int pieces = ((LibraryMuseum)Game1.currentLocation).museumPieces.Count();
|
|
||||||
Game1.stats.checkForArchaeologyAchievements();
|
|
||||||
switch (pieces)
|
|
||||||
{
|
|
||||||
case 95:
|
|
||||||
globalChatInfoMessage("MuseumComplete", Game1.player.farmName.Value);
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
globalChatInfoMessage("Museum40", Game1.player.farmName.Value);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
globalChatInfoMessage("donation", Game1.player.Name, "object:" + objectID);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if (museumQueryKey != $"ok button")
|
|
||||||
{
|
|
||||||
museumQueryKey = $"ok button";
|
|
||||||
MainClass.ScreenReader.Say("ok button", true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the index of the hovered item or -9999
|
|
||||||
internal static int narrateHoveredItemInInventory(InventoryMenu inventoryMenu, List<ClickableComponent> inventory, IList<Item> actualInventory, int x, int y)
|
|
||||||
{
|
|
||||||
#region Narrate hovered item
|
|
||||||
for (int i = 0; i < inventory.Count; i++)
|
|
||||||
{
|
|
||||||
if (inventory[i].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = "";
|
|
||||||
if ((i + 1) <= actualInventory.Count)
|
|
||||||
{
|
|
||||||
if (actualInventory[i] != null)
|
|
||||||
{
|
|
||||||
string name = actualInventory[i].DisplayName;
|
|
||||||
int stack = actualInventory[i].Stack;
|
|
||||||
string quality = "";
|
|
||||||
|
|
||||||
#region Add quality of item
|
|
||||||
if (actualInventory[i] is StardewValley.Object && ((StardewValley.Object)actualInventory[i]).Quality > 0)
|
|
||||||
{
|
|
||||||
int qualityIndex = ((StardewValley.Object)actualInventory[i]).Quality;
|
|
||||||
if (qualityIndex == 1)
|
|
||||||
{
|
|
||||||
quality = "Silver quality";
|
|
||||||
}
|
|
||||||
else if (qualityIndex == 2 || qualityIndex == 3)
|
|
||||||
{
|
|
||||||
quality = "Gold quality";
|
|
||||||
}
|
|
||||||
else if (qualityIndex >= 4)
|
|
||||||
{
|
|
||||||
quality = "Iridium quality";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
if (inventoryMenu.highlightMethod(inventoryMenu.actualInventory[i]))
|
|
||||||
name = $"Donatable {name}";
|
|
||||||
|
|
||||||
if (stack > 1)
|
|
||||||
toSpeak = $"{stack} {name} {quality}";
|
|
||||||
else
|
|
||||||
toSpeak = $"{name} {quality}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For empty slot
|
|
||||||
toSpeak = "Empty Slot";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// For empty slot
|
|
||||||
toSpeak = "Empty Slot";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (museumQueryKey != $"{toSpeak}:{i}")
|
|
||||||
{
|
|
||||||
museumQueryKey = $"{toSpeak}:{i}";
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
return -9999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region These methods are taken from the game's source code, https://github.com/veywrn/StardewValley/blob/3ff171b6e9e6839555d7881a391b624ccd820a83/StardewValley/Multiplayer.cs#L1331-L1395
|
|
||||||
internal static void globalChatInfoMessage(string messageKey, params string[] args)
|
|
||||||
{
|
|
||||||
if (Game1.IsMultiplayer || Game1.multiplayerMode != 0)
|
|
||||||
{
|
|
||||||
receiveChatInfoMessage(Game1.player, messageKey, args);
|
|
||||||
sendChatInfoMessage(messageKey, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void sendChatInfoMessage(string messageKey, params string[] args)
|
|
||||||
{
|
|
||||||
if (Game1.IsClient)
|
|
||||||
{
|
|
||||||
Game1.client.sendMessage(15, messageKey, args);
|
|
||||||
}
|
|
||||||
else if (Game1.IsServer)
|
|
||||||
{
|
|
||||||
foreach (long id in Game1.otherFarmers.Keys)
|
|
||||||
{
|
|
||||||
Game1.server.sendMessage(id, 15, Game1.player, messageKey, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void receiveChatInfoMessage(Farmer sourceFarmer, string messageKey, string[] args)
|
|
||||||
{
|
|
||||||
if (Game1.chatBox != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string[] processedArgs = args.Select(delegate (string arg)
|
|
||||||
{
|
|
||||||
if (arg.StartsWith("achievement:"))
|
|
||||||
{
|
|
||||||
int key = Convert.ToInt32(arg.Substring("achievement:".Length));
|
|
||||||
return Game1.content.Load<Dictionary<int, string>>("Data\\Achievements")[key].Split('^')[0];
|
|
||||||
}
|
|
||||||
return arg.StartsWith("object:") ? new StardewValley.Object(Convert.ToInt32(arg.Substring("object:".Length)), 1).DisplayName : arg;
|
|
||||||
}).ToArray();
|
|
||||||
ChatBox chatBox = Game1.chatBox;
|
|
||||||
LocalizedContentManager content = Game1.content;
|
|
||||||
string path = "Strings\\UI:Chat_" + messageKey;
|
|
||||||
object[] substitutions = processedArgs;
|
|
||||||
chatBox.addInfoMessage(content.LoadString(path, substitutions));
|
|
||||||
}
|
|
||||||
catch (ContentLoadException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
catch (FormatException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
catch (OverflowException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
catch (KeyNotFoundException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Field Office
|
|
||||||
|
|
||||||
internal static void FieldOfficeMenuPatch(FieldOfficeMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = " ";
|
|
||||||
|
|
||||||
if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Trashcan";
|
|
||||||
}
|
|
||||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "ok button";
|
|
||||||
}
|
|
||||||
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "drop item";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < __instance.inventory.inventory.Count; i++)
|
|
||||||
{
|
|
||||||
if (!__instance.inventory.inventory[i].containsPoint(x, y))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (__instance.inventory.actualInventory[i] == null)
|
|
||||||
toSpeak = "Empty slot";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toSpeak = $"{__instance.inventory.actualInventory[i].Stack} {__instance.inventory.actualInventory[i].DisplayName}";
|
|
||||||
|
|
||||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[i]))
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} not usable here";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldOfficeMenuQuery != $"{toSpeak}:{i}")
|
|
||||||
{
|
|
||||||
fieldOfficeMenuQuery = $"{toSpeak}:{i}";
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < __instance.pieceHolders.Count; i++)
|
|
||||||
{
|
|
||||||
if (!__instance.pieceHolders[i].containsPoint(x, y))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (__instance.pieceHolders[i].item == null)
|
|
||||||
toSpeak = i switch
|
|
||||||
{
|
|
||||||
0 => "Center skeleton slot",
|
|
||||||
1 => "Center skeleton slot",
|
|
||||||
2 => "Center skeleton slot",
|
|
||||||
3 => "Center skeleton slot",
|
|
||||||
4 => "Center skeleton slot",
|
|
||||||
5 => "Center skeleton slot",
|
|
||||||
6 => "Snake slot",
|
|
||||||
7 => "Snake slot",
|
|
||||||
8 => "Snake slot",
|
|
||||||
9 => "Bat slot",
|
|
||||||
10 => "Frog slot",
|
|
||||||
_ => "Donation slot"
|
|
||||||
};
|
|
||||||
else
|
|
||||||
toSpeak = $"Slot {i + 1} finished: {__instance.pieceHolders[i].item.DisplayName}";
|
|
||||||
|
|
||||||
if (__instance.heldItem != null && __instance.pieceHolders[i].item == null)
|
|
||||||
{
|
|
||||||
int highlight = getPieceIndexForDonationItem(__instance.heldItem.ParentSheetIndex);
|
|
||||||
if (highlight != -1 && highlight == i)
|
|
||||||
toSpeak += "Donatable ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldOfficeMenuQuery != $"{toSpeak}:{i}")
|
|
||||||
{
|
|
||||||
fieldOfficeMenuQuery = $"{toSpeak}:{i}";
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldOfficeMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
fieldOfficeMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
|
|
||||||
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
|
||||||
Game1.playSound("drop_item");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static int getPieceIndexForDonationItem(int itemIndex)
|
|
||||||
{
|
|
||||||
switch (itemIndex)
|
|
||||||
{
|
|
||||||
case 820:
|
|
||||||
return 5;
|
|
||||||
case 821:
|
|
||||||
return 4;
|
|
||||||
case 822:
|
|
||||||
return 3;
|
|
||||||
case 823:
|
|
||||||
return 0;
|
|
||||||
case 824:
|
|
||||||
return 1;
|
|
||||||
case 825:
|
|
||||||
return 8;
|
|
||||||
case 826:
|
|
||||||
return 7;
|
|
||||||
case 827:
|
|
||||||
return 9;
|
|
||||||
case 828:
|
|
||||||
return 10;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
using StardewValley;
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class FieldOfficeMenuPatch
|
||||||
|
{
|
||||||
|
private static string fieldOfficeMenuQuery = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(FieldOfficeMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
string toSpeak = " ";
|
||||||
|
|
||||||
|
if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trashcan";
|
||||||
|
}
|
||||||
|
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "ok button";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "drop item";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = 0; i < __instance.pieceHolders.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.pieceHolders[i].containsPoint(x, y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (__instance.pieceHolders[i].item == null)
|
||||||
|
toSpeak = i switch
|
||||||
|
{
|
||||||
|
0 => "Center skeleton slot",
|
||||||
|
1 => "Center skeleton slot",
|
||||||
|
2 => "Center skeleton slot",
|
||||||
|
3 => "Center skeleton slot",
|
||||||
|
4 => "Center skeleton slot",
|
||||||
|
5 => "Center skeleton slot",
|
||||||
|
6 => "Snake slot",
|
||||||
|
7 => "Snake slot",
|
||||||
|
8 => "Snake slot",
|
||||||
|
9 => "Bat slot",
|
||||||
|
10 => "Frog slot",
|
||||||
|
_ => "Donation slot"
|
||||||
|
};
|
||||||
|
else
|
||||||
|
toSpeak = $"Slot {i + 1} finished: {__instance.pieceHolders[i].item.DisplayName}";
|
||||||
|
|
||||||
|
if (!MainClass.Config.DisableInventoryVerbosity && __instance.heldItem != null && __instance.pieceHolders[i].item == null)
|
||||||
|
{
|
||||||
|
int highlight = getPieceIndexForDonationItem(__instance.heldItem.ParentSheetIndex);
|
||||||
|
if (highlight != -1 && highlight == i)
|
||||||
|
toSpeak += "Donatable ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldOfficeMenuQuery != $"{toSpeak}:{i}")
|
||||||
|
{
|
||||||
|
fieldOfficeMenuQuery = $"{toSpeak}:{i}";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fieldOfficeMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
fieldOfficeMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
|
||||||
|
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
Game1.playSound("drop_item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static int getPieceIndexForDonationItem(int itemIndex)
|
||||||
|
{
|
||||||
|
switch (itemIndex)
|
||||||
|
{
|
||||||
|
case 820:
|
||||||
|
return 5;
|
||||||
|
case 821:
|
||||||
|
return 4;
|
||||||
|
case 822:
|
||||||
|
return 3;
|
||||||
|
case 823:
|
||||||
|
return 0;
|
||||||
|
case 824:
|
||||||
|
return 1;
|
||||||
|
case 825:
|
||||||
|
return 8;
|
||||||
|
case 826:
|
||||||
|
return 7;
|
||||||
|
case 827:
|
||||||
|
return 9;
|
||||||
|
case 828:
|
||||||
|
return 10;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
fieldOfficeMenuQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using StardewValley;
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley.Locations;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class MuseumMenuPatch
|
||||||
|
{
|
||||||
|
private static string museumQueryKey = "";
|
||||||
|
private static bool isMoving = false;
|
||||||
|
private static (int x, int y)[] donationTiles =
|
||||||
|
{
|
||||||
|
(26,5),(26,6),(26,7),(26,8),(26,9),(26,10),(26,11),
|
||||||
|
(29,5),(30,5),(31,5),(32,5),(33,5),(34,5),(35,5),(36,5),
|
||||||
|
(28,6),(29,6),(30,6),(31,6),(32,6),(33,6),(34,6),(35,6),(36,6),(37,6),
|
||||||
|
(28,9),(29,9),(30,9),(31,9),(32,9),(33,9),(34,9),(35,9),(36,9),
|
||||||
|
(28,10),(29,10),(30,10),(31,10),(32,10),(33,10),(34,10),(35,10),(36,10),
|
||||||
|
(30,13),(31,13),(32,13),(33,13),(34,13),
|
||||||
|
(30,14),(31,14),(32,14),(33,14),(34,14),
|
||||||
|
(28,15),(29,15),(30,15),(31,15),(32,15),(33,15),(34,15),(35,15),(36,15),
|
||||||
|
(28,16),(29,16),(30,16),(31,16),(32,16),(33,16),(34,16),(35,16),(36,16),
|
||||||
|
(39,6),(40,6),(41,6),(42,6),(43,6),(44,6),(45,6),(46,6),
|
||||||
|
(39,7),(40,7),(41,7),(42,7),(43,7),(44,7),(45,7),(46,7),
|
||||||
|
(48,5),(48,6),(48,7),
|
||||||
|
(42,15),(43,15),(44,15),(45,15),(46,15),(47,15),
|
||||||
|
(42,16),(43,16),(44,16),(45,16),(46,16),(47,16),
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static bool RecieveKeyPressPatch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isMoving)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!isMoving)
|
||||||
|
{
|
||||||
|
isMoving = true;
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isMoving = false; });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void DrawPatch(MuseumMenu __instance, bool ___holdingMuseumPiece)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
narrateMuseumInventory(__instance, x, y);
|
||||||
|
|
||||||
|
narratePlayerInventory(__instance, x, y);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateMuseumInventory(MuseumMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
if (__instance.heldItem == null) return;
|
||||||
|
|
||||||
|
string toSpeak = "";
|
||||||
|
int tileX = (int)(Utility.ModifyCoordinateFromUIScale(x) + (float)Game1.viewport.X) / 64;
|
||||||
|
int tileY = (int)(Utility.ModifyCoordinateFromUIScale(y) + (float)Game1.viewport.Y) / 64;
|
||||||
|
LibraryMuseum libraryMuseum = (LibraryMuseum)Game1.currentLocation;
|
||||||
|
|
||||||
|
if (libraryMuseum.isTileSuitableForMuseumPiece(tileX, tileY))
|
||||||
|
toSpeak = $"slot {tileX}x {tileY}y";
|
||||||
|
|
||||||
|
if (museumQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
museumQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narratePlayerInventory(MuseumMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
if (__instance.heldItem != null) return;
|
||||||
|
|
||||||
|
if (narrateHoveredButtons(__instance, x, y)) return;
|
||||||
|
|
||||||
|
int hoveredItemIndex = InventoryUtils.narrateHoveredSlotAndReturnIndex(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y,
|
||||||
|
handleHighlightedItem: true, highlightedItemPrefix: "Donatable ");
|
||||||
|
if (hoveredItemIndex != -9999)
|
||||||
|
{
|
||||||
|
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed(); // For donating hovered item
|
||||||
|
|
||||||
|
if (isPrimaryInfoKeyPressed && hoveredItemIndex >= 0 && hoveredItemIndex < __instance.inventory.actualInventory.Count && __instance.inventory.actualInventory[hoveredItemIndex] != null)
|
||||||
|
{
|
||||||
|
manuallyDonateItem(__instance, hoveredItemIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButtons(MuseumMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Ok button";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Drop Item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (museumQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
museumQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void manuallyDonateItem(MuseumMenu __instance, int i)
|
||||||
|
{
|
||||||
|
foreach (var tile in donationTiles)
|
||||||
|
{
|
||||||
|
#region Manually donates the hovered item (https://github.com/veywrn/StardewValley/blob/3ff171b6e9e6839555d7881a391b624ccd820a83/StardewValley/Menus/MuseumMenu.cs#L206-L247)
|
||||||
|
int tileX = tile.x;
|
||||||
|
int tileY = tile.y;
|
||||||
|
|
||||||
|
if (((LibraryMuseum)Game1.currentLocation).isTileSuitableForMuseumPiece(tileX, tileY) && ((LibraryMuseum)Game1.currentLocation).isItemSuitableForDonation(__instance.inventory.actualInventory[i]))
|
||||||
|
{
|
||||||
|
int objectID = __instance.inventory.actualInventory[i].ParentSheetIndex;
|
||||||
|
int rewardsCount = ((LibraryMuseum)Game1.currentLocation).getRewardsForPlayer(Game1.player).Count;
|
||||||
|
((LibraryMuseum)Game1.currentLocation).museumPieces.Add(new Vector2(tileX, tileY), ((StardewValley.Object)__instance.inventory.actualInventory[i]).ParentSheetIndex);
|
||||||
|
Game1.playSound("stoneStep");
|
||||||
|
if (((LibraryMuseum)Game1.currentLocation).getRewardsForPlayer(Game1.player).Count > rewardsCount)
|
||||||
|
{
|
||||||
|
Game1.playSound("reward");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game1.playSound("newArtifact");
|
||||||
|
}
|
||||||
|
Game1.player.completeQuest(24);
|
||||||
|
__instance.inventory.actualInventory[i].Stack--;
|
||||||
|
if (__instance.inventory.actualInventory[i].Stack <= 0)
|
||||||
|
{
|
||||||
|
__instance.inventory.actualInventory[i] = null;
|
||||||
|
}
|
||||||
|
int pieces = ((LibraryMuseum)Game1.currentLocation).museumPieces.Count();
|
||||||
|
Game1.stats.checkForArchaeologyAchievements();
|
||||||
|
switch (pieces)
|
||||||
|
{
|
||||||
|
case 95:
|
||||||
|
globalChatInfoMessage("MuseumComplete", Game1.player.farmName.Value);
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
globalChatInfoMessage("Museum40", Game1.player.farmName.Value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
globalChatInfoMessage("donation", Game1.player.Name, "object:" + objectID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region These methods are taken from the game's source code, https://github.com/veywrn/StardewValley/blob/3ff171b6e9e6839555d7881a391b624ccd820a83/StardewValley/Multiplayer.cs#L1331-L1395
|
||||||
|
internal static void globalChatInfoMessage(string messageKey, params string[] args)
|
||||||
|
{
|
||||||
|
if (Game1.IsMultiplayer || Game1.multiplayerMode != 0)
|
||||||
|
{
|
||||||
|
receiveChatInfoMessage(Game1.player, messageKey, args);
|
||||||
|
sendChatInfoMessage(messageKey, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void sendChatInfoMessage(string messageKey, params string[] args)
|
||||||
|
{
|
||||||
|
if (Game1.IsClient)
|
||||||
|
{
|
||||||
|
Game1.client.sendMessage(15, messageKey, args);
|
||||||
|
}
|
||||||
|
else if (Game1.IsServer)
|
||||||
|
{
|
||||||
|
foreach (long id in Game1.otherFarmers.Keys)
|
||||||
|
{
|
||||||
|
Game1.server.sendMessage(id, 15, Game1.player, messageKey, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void receiveChatInfoMessage(Farmer sourceFarmer, string messageKey, string[] args)
|
||||||
|
{
|
||||||
|
if (Game1.chatBox != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] processedArgs = args.Select(delegate (string arg)
|
||||||
|
{
|
||||||
|
if (arg.StartsWith("achievement:"))
|
||||||
|
{
|
||||||
|
int key = Convert.ToInt32(arg.Substring("achievement:".Length));
|
||||||
|
return Game1.content.Load<Dictionary<int, string>>("Data\\Achievements")[key].Split('^')[0];
|
||||||
|
}
|
||||||
|
return arg.StartsWith("object:") ? new StardewValley.Object(Convert.ToInt32(arg.Substring("object:".Length)), 1).DisplayName : arg;
|
||||||
|
}).ToArray();
|
||||||
|
ChatBox chatBox = Game1.chatBox;
|
||||||
|
LocalizedContentManager content = Game1.content;
|
||||||
|
string path = "Strings\\UI:Chat_" + messageKey;
|
||||||
|
object[] substitutions = processedArgs;
|
||||||
|
chatBox.addInfoMessage(content.LoadString(path, substitutions));
|
||||||
|
}
|
||||||
|
catch (Microsoft.Xna.Framework.Content.ContentLoadException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (FormatException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (OverflowException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
museumQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class CollectionsPagePatch
|
||||||
|
{
|
||||||
|
internal static void DrawPatch(StardewValley.Menus.CollectionsPage __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = StardewValley.Game1.getMousePosition().X, y = StardewValley.Game1.getMousePosition().Y;
|
||||||
|
if (__instance.letterviewerSubMenu != null)
|
||||||
|
{
|
||||||
|
LetterViwerMenuPatch.narrateLetterContent(__instance.letterviewerSubMenu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,251 @@
|
||||||
|
using StardewValley;
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using StardewValley.Objects;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class CraftingPagePatch
|
||||||
|
{
|
||||||
|
internal static string hoveredItemQueryKey = "";
|
||||||
|
internal static string craftingPageQueryKey = "";
|
||||||
|
internal static int currentSelectedCraftingRecipe = -1;
|
||||||
|
internal static bool isSelectingRecipe = false;
|
||||||
|
|
||||||
|
internal static void DrawPatch(CraftingPage __instance, CraftingRecipe ___hoverRecipe, int ___currentCraftingPage)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
handleKeyBinds(__instance, ___currentCraftingPage);
|
||||||
|
|
||||||
|
if (narrateMenuButtons(__instance, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (narrateHoveredRecipe(__instance, ___currentCraftingPage, ___hoverRecipe, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y))
|
||||||
|
{
|
||||||
|
craftingPageQueryKey = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleKeyBinds(CraftingPage __instance, int ___currentCraftingPage)
|
||||||
|
{
|
||||||
|
if (MainClass.Config.SnapToFirstSecondaryInventorySlotKey.JustPressed() && __instance.pagesOfCraftingRecipes[___currentCraftingPage].Count > 0)
|
||||||
|
{
|
||||||
|
// snap to first crafting recipe
|
||||||
|
__instance.setCurrentlySnappedComponentTo(__instance.pagesOfCraftingRecipes[___currentCraftingPage].ElementAt(0).Key.myID);
|
||||||
|
__instance.pagesOfCraftingRecipes[___currentCraftingPage].ElementAt(0).Key.snapMouseCursorToCenter();
|
||||||
|
currentSelectedCraftingRecipe = 0;
|
||||||
|
}
|
||||||
|
else if (MainClass.Config.SnapToFirstInventorySlotKey.JustPressed() && __instance.inventory.inventory.Count > 0)
|
||||||
|
{
|
||||||
|
// snap to first inventory slot
|
||||||
|
__instance.setCurrentlySnappedComponentTo(__instance.inventory.inventory[0].myID);
|
||||||
|
__instance.inventory.inventory[0].snapMouseCursorToCenter();
|
||||||
|
currentSelectedCraftingRecipe = -1;
|
||||||
|
}
|
||||||
|
else if (MainClass.Config.CraftingMenuCycleThroughRecipiesKey.JustPressed() && !isSelectingRecipe)
|
||||||
|
{
|
||||||
|
isSelectingRecipe = true;
|
||||||
|
CycleThroughRecipies(__instance.pagesOfCraftingRecipes, ___currentCraftingPage, __instance);
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isSelectingRecipe = false; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateMenuButtons(CraftingPage __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string? toSpeak = null;
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.upButton != null && __instance.upButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Previous Recipe List";
|
||||||
|
}
|
||||||
|
else if (__instance.downButton != null && __instance.downButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Next Recipe List";
|
||||||
|
}
|
||||||
|
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trash Can";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Drop Item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toSpeak != null && craftingPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
craftingPageQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredRecipe(CraftingPage __instance, int ___currentCraftingPage, CraftingRecipe ___hoverRecipe, int x, int y)
|
||||||
|
{
|
||||||
|
if (___hoverRecipe == null)
|
||||||
|
{
|
||||||
|
var isRecipeInFocus = false;
|
||||||
|
foreach (var item in __instance.pagesOfCraftingRecipes[___currentCraftingPage])
|
||||||
|
{
|
||||||
|
if (!item.Key.containsPoint(x, y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
isRecipeInFocus = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isRecipeInFocus)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string query = $"unknown recipe:{__instance.getCurrentlySnappedComponent().myID}";
|
||||||
|
|
||||||
|
if (craftingPageQueryKey != query)
|
||||||
|
{
|
||||||
|
craftingPageQueryKey = query;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say("unknown recipe", true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string name = ___hoverRecipe.DisplayName;
|
||||||
|
int numberOfProduce = ___hoverRecipe.numberProducedPerCraft;
|
||||||
|
string description = "";
|
||||||
|
string ingredients = "";
|
||||||
|
string buffs = "";
|
||||||
|
string craftable = "";
|
||||||
|
|
||||||
|
description = $"Description:\n{___hoverRecipe.description}";
|
||||||
|
craftable = ___hoverRecipe.doesFarmerHaveIngredientsInInventory(getContainerContents(__instance._materialContainers)) ? "Craftable" : "Not Craftable";
|
||||||
|
|
||||||
|
#region Crafting ingredients
|
||||||
|
ingredients = "Ingredients:\n";
|
||||||
|
for (int i = 0; i < ___hoverRecipe.recipeList.Count; i++)
|
||||||
|
{
|
||||||
|
int recipeCount = ___hoverRecipe.recipeList.ElementAt(i).Value;
|
||||||
|
int recipeItem = ___hoverRecipe.recipeList.ElementAt(i).Key;
|
||||||
|
string recipeName = ___hoverRecipe.getNameFromIndex(recipeItem);
|
||||||
|
|
||||||
|
ingredients += $" ,{recipeCount} {recipeName}";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Health & stamina and buff items (effects like +1 walking speed)
|
||||||
|
Item producesItem = ___hoverRecipe.createItem();
|
||||||
|
if (producesItem is StardewValley.Object producesItemObject)
|
||||||
|
{
|
||||||
|
if (producesItemObject.Edibility != -300)
|
||||||
|
{
|
||||||
|
int stamina_recovery = producesItemObject.staminaRecoveredOnConsumption();
|
||||||
|
buffs += $"{stamina_recovery} Energy";
|
||||||
|
if (stamina_recovery >= 0)
|
||||||
|
{
|
||||||
|
int health_recovery = producesItemObject.healthRecoveredOnConsumption();
|
||||||
|
buffs += $"\n{health_recovery} Health";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// These variables are taken from the game's code itself (IClickableMenu.cs -> 1016 line)
|
||||||
|
bool edibleItem = producesItem != null && (int)producesItemObject.Edibility != -300;
|
||||||
|
string[]? buffIconsToDisplay = (producesItem != null && edibleItem && Game1.objectInformation[producesItemObject.ParentSheetIndex].Split('/').Length > 7)
|
||||||
|
? producesItem.ModifyItemBuffs(Game1.objectInformation[producesItemObject.ParentSheetIndex].Split('/')[7].Split(' '))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (buffIconsToDisplay != null)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < buffIconsToDisplay.Length; j++)
|
||||||
|
{
|
||||||
|
string buffName = ((Convert.ToInt32(buffIconsToDisplay[j]) > 0) ? "+" : "") + buffIconsToDisplay[j] + " ";
|
||||||
|
if (j <= 11)
|
||||||
|
{
|
||||||
|
buffName = Game1.content.LoadString("Strings\\UI:ItemHover_Buff" + j, buffName);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int count = int.Parse(buffName.Substring(0, buffName.IndexOf(' ')));
|
||||||
|
if (count != 0)
|
||||||
|
buffs += $"{buffName}\n";
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
buffs = $"Buffs and boosts:\n {buffs}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
string toSpeak = $"{numberOfProduce} {name}, {craftable}, \n\t{ingredients}, \n\t{description} \n\t{buffs}";
|
||||||
|
|
||||||
|
if (craftingPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
craftingPageQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CycleThroughRecipies(List<Dictionary<ClickableTextureComponent, CraftingRecipe>> pagesOfCraftingRecipes, int ___currentCraftingPage, CraftingPage __instance)
|
||||||
|
{
|
||||||
|
currentSelectedCraftingRecipe++;
|
||||||
|
if (currentSelectedCraftingRecipe < 0 || currentSelectedCraftingRecipe >= pagesOfCraftingRecipes[0].Count)
|
||||||
|
currentSelectedCraftingRecipe = 0;
|
||||||
|
|
||||||
|
__instance.setCurrentlySnappedComponentTo(pagesOfCraftingRecipes[___currentCraftingPage].ElementAt(currentSelectedCraftingRecipe).Key.myID);
|
||||||
|
pagesOfCraftingRecipes[___currentCraftingPage].ElementAt(currentSelectedCraftingRecipe).Key.snapMouseCursorToCenter();
|
||||||
|
|
||||||
|
// Skip if recipe is not unlocked/unknown
|
||||||
|
if (pagesOfCraftingRecipes[___currentCraftingPage].ElementAt(currentSelectedCraftingRecipe).Key.hoverText.Equals("ghosted"))
|
||||||
|
CycleThroughRecipies(pagesOfCraftingRecipes, ___currentCraftingPage, __instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method is used to get the inventory items to check if the player has enough ingredients for a recipe
|
||||||
|
// Taken from CraftingPage.cs -> 169 line
|
||||||
|
internal static IList<Item>? getContainerContents(List<Chest> materialContainers)
|
||||||
|
{
|
||||||
|
if (materialContainers == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Item> items = new List<Item>();
|
||||||
|
for (int i = 0; i < materialContainers.Count; i++)
|
||||||
|
{
|
||||||
|
items.AddRange(materialContainers[i].items);
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
craftingPageQueryKey = "";
|
||||||
|
currentSelectedCraftingRecipe = -1;
|
||||||
|
isSelectingRecipe = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ExitPagePatch
|
||||||
|
{
|
||||||
|
internal static string exitPageQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(ExitPage __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (__instance.exitToTitle.visible &&
|
||||||
|
__instance.exitToTitle.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||||
|
{
|
||||||
|
string toSpeak = "Exit to Title Button";
|
||||||
|
if (exitPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
exitPageQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (__instance.exitToDesktop.visible &&
|
||||||
|
__instance.exitToDesktop.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||||
|
{
|
||||||
|
string toSpeak = "Exit to Desktop Button";
|
||||||
|
if (exitPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
exitPageQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
exitPageQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class GameMenuPatch
|
||||||
|
{
|
||||||
|
internal static string gameMenuQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(GameMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Skip if in map page
|
||||||
|
if (__instance.currentTab == 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
for (int i = 0; i < __instance.tabs.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.tabs[i].containsPoint(x, y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string toSpeak = $"{GameMenu.getLabelOfTabFromIndex(i)} Tab" + ((i == __instance.currentTab) ? " Active" : "");
|
||||||
|
if (gameMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
gameMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not hovering on any tab button
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
gameMenuQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class InventoryPagePatch
|
||||||
|
{
|
||||||
|
internal static string inventoryPageQueryKey = "";
|
||||||
|
internal static string hoveredItemQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(InventoryPage __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
handleKeyBinds();
|
||||||
|
|
||||||
|
if (narrateHoveredButton(__instance, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (narrateHoveredEquipmentSlot(__instance, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y, true))
|
||||||
|
{
|
||||||
|
inventoryPageQueryKey = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no slot or button is hovered
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in InventoryPagePatch()->DrawPatch():\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void handleKeyBinds()
|
||||||
|
{
|
||||||
|
if (!MainClass.Config.MoneyKey.JustPressed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
string farmName = Game1.content.LoadString("Strings\\UI:Inventory_FarmName", Game1.player.farmName.Value);
|
||||||
|
string currentFunds = Game1.content.LoadString("Strings\\UI:Inventory_CurrentFunds" + (Game1.player.useSeparateWallets ? "_Separate" : ""), Utility.getNumberWithCommas(Game1.player.Money));
|
||||||
|
string totalEarnings = Game1.content.LoadString("Strings\\UI:Inventory_TotalEarnings" + (Game1.player.useSeparateWallets ? "_Separate" : ""), Utility.getNumberWithCommas((int)Game1.player.totalMoneyEarned));
|
||||||
|
int festivalScore = Game1.player.festivalScore;
|
||||||
|
int walnut = Game1.netWorldState.Value.GoldenWalnuts.Value;
|
||||||
|
int qiGems = Game1.player.QiGems;
|
||||||
|
int qiCoins = Game1.player.clubCoins;
|
||||||
|
|
||||||
|
string toSpeak = $"{farmName}\n{currentFunds}\n{totalEarnings}";
|
||||||
|
|
||||||
|
if (festivalScore > 0)
|
||||||
|
toSpeak = $"{toSpeak}\nFestival Score: {festivalScore}";
|
||||||
|
|
||||||
|
if (walnut > 0)
|
||||||
|
toSpeak = $"{toSpeak}\nGolden Walnut: {walnut}";
|
||||||
|
|
||||||
|
if (qiGems > 0)
|
||||||
|
toSpeak = $"{toSpeak}\nQi Gems: {qiGems}";
|
||||||
|
|
||||||
|
if (qiCoins > 0)
|
||||||
|
toSpeak = $"{toSpeak}\nQi Club Coins: {qiCoins}";
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButton(InventoryPage __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string? toSpeak = null;
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.inventory.dropItemInvisibleButton != null && __instance.inventory.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Drop Item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else if (__instance.organizeButton != null && __instance.organizeButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Organize Inventory Button";
|
||||||
|
}
|
||||||
|
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trash Can";
|
||||||
|
}
|
||||||
|
else if (__instance.organizeButton != null && __instance.organizeButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Organize Button";
|
||||||
|
}
|
||||||
|
else if (__instance.junimoNoteIcon != null && __instance.junimoNoteIcon.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Community Center Button";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toSpeak != null && inventoryPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
inventoryPageQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredEquipmentSlot(InventoryPage __instance, int mouseX, int mouseY)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < __instance.equipmentIcons.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.equipmentIcons[i].containsPoint(mouseX, mouseY))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string toSpeak = getNameAndDescriptionOfItem(__instance.equipmentIcons[i].name);
|
||||||
|
|
||||||
|
if (inventoryPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
inventoryPageQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string getNameAndDescriptionOfItem(string slotName) => slotName switch
|
||||||
|
{
|
||||||
|
"Hat" => (Game1.player.hat.Value != null) ? $"{Game1.player.hat.Value.DisplayName}, {Game1.player.hat.Value.getDescription()}" : "Hat slot",
|
||||||
|
"Left Ring" => (Game1.player.leftRing.Value != null) ? $"{Game1.player.leftRing.Value.DisplayName}, {Game1.player.leftRing.Value.getDescription()}" : "Left Ring slot",
|
||||||
|
"Right Ring" => (Game1.player.rightRing.Value != null) ? $"{Game1.player.rightRing.Value.DisplayName}, {Game1.player.rightRing.Value.getDescription()}" : "Right ring slot",
|
||||||
|
"Boots" => (Game1.player.boots.Value != null) ? $"{Game1.player.boots.Value.DisplayName}, {Game1.player.boots.Value.getDescription()}" : "Boots slot",
|
||||||
|
"Shirt" => (Game1.player.shirtItem.Value != null) ? $"{Game1.player.shirtItem.Value.DisplayName}, {Game1.player.shirtItem.Value.getDescription()}" : "Shirt slot",
|
||||||
|
"Pants" => (Game1.player.pantsItem.Value != null) ? $"{Game1.player.pantsItem.Value.DisplayName}, {Game1.player.pantsItem.Value.getDescription()}" : "Pants slot",
|
||||||
|
_ => "unkown slot"
|
||||||
|
};
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
InventoryUtils.Cleanup();
|
||||||
|
inventoryPageQueryKey = "";
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class OptionsPagePatch
|
||||||
|
{
|
||||||
|
internal static string optionsPageQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(OptionsPage __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int currentItemIndex = Math.Max(0, Math.Min(__instance.options.Count - 7, __instance.currentItemIndex));
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||||
|
for (int i = 0; i < __instance.optionSlots.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.optionSlots[i].bounds.Contains(x, y) || currentItemIndex + i >= __instance.options.Count || !__instance.options[currentItemIndex + i].bounds.Contains(x - __instance.optionSlots[i].bounds.X, y - __instance.optionSlots[i].bounds.Y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
OptionsElement optionsElement = __instance.options[currentItemIndex + i];
|
||||||
|
string toSpeak = optionsElement.label;
|
||||||
|
|
||||||
|
if (optionsElement is OptionsButton)
|
||||||
|
toSpeak = $" {toSpeak} Button";
|
||||||
|
else if (optionsElement is OptionsCheckbox)
|
||||||
|
toSpeak = (((OptionsCheckbox)optionsElement).isChecked ? "Enabled" : "Disabled") + $" {toSpeak} Checkbox";
|
||||||
|
else if (optionsElement is OptionsDropDown)
|
||||||
|
toSpeak = $"{toSpeak} Dropdown, option {((OptionsDropDown)optionsElement).dropDownDisplayOptions[((OptionsDropDown)optionsElement).selectedOption]} selected";
|
||||||
|
else if (optionsElement is OptionsSlider)
|
||||||
|
toSpeak = $"{((OptionsSlider)optionsElement).value}% {toSpeak} Slider";
|
||||||
|
else if (optionsElement is OptionsPlusMinus)
|
||||||
|
toSpeak = $"{((OptionsPlusMinus)optionsElement).displayOptions[((OptionsPlusMinus)optionsElement).selected]} selected of {toSpeak}";
|
||||||
|
else if (optionsElement is OptionsInputListener)
|
||||||
|
{
|
||||||
|
string buttons = "";
|
||||||
|
((OptionsInputListener)optionsElement).buttonNames.ForEach(name => { buttons += $", {name}"; });
|
||||||
|
toSpeak = $"{toSpeak} is bound to {buttons}. Left click to change.";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (toSpeak.Contains(":"))
|
||||||
|
toSpeak = toSpeak.Replace(":", "");
|
||||||
|
|
||||||
|
toSpeak = $"{toSpeak} Options:";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionsPageQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
optionsPageQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
optionsPageQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class SocialPagePatch
|
||||||
|
{
|
||||||
|
internal static string socialPageQuery = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(SocialPage __instance, List<ClickableTextureComponent> ___sprites, int ___slotPosition, List<string> ___kidsNames)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
for (int i = ___slotPosition; i < ___slotPosition + 5; i++)
|
||||||
|
{
|
||||||
|
if (i >= ___sprites.Count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (__instance.names[i] is string && narrateNPCDetails(__instance, i, ___kidsNames, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (__instance.names[i] is long && narrateFarmerDetails(__instance, i, ___sprites, x, y))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateNPCDetails(SocialPage __instance, int i, List<string> ___kidsNames, int x, int y)
|
||||||
|
{
|
||||||
|
if (!__instance.characterSlots[i].bounds.Contains(x, y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
string name = $"{__instance.names[i] as string}";
|
||||||
|
int heartLevel = Game1.player.getFriendshipHeartLevelForNPC(name);
|
||||||
|
bool datable = SocialPage.isDatable(name);
|
||||||
|
Friendship friendship = __instance.getFriendship(name);
|
||||||
|
int giftsThisWeek = friendship.GiftsThisWeek;
|
||||||
|
bool hasTalked = Game1.player.hasPlayerTalkedToNPC(name);
|
||||||
|
bool spouse = friendship.IsMarried();
|
||||||
|
bool housemate = spouse && SocialPage.isRoommateOfAnyone(name);
|
||||||
|
___kidsNames.Add("Robin");
|
||||||
|
___kidsNames.Add("Pierre");
|
||||||
|
___kidsNames.Add("Caroline");
|
||||||
|
___kidsNames.Add("Jodi");
|
||||||
|
___kidsNames.Add("Kent");
|
||||||
|
___kidsNames.Add("George");
|
||||||
|
___kidsNames.Add("Evelyn");
|
||||||
|
___kidsNames.Add("Demetrius");
|
||||||
|
|
||||||
|
string toSpeak = $"{name}";
|
||||||
|
|
||||||
|
if (!hasTalked)
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak}, not talked yet";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (datable | housemate)
|
||||||
|
{
|
||||||
|
string text2 = (LocalizedContentManager.CurrentLanguageCode != LocalizedContentManager.LanguageCode.pt) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635") : ((__instance.getGender(name) == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635").Split('/').First() : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635").Split('/').Last());
|
||||||
|
if (housemate)
|
||||||
|
{
|
||||||
|
text2 = Game1.content.LoadString("Strings\\StringsFromCSFiles:Housemate");
|
||||||
|
}
|
||||||
|
else if (spouse)
|
||||||
|
{
|
||||||
|
text2 = ((__instance.getGender(name) == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11636") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11637"));
|
||||||
|
}
|
||||||
|
else if (__instance.isMarriedToAnyone(name))
|
||||||
|
{
|
||||||
|
text2 = ((__instance.getGender(name) == 0) ? Game1.content.LoadString("Strings\\UI:SocialPage_MarriedToOtherPlayer_MaleNPC") : Game1.content.LoadString("Strings\\UI:SocialPage_MarriedToOtherPlayer_FemaleNPC"));
|
||||||
|
}
|
||||||
|
else if (!Game1.player.isMarried() && friendship.IsDating())
|
||||||
|
{
|
||||||
|
text2 = ((__instance.getGender(name) == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11639") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11640"));
|
||||||
|
}
|
||||||
|
else if (__instance.getFriendship(name).IsDivorced())
|
||||||
|
{
|
||||||
|
text2 = ((__instance.getGender(name) == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11642") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11643"));
|
||||||
|
}
|
||||||
|
|
||||||
|
toSpeak = $"{toSpeak}, {text2}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!__instance.getFriendship(name).IsMarried() && ___kidsNames.Contains(name))
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak}, married";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spouse)
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak}, spouse";
|
||||||
|
}
|
||||||
|
else if (friendship.IsDating())
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak}, dating";
|
||||||
|
}
|
||||||
|
|
||||||
|
toSpeak = $"{toSpeak}, {heartLevel} hearts, {giftsThisWeek} gifts given this week.";
|
||||||
|
|
||||||
|
if (socialPageQuery != toSpeak)
|
||||||
|
{
|
||||||
|
socialPageQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateFarmerDetails(SocialPage __instance, int i, List<ClickableTextureComponent> ___sprites, int x, int y)
|
||||||
|
{
|
||||||
|
long farmerID = (long)__instance.names[i];
|
||||||
|
Farmer farmer = Game1.getFarmerMaybeOffline(farmerID);
|
||||||
|
if (farmer == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int gender = (!farmer.IsMale) ? 1 : 0;
|
||||||
|
ClickableTextureComponent clickableTextureComponent = ___sprites[i];
|
||||||
|
if (!clickableTextureComponent.containsPoint(x, y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Friendship friendship = Game1.player.team.GetFriendship(Game1.player.UniqueMultiplayerID, farmerID);
|
||||||
|
bool spouse = friendship.IsMarried();
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
string text2 = (LocalizedContentManager.CurrentLanguageCode != LocalizedContentManager.LanguageCode.pt) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635") : ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635").Split('/').First() : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11635").Split('/').Last());
|
||||||
|
if (spouse)
|
||||||
|
{
|
||||||
|
text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11636") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11637"));
|
||||||
|
}
|
||||||
|
else if (farmer.isMarried() && !farmer.hasRoommate())
|
||||||
|
{
|
||||||
|
text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\UI:SocialPage_MarriedToOtherPlayer_MaleNPC") : Game1.content.LoadString("Strings\\UI:SocialPage_MarriedToOtherPlayer_FemaleNPC"));
|
||||||
|
}
|
||||||
|
else if (!Game1.player.isMarried() && friendship.IsDating())
|
||||||
|
{
|
||||||
|
text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11639") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11640"));
|
||||||
|
}
|
||||||
|
else if (friendship.IsDivorced())
|
||||||
|
{
|
||||||
|
text2 = ((gender == 0) ? Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11642") : Game1.content.LoadString("Strings\\StringsFromCSFiles:SocialPage.cs.11643"));
|
||||||
|
}
|
||||||
|
|
||||||
|
toSpeak = $"{farmer.displayName}, {text2}";
|
||||||
|
|
||||||
|
if (socialPageQuery != toSpeak)
|
||||||
|
{
|
||||||
|
socialPageQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
socialPageQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,801 +0,0 @@
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using stardew_access.Features;
|
|
||||||
using StardewModdingAPI;
|
|
||||||
using StardewValley;
|
|
||||||
using StardewValley.Buildings;
|
|
||||||
using StardewValley.Menus;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
|
||||||
{
|
|
||||||
internal class MenuPatches
|
|
||||||
{
|
|
||||||
internal static string currentLevelUpTitle = " ";
|
|
||||||
internal static bool firstTimeInNamingMenu = true;
|
|
||||||
internal static bool isNarratingPondInfo = false;
|
|
||||||
internal static string tailoringMenuQuery = " ";
|
|
||||||
internal static string pondQueryMenuQuery = " ";
|
|
||||||
internal static string forgeMenuQuery = " ";
|
|
||||||
internal static string itemListMenuQuery = " ";
|
|
||||||
public static Vector2? prevTile = null;
|
|
||||||
|
|
||||||
internal static void ItemListMenuPatch(ItemListMenu __instance, string ___title, int ___currentTab, int ___totalValueOfItems, List<Item> ___itemsToList)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = " ", currentList = " ";
|
|
||||||
|
|
||||||
for (int i = ___currentTab * __instance.itemsPerCategoryPage; i < ___currentTab * __instance.itemsPerCategoryPage + __instance.itemsPerCategoryPage; i++)
|
|
||||||
{
|
|
||||||
if (i == 0)
|
|
||||||
currentList = ___title;
|
|
||||||
|
|
||||||
if (___itemsToList.Count > i)
|
|
||||||
{
|
|
||||||
if (___itemsToList[i] == null)
|
|
||||||
{
|
|
||||||
currentList = $"{currentList}, \n" + Game1.content.LoadString("Strings\\UI:ItemList_ItemsLostValue", ___totalValueOfItems);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
currentList = $"{currentList}, \n {___itemsToList[i].Stack} {___itemsToList[i].DisplayName}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
toSpeak = $"Page {___currentTab + 1} of {((int)___itemsToList.Count / __instance.itemsPerCategoryPage) + 1} \n {currentList} \n ok button";
|
|
||||||
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Next page button";
|
|
||||||
else if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Previous page button";
|
|
||||||
|
|
||||||
if (itemListMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
itemListMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ForgeMenuPatch(ForgeMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = " ";
|
|
||||||
|
|
||||||
if (__instance.leftIngredientSpot != null && __instance.leftIngredientSpot.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if (__instance.leftIngredientSpot.item == null)
|
|
||||||
{
|
|
||||||
toSpeak = "Input weapon or tool here";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Item item = __instance.leftIngredientSpot.item;
|
|
||||||
toSpeak = $"Weapon slot: {item.Stack} {item.DisplayName}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__instance.rightIngredientSpot != null && __instance.rightIngredientSpot.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if (__instance.rightIngredientSpot.item == null)
|
|
||||||
{
|
|
||||||
toSpeak = "Input gemstone here";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Item item = __instance.rightIngredientSpot.item;
|
|
||||||
toSpeak = $"Gemstone slot: {item.Stack} {item.DisplayName}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__instance.startTailoringButton != null && __instance.startTailoringButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Star forging button";
|
|
||||||
}
|
|
||||||
else if (__instance.unforgeButton != null && __instance.unforgeButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Unforge button";
|
|
||||||
}
|
|
||||||
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Trashcan";
|
|
||||||
}
|
|
||||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "ok button";
|
|
||||||
}
|
|
||||||
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "drop item";
|
|
||||||
}
|
|
||||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[0].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Left ring Slot";
|
|
||||||
|
|
||||||
if (Game1.player.leftRing.Value != null)
|
|
||||||
toSpeak = $"{toSpeak}: {Game1.player.leftRing.Value.DisplayName}";
|
|
||||||
}
|
|
||||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[1].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Right ring Slot";
|
|
||||||
|
|
||||||
if (Game1.player.rightRing.Value != null)
|
|
||||||
toSpeak = $"{toSpeak}: {Game1.player.rightRing.Value.DisplayName}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < __instance.inventory.inventory.Count; i++)
|
|
||||||
{
|
|
||||||
if (!__instance.inventory.inventory[i].containsPoint(x, y))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (__instance.inventory.actualInventory[i] == null)
|
|
||||||
toSpeak = "Empty slot";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toSpeak = $"{__instance.inventory.actualInventory[i].Stack} {__instance.inventory.actualInventory[i].DisplayName}";
|
|
||||||
|
|
||||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[i]))
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} not usable here";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forgeMenuQuery != $"{toSpeak}:{i}")
|
|
||||||
{
|
|
||||||
forgeMenuQuery = $"{toSpeak}:{i}";
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (forgeMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
forgeMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
|
|
||||||
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
|
||||||
Game1.playSound("drop_item");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void PondQueryMenuPatch(PondQueryMenu __instance, StardewValley.Object ____fishItem, FishPond ____pond, string ____statusText, bool ___confirmingEmpty)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
|
||||||
string toSpeak = " ", extra = "";
|
|
||||||
|
|
||||||
if (___confirmingEmpty)
|
|
||||||
{
|
|
||||||
if (__instance.yesButton != null && __instance.yesButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Confirm button";
|
|
||||||
else if (__instance.noButton != null && __instance.noButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Cancel button";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (isPrimaryInfoKeyPressed && !isNarratingPondInfo)
|
|
||||||
{
|
|
||||||
string pond_name_text = Game1.content.LoadString("Strings\\UI:PondQuery_Name", ____fishItem.DisplayName);
|
|
||||||
string population_text = Game1.content.LoadString("Strings\\UI:PondQuery_Population", string.Concat(____pond.FishCount), ____pond.maxOccupants.Value);
|
|
||||||
bool has_unresolved_needs = ____pond.neededItem.Value != null && ____pond.HasUnresolvedNeeds() && !____pond.hasCompletedRequest.Value;
|
|
||||||
string bring_text = "";
|
|
||||||
|
|
||||||
if (has_unresolved_needs && ____pond.neededItem.Value != null)
|
|
||||||
bring_text = Game1.content.LoadString("Strings\\UI:PondQuery_StatusRequest_Bring") + $": {____pond.neededItemCount} {____pond.neededItem.Value.DisplayName}";
|
|
||||||
|
|
||||||
extra = $"{pond_name_text} {population_text} {bring_text} Status: {____statusText}";
|
|
||||||
pondQueryMenuQuery = " ";
|
|
||||||
|
|
||||||
isNarratingPondInfo = true;
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isNarratingPondInfo = false; });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Ok button";
|
|
||||||
else if (__instance.changeNettingButton != null && __instance.changeNettingButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Change netting button";
|
|
||||||
else if (__instance.emptyButton != null && __instance.emptyButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Empty pond button";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pondQueryMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
pondQueryMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void TailoringMenuPatch(TailoringMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = " ";
|
|
||||||
|
|
||||||
if (__instance.leftIngredientSpot != null && __instance.leftIngredientSpot.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if (__instance.leftIngredientSpot.item == null)
|
|
||||||
{
|
|
||||||
toSpeak = "Input cloth here";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Item item = __instance.leftIngredientSpot.item;
|
|
||||||
toSpeak = $"Cloth slot: {item.Stack} {item.DisplayName}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__instance.rightIngredientSpot != null && __instance.rightIngredientSpot.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if (__instance.rightIngredientSpot.item == null)
|
|
||||||
{
|
|
||||||
toSpeak = "Input ingredient here";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Item item = __instance.rightIngredientSpot.item;
|
|
||||||
toSpeak = $"Ingredient slot: {item.Stack} {item.DisplayName}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (__instance.startTailoringButton != null && __instance.startTailoringButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Star tailoring button";
|
|
||||||
}
|
|
||||||
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Trashcan";
|
|
||||||
}
|
|
||||||
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "ok button";
|
|
||||||
}
|
|
||||||
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "drop item";
|
|
||||||
}
|
|
||||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[0].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Hat Slot";
|
|
||||||
|
|
||||||
if (Game1.player.hat.Value != null)
|
|
||||||
toSpeak = $"{toSpeak}: {Game1.player.hat.Value.DisplayName}";
|
|
||||||
}
|
|
||||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[1].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Shirt Slot";
|
|
||||||
|
|
||||||
if (Game1.player.shirtItem.Value != null)
|
|
||||||
toSpeak = $"{toSpeak}: {Game1.player.shirtItem.Value.DisplayName}";
|
|
||||||
}
|
|
||||||
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[2].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak = "Pants Slot";
|
|
||||||
|
|
||||||
if (Game1.player.pantsItem.Value != null)
|
|
||||||
toSpeak = $"{toSpeak}: {Game1.player.pantsItem.Value.DisplayName}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < __instance.inventory.inventory.Count; i++)
|
|
||||||
{
|
|
||||||
if (!__instance.inventory.inventory[i].containsPoint(x, y))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (__instance.inventory.actualInventory[i] == null)
|
|
||||||
toSpeak = "Empty slot";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
toSpeak = $"{__instance.inventory.actualInventory[i].Stack} {__instance.inventory.actualInventory[i].DisplayName}";
|
|
||||||
|
|
||||||
if (!__instance.inventory.highlightMethod(__instance.inventory.actualInventory[i]))
|
|
||||||
{
|
|
||||||
toSpeak = $"{toSpeak} not usable here";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tailoringMenuQuery != $"{toSpeak}:{i}")
|
|
||||||
{
|
|
||||||
tailoringMenuQuery = $"{toSpeak}:{i}";
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (tailoringMenuQuery != toSpeak)
|
|
||||||
{
|
|
||||||
tailoringMenuQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
|
|
||||||
if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
|
||||||
Game1.playSound("drop_item");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ChooseFromListMenuPatch(ChooseFromListMenu __instance, List<string> ___options, int ___index, bool ___isJukebox)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = "";
|
|
||||||
|
|
||||||
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Select " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[___index]) : ___options[___index]) + " button";
|
|
||||||
else if (__instance.cancelButton != null && __instance.cancelButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Cancel button";
|
|
||||||
else if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Previous option: " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[Math.Max(0, ___index - 1)]) : ___options[Math.Max(0, ___index - 1)]) + " button";
|
|
||||||
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Next option: " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[Math.Min(___options.Count, ___index + 1)]) : ___options[Math.Min(___options.Count, ___index + 1)]) + " button";
|
|
||||||
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool PlaySoundPatch(string cueName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!Context.IsPlayerFree)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (!Game1.player.isMoving())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (cueName == "grassyStep" || cueName == "sandyStep" || cueName == "snowyStep" || cueName == "stoneStep" || cueName == "thudStep" || cueName == "woodyStep")
|
|
||||||
{
|
|
||||||
Vector2 nextTile = CurrentPlayer.FacingTile;
|
|
||||||
if (TileInfo.isCollidingAtTile((int)nextTile.X, (int)nextTile.Y))
|
|
||||||
{
|
|
||||||
if (prevTile != nextTile)
|
|
||||||
{
|
|
||||||
prevTile = nextTile;
|
|
||||||
//Game1.playSound("colliding");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void LanguageSelectionMenuPatch(LanguageSelectionMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
|
|
||||||
if (__instance.nextPageButton != null && __instance.nextPageButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker($"Next Page Button", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.previousPageButton != null && __instance.previousPageButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker($"Previous Page Button", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < __instance.languages.Count; i++)
|
|
||||||
{
|
|
||||||
if (__instance.languages[i].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker($"{__instance.languageList[i]} Button", true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void MineElevatorMenuPatch(List<ClickableComponent> ___elevators)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
for (int i = 0; i < ___elevators.Count; i++)
|
|
||||||
{
|
|
||||||
if (___elevators[i].containsPoint(x, y))
|
|
||||||
{
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker($"{___elevators[i].name} level", true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void TitleTextInputMenuPatch(TitleTextInputMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string toSpeak = "";
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
|
|
||||||
if (__instance.pasteButton != null && __instance.pasteButton.containsPoint(x, y))
|
|
||||||
toSpeak = $"Paste button";
|
|
||||||
|
|
||||||
if (toSpeak != "")
|
|
||||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void NamingMenuPatch(NamingMenu __instance, TextBox ___textBox, string ___title)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string toSpeak = "";
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
|
||||||
|
|
||||||
if (firstTimeInNamingMenu)
|
|
||||||
{
|
|
||||||
firstTimeInNamingMenu = false;
|
|
||||||
___textBox.Selected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (___textBox.Selected)
|
|
||||||
{
|
|
||||||
___textBox.Update();
|
|
||||||
toSpeak = ___textBox.Text;
|
|
||||||
|
|
||||||
if (isEscPressed)
|
|
||||||
{
|
|
||||||
___textBox.Selected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
|
||||||
toSpeak = $"{___title} text box";
|
|
||||||
else if (__instance.doneNamingButton != null && __instance.doneNamingButton.containsPoint(x, y))
|
|
||||||
toSpeak = $"Done naming button";
|
|
||||||
else if (__instance.randomButton != null && __instance.randomButton.containsPoint(x, y))
|
|
||||||
toSpeak = $"Random button";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toSpeak != "")
|
|
||||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ConfirmationDialogPatch(ConfirmationDialog __instance, string ___message)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
|
||||||
string toSpeak = ___message;
|
|
||||||
|
|
||||||
if (__instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak += "\n\tOk Button";
|
|
||||||
}
|
|
||||||
else if (__instance.cancelButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
toSpeak += "\n\tCancel Button";
|
|
||||||
}
|
|
||||||
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void LevelUpMenuPatch(LevelUpMenu __instance, List<int> ___professionsToChoose, List<string> ___leftProfessionDescription, List<string> ___rightProfessionDescription, List<string> ___extraInfoForLevel, List<CraftingRecipe> ___newCraftingRecipes, string ___title, bool ___isActive, bool ___isProfessionChooser)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
|
||||||
string leftProfession = " ", rightProfession = " ", extraInfo = " ", newCraftingRecipe = " ", toSpeak = " ";
|
|
||||||
|
|
||||||
if (!__instance.informationUp)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (__instance.isProfessionChooser)
|
|
||||||
{
|
|
||||||
if (___professionsToChoose.Count() == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (int j = 0; j < ___leftProfessionDescription.Count; j++)
|
|
||||||
{
|
|
||||||
leftProfession += ___leftProfessionDescription[j] + ", ";
|
|
||||||
}
|
|
||||||
for (int i = 0; i < ___rightProfessionDescription.Count; i++)
|
|
||||||
{
|
|
||||||
rightProfession += ___rightProfessionDescription[i] + ", ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.leftProfession.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if ((MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed()) && __instance.readyToClose())
|
|
||||||
{
|
|
||||||
Game1.player.professions.Add(___professionsToChoose[0]);
|
|
||||||
__instance.getImmediateProfessionPerk(___professionsToChoose[0]);
|
|
||||||
___isActive = false;
|
|
||||||
__instance.informationUp = false;
|
|
||||||
___isProfessionChooser = false;
|
|
||||||
__instance.RemoveLevelFromLevelList();
|
|
||||||
__instance.exitThisMenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
toSpeak = $"Selected: {leftProfession} Left click to choose.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.rightProfession.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if ((MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed()) && __instance.readyToClose())
|
|
||||||
{
|
|
||||||
Game1.player.professions.Add(___professionsToChoose[1]);
|
|
||||||
__instance.getImmediateProfessionPerk(___professionsToChoose[1]);
|
|
||||||
___isActive = false;
|
|
||||||
__instance.informationUp = false;
|
|
||||||
___isProfessionChooser = false;
|
|
||||||
__instance.RemoveLevelFromLevelList();
|
|
||||||
__instance.exitThisMenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
toSpeak = $"Selected: {rightProfession} Left click to choose.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (string s2 in ___extraInfoForLevel)
|
|
||||||
{
|
|
||||||
extraInfo += s2 + ", ";
|
|
||||||
}
|
|
||||||
foreach (CraftingRecipe s in ___newCraftingRecipes)
|
|
||||||
{
|
|
||||||
string cookingOrCrafting = Game1.content.LoadString("Strings\\UI:LearnedRecipe_" + (s.isCookingRecipe ? "cooking" : "crafting"));
|
|
||||||
string message = Game1.content.LoadString("Strings\\UI:LevelUp_NewRecipe", cookingOrCrafting, s.DisplayName);
|
|
||||||
|
|
||||||
newCraftingRecipe += $"{message}, ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.okButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
if (MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed())
|
|
||||||
__instance.okButtonClicked();
|
|
||||||
|
|
||||||
toSpeak = $"{___title} {extraInfo} {newCraftingRecipe}. Left click to close.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toSpeak != " ")
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
|
||||||
else if (__instance.isProfessionChooser && currentLevelUpTitle != $"{___title}. Select a new profession.")
|
|
||||||
{
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker($"{___title}. Select a new profession.", true);
|
|
||||||
currentLevelUpTitle = $"{___title}. Select a new profession.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void ShippingMenuPatch(ShippingMenu __instance, List<int> ___categoryTotals)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
|
|
||||||
if (__instance.currentPage == -1)
|
|
||||||
{
|
|
||||||
int total = ___categoryTotals[5];
|
|
||||||
string toSpeak;
|
|
||||||
if (__instance.okButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
|
||||||
{
|
|
||||||
// Perform Left Click
|
|
||||||
if (MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed())
|
|
||||||
{
|
|
||||||
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
|
||||||
}
|
|
||||||
toSpeak = $"{total}g in total. Press left mouse button to save.";
|
|
||||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < __instance.categories.Count; i++)
|
|
||||||
{
|
|
||||||
if (__instance.categories[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
|
||||||
{
|
|
||||||
toSpeak = $"Money recieved from {__instance.getCategoryName(i)}: {___categoryTotals[i]}g.";
|
|
||||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Cleanup on exitting a menu
|
|
||||||
internal static void Game1ExitActiveMenuPatch()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Cleanup(Game1.activeClickableMenu);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void IClickableMenuOnExitPatch(IClickableMenu __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Cleanup(__instance);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Cleanup(IClickableMenu menu)
|
|
||||||
{
|
|
||||||
if (menu is LetterViewerMenu)
|
|
||||||
{
|
|
||||||
DialoguePatches.currentLetterText = " ";
|
|
||||||
}
|
|
||||||
else if (menu is LevelUpMenu)
|
|
||||||
{
|
|
||||||
currentLevelUpTitle = " ";
|
|
||||||
}
|
|
||||||
else if (menu is Billboard)
|
|
||||||
{
|
|
||||||
QuestPatches.currentDailyQuestText = " ";
|
|
||||||
}
|
|
||||||
else if (menu is GameMenu)
|
|
||||||
{
|
|
||||||
GameMenuPatches.gameMenuQueryKey = "";
|
|
||||||
GameMenuPatches.craftingPageQueryKey = "";
|
|
||||||
GameMenuPatches.inventoryPageQueryKey = "";
|
|
||||||
GameMenuPatches.exitPageQueryKey = "";
|
|
||||||
GameMenuPatches.optionsPageQueryKey = "";
|
|
||||||
GameMenuPatches.socialPageQuery = "";
|
|
||||||
GameMenuPatches.currentSelectedCraftingRecipe = -1;
|
|
||||||
GameMenuPatches.isSelectingRecipe = false;
|
|
||||||
}
|
|
||||||
else if (menu is JunimoNoteMenu)
|
|
||||||
{
|
|
||||||
BundleMenuPatches.currentIngredientListItem = -1;
|
|
||||||
BundleMenuPatches.currentIngredientInputSlot = -1;
|
|
||||||
BundleMenuPatches.currentInventorySlot = -1;
|
|
||||||
BundleMenuPatches.junimoNoteMenuQuery = "";
|
|
||||||
}
|
|
||||||
else if (menu is ShopMenu)
|
|
||||||
{
|
|
||||||
GameMenuPatches.shopMenuQueryKey = "";
|
|
||||||
}
|
|
||||||
else if (menu is ItemGrabMenu)
|
|
||||||
{
|
|
||||||
GameMenuPatches.itemGrabMenuQueryKey = "";
|
|
||||||
}
|
|
||||||
else if (menu is GeodeMenu)
|
|
||||||
{
|
|
||||||
GameMenuPatches.geodeMenuQueryKey = "";
|
|
||||||
}
|
|
||||||
else if (menu is CarpenterMenu)
|
|
||||||
{
|
|
||||||
BuildingNAnimalMenuPatches.carpenterMenuQuery = "";
|
|
||||||
BuildingNAnimalMenuPatches.isUpgrading = false;
|
|
||||||
BuildingNAnimalMenuPatches.isDemolishing = false;
|
|
||||||
BuildingNAnimalMenuPatches.isPainting = false;
|
|
||||||
BuildingNAnimalMenuPatches.isMoving = false;
|
|
||||||
BuildingNAnimalMenuPatches.isConstructing = false;
|
|
||||||
BuildingNAnimalMenuPatches.carpenterMenu = null;
|
|
||||||
}
|
|
||||||
else if (menu is PurchaseAnimalsMenu)
|
|
||||||
{
|
|
||||||
BuildingNAnimalMenuPatches.purchaseAnimalMenuQuery = "";
|
|
||||||
BuildingNAnimalMenuPatches.firstTimeInNamingMenu = true;
|
|
||||||
BuildingNAnimalMenuPatches.purchaseAnimalsMenu = null;
|
|
||||||
}
|
|
||||||
else if (menu is DialogueBox)
|
|
||||||
{
|
|
||||||
DialoguePatches.isDialogueAppearingFirstTime = true;
|
|
||||||
DialoguePatches.currentDialogue = " ";
|
|
||||||
}
|
|
||||||
else if (menu is JojaCDMenu)
|
|
||||||
{
|
|
||||||
BundleMenuPatches.jojaCDMenuQuery = "";
|
|
||||||
}
|
|
||||||
else if (menu is QuestLog)
|
|
||||||
{
|
|
||||||
QuestPatches.questLogQuery = " ";
|
|
||||||
}
|
|
||||||
else if (menu is TailoringMenu)
|
|
||||||
{
|
|
||||||
tailoringMenuQuery = " ";
|
|
||||||
}
|
|
||||||
else if (menu is ForgeMenu)
|
|
||||||
{
|
|
||||||
forgeMenuQuery = " ";
|
|
||||||
}
|
|
||||||
else if (menu is ItemListMenu)
|
|
||||||
{
|
|
||||||
itemListMenuQuery = " ";
|
|
||||||
}
|
|
||||||
else if (menu is FieldOfficeMenu)
|
|
||||||
{
|
|
||||||
DonationMenuPatches.fieldOfficeMenuQuery = " ";
|
|
||||||
}
|
|
||||||
else if (menu is MuseumMenu)
|
|
||||||
{
|
|
||||||
DonationMenuPatches.museumQueryKey = " ";
|
|
||||||
}
|
|
||||||
else if (menu is PondQueryMenu)
|
|
||||||
{
|
|
||||||
pondQueryMenuQuery = " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
GameMenuPatches.hoveredItemQueryKey = "";
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
internal static void ExitEventPatch()
|
|
||||||
{
|
|
||||||
if (MainClass.ScreenReader != null)
|
|
||||||
MainClass.ScreenReader.CloseScreenReader();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ForgeMenuPatch
|
||||||
|
{
|
||||||
|
private static string forgeMenuQuery = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(ForgeMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (narrateHoveredButton(__instance, x, y)) return;
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y))
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in forge menu patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButton(ForgeMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.leftIngredientSpot != null && __instance.leftIngredientSpot.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if (__instance.leftIngredientSpot.item == null)
|
||||||
|
{
|
||||||
|
toSpeak = "Input weapon or tool here";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Item item = __instance.leftIngredientSpot.item;
|
||||||
|
toSpeak = $"Weapon slot: {item.Stack} {item.DisplayName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (__instance.rightIngredientSpot != null && __instance.rightIngredientSpot.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if (__instance.rightIngredientSpot.item == null)
|
||||||
|
{
|
||||||
|
toSpeak = "Input gemstone here";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Item item = __instance.rightIngredientSpot.item;
|
||||||
|
toSpeak = $"Gemstone slot: {item.Stack} {item.DisplayName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (__instance.startTailoringButton != null && __instance.startTailoringButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Star forging button";
|
||||||
|
}
|
||||||
|
else if (__instance.unforgeButton != null && __instance.unforgeButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Unforge button";
|
||||||
|
}
|
||||||
|
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trashcan";
|
||||||
|
}
|
||||||
|
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "ok button";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "drop item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[0].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Left ring Slot";
|
||||||
|
|
||||||
|
if (Game1.player.leftRing.Value != null)
|
||||||
|
toSpeak = $"{toSpeak}: {Game1.player.leftRing.Value.DisplayName}";
|
||||||
|
}
|
||||||
|
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[1].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Right ring Slot";
|
||||||
|
|
||||||
|
if (Game1.player.rightRing.Value != null)
|
||||||
|
toSpeak = $"{toSpeak}: {Game1.player.rightRing.Value.DisplayName}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forgeMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
forgeMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
forgeMenuQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class GeodeMenuPatch
|
||||||
|
{
|
||||||
|
private static string geodeMenuQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(GeodeMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (narrateRecievedTreasure(__instance)) return;
|
||||||
|
if (narrateHoveredButton(__instance, x, y)) return;
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y))
|
||||||
|
geodeMenuQueryKey = "";
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateRecievedTreasure(GeodeMenu __instance)
|
||||||
|
{
|
||||||
|
// Narrates the treasure recieved on breaking the geode
|
||||||
|
if (__instance.geodeTreasure == null) return false;
|
||||||
|
|
||||||
|
string name = __instance.geodeTreasure.DisplayName;
|
||||||
|
int stack = __instance.geodeTreasure.Stack;
|
||||||
|
|
||||||
|
string toSpeak = $"Recieved {stack} {name}";
|
||||||
|
|
||||||
|
if (geodeMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
geodeMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButton(GeodeMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.geodeSpot != null && __instance.geodeSpot.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Place geode here";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Drop item here";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trash can";
|
||||||
|
}
|
||||||
|
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Ok button";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geodeMenuQueryKey == toSpeak) return true;
|
||||||
|
|
||||||
|
geodeMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
geodeMenuQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,230 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ItemGrabMenuPatch
|
||||||
|
{
|
||||||
|
internal static string itemGrabMenuQueryKey = "";
|
||||||
|
internal static string hoveredItemQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(ItemGrabMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (MainClass.Config.SnapToFirstSecondaryInventorySlotKey.JustPressed() && __instance.ItemsToGrabMenu.inventory.Count > 0 && !__instance.shippingBin)
|
||||||
|
{
|
||||||
|
__instance.setCurrentlySnappedComponentTo(__instance.ItemsToGrabMenu.inventory[0].myID);
|
||||||
|
__instance.ItemsToGrabMenu.inventory[0].snapMouseCursorToCenter();
|
||||||
|
}
|
||||||
|
else if (MainClass.Config.SnapToFirstInventorySlotKey.JustPressed() && __instance.inventory.inventory.Count > 0)
|
||||||
|
{
|
||||||
|
__instance.setCurrentlySnappedComponentTo(__instance.inventory.inventory[0].myID);
|
||||||
|
__instance.inventory.inventory[0].snapMouseCursorToCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (narrateHoveredButton(__instance, x, y))
|
||||||
|
{
|
||||||
|
InventoryUtils.Cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (narrateLastShippedItem(__instance, x, y))
|
||||||
|
{
|
||||||
|
InventoryUtils.Cleanup();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y, true))
|
||||||
|
{
|
||||||
|
itemGrabMenuQueryKey = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.ItemsToGrabMenu, __instance.ItemsToGrabMenu.inventory, __instance.ItemsToGrabMenu.actualInventory, x, y, true))
|
||||||
|
{
|
||||||
|
itemGrabMenuQueryKey = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButton(ItemGrabMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Ok Button";
|
||||||
|
}
|
||||||
|
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trash Can";
|
||||||
|
}
|
||||||
|
else if (__instance.organizeButton != null && __instance.organizeButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Organize Button";
|
||||||
|
}
|
||||||
|
else if (__instance.fillStacksButton != null && __instance.fillStacksButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Add to existing stacks button";
|
||||||
|
}
|
||||||
|
else if (__instance.specialButton != null && __instance.specialButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Special Button";
|
||||||
|
}
|
||||||
|
else if (__instance.colorPickerToggleButton != null && __instance.colorPickerToggleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Color Picker: " + (__instance.chestColorPicker.visible ? "Enabled" : "Disabled");
|
||||||
|
}
|
||||||
|
else if (__instance.junimoNoteIcon != null && __instance.junimoNoteIcon.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Community Center Button";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Drop Item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
/*if (__instance.discreteColorPickerCC.Count > 0) {
|
||||||
|
for (int i = 0; i < __instance.discreteColorPickerCC.Count; i++)
|
||||||
|
{
|
||||||
|
if (__instance.discreteColorPickerCC[i].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
MainClass.monitor.Log(i.ToString(), LogLevel.Debug);
|
||||||
|
string toSpeak = getChestColorName(i);
|
||||||
|
if (itemGrabMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
itemGrabMenuQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
ScreenReader.say(toSpeak, true);
|
||||||
|
Game1.playSound("sa_drop_item");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (itemGrabMenuQueryKey == toSpeak) return true;
|
||||||
|
|
||||||
|
itemGrabMenuQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateLastShippedItem(ItemGrabMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
if (!__instance.shippingBin || Game1.getFarm().lastItemShipped == null || !__instance.lastShippedHolder.containsPoint(x, y))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Item lastShippedItem = Game1.getFarm().lastItemShipped;
|
||||||
|
string name = lastShippedItem.DisplayName;
|
||||||
|
int count = lastShippedItem.Stack;
|
||||||
|
|
||||||
|
string toSpeak = $"Last Shipped: {count} {name}";
|
||||||
|
|
||||||
|
if (itemGrabMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
itemGrabMenuQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add color names
|
||||||
|
private static string getChestColorName(int i)
|
||||||
|
{
|
||||||
|
string toReturn = "";
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
toReturn = "Default chest color";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
itemGrabMenuQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ShopMenuPatch
|
||||||
|
{
|
||||||
|
internal static string shopMenuQueryKey = "";
|
||||||
|
internal static string hoveredItemQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(ShopMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (MainClass.Config.SnapToFirstSecondaryInventorySlotKey.JustPressed() && __instance.forSaleButtons.Count > 0)
|
||||||
|
{
|
||||||
|
__instance.forSaleButtons[0].snapMouseCursorToCenter();
|
||||||
|
__instance.setCurrentlySnappedComponentTo(__instance.forSaleButtons[0].myID);
|
||||||
|
}
|
||||||
|
else if (MainClass.Config.SnapToFirstInventorySlotKey.JustPressed() && __instance.inventory.inventory.Count > 0)
|
||||||
|
{
|
||||||
|
__instance.inventory.inventory[0].snapMouseCursorToCenter();
|
||||||
|
__instance.setCurrentlySnappedComponentTo(__instance.inventory.inventory[0].myID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (narrateHoveredButton(__instance, x, y)) return;
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y, hoverPrice: __instance.hoverPrice))
|
||||||
|
{
|
||||||
|
shopMenuQueryKey = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
narrateHoveredSellingItem(__instance);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButton(ShopMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.inventory.dropItemInvisibleButton != null && __instance.inventory.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Drop Item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else if (__instance.upArrow != null && __instance.upArrow.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Up Arrow Button";
|
||||||
|
}
|
||||||
|
else if (__instance.downArrow != null && __instance.downArrow.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Down Arrow Button";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shopMenuQueryKey == toSpeak) return true;
|
||||||
|
|
||||||
|
shopMenuQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateHoveredSellingItem(ShopMenu __instance)
|
||||||
|
{
|
||||||
|
if (__instance.hoveredItem == null) return;
|
||||||
|
|
||||||
|
string name = __instance.hoveredItem.DisplayName;
|
||||||
|
string price = $"Buy Price: {__instance.hoverPrice} g";
|
||||||
|
string description = __instance.hoveredItem.getDescription();
|
||||||
|
string requirements = "";
|
||||||
|
|
||||||
|
#region get required items for item
|
||||||
|
int itemIndex = -1, itemAmount = 5;
|
||||||
|
|
||||||
|
if (__instance.itemPriceAndStock[__instance.hoveredItem].Length > 2)
|
||||||
|
itemIndex = __instance.itemPriceAndStock[__instance.hoveredItem][2];
|
||||||
|
|
||||||
|
if (__instance.itemPriceAndStock[__instance.hoveredItem].Length > 3)
|
||||||
|
itemAmount = __instance.itemPriceAndStock[__instance.hoveredItem][3];
|
||||||
|
|
||||||
|
if (itemIndex != -1)
|
||||||
|
{
|
||||||
|
string itemName = Game1.objectInformation[itemIndex].Split('/')[0];
|
||||||
|
|
||||||
|
if (itemAmount != -1)
|
||||||
|
requirements = $"Required: {itemAmount} {itemName}";
|
||||||
|
else
|
||||||
|
requirements = $"Required: {itemName}";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
string toSpeak = $"{name}, {requirements}, {price}, \n\t{description}";
|
||||||
|
if (shopMenuQueryKey == toSpeak) return;
|
||||||
|
|
||||||
|
shopMenuQueryKey = toSpeak;
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
shopMenuQueryKey = "";
|
||||||
|
hoveredItemQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class TailoringMenuPatch
|
||||||
|
{
|
||||||
|
internal static string tailoringMenuQuery = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(TailoringMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (InventoryUtils.narrateHoveredSlot(__instance.inventory, __instance.inventory.inventory, __instance.inventory.actualInventory, x, y))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateHoveredButton(TailoringMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
bool isDropItemButton = false;
|
||||||
|
|
||||||
|
if (__instance.leftIngredientSpot != null && __instance.leftIngredientSpot.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if (__instance.leftIngredientSpot.item == null)
|
||||||
|
{
|
||||||
|
toSpeak = "Input cloth here";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Item item = __instance.leftIngredientSpot.item;
|
||||||
|
toSpeak = $"Cloth slot: {item.Stack} {item.DisplayName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (__instance.rightIngredientSpot != null && __instance.rightIngredientSpot.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if (__instance.rightIngredientSpot.item == null)
|
||||||
|
{
|
||||||
|
toSpeak = "Input ingredient here";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Item item = __instance.rightIngredientSpot.item;
|
||||||
|
toSpeak = $"Ingredient slot: {item.Stack} {item.DisplayName}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (__instance.startTailoringButton != null && __instance.startTailoringButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Star tailoring button";
|
||||||
|
}
|
||||||
|
else if (__instance.trashCan != null && __instance.trashCan.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Trashcan";
|
||||||
|
}
|
||||||
|
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "ok button";
|
||||||
|
}
|
||||||
|
else if (__instance.dropItemInvisibleButton != null && __instance.dropItemInvisibleButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "drop item";
|
||||||
|
isDropItemButton = true;
|
||||||
|
}
|
||||||
|
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[0].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Hat Slot";
|
||||||
|
|
||||||
|
if (Game1.player.hat.Value != null)
|
||||||
|
toSpeak = $"{toSpeak}: {Game1.player.hat.Value.DisplayName}";
|
||||||
|
}
|
||||||
|
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[1].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Shirt Slot";
|
||||||
|
|
||||||
|
if (Game1.player.shirtItem.Value != null)
|
||||||
|
toSpeak = $"{toSpeak}: {Game1.player.shirtItem.Value.DisplayName}";
|
||||||
|
}
|
||||||
|
else if (__instance.equipmentIcons.Count > 0 && __instance.equipmentIcons[2].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Pants Slot";
|
||||||
|
|
||||||
|
if (Game1.player.pantsItem.Value != null)
|
||||||
|
toSpeak = $"{toSpeak}: {Game1.player.pantsItem.Value.DisplayName}";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tailoringMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
tailoringMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
|
||||||
|
if (isDropItemButton) Game1.playSound("drop_item");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
tailoringMenuQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,43 +4,11 @@ using StardewValley.Minigames;
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
namespace stardew_access.Patches
|
||||||
{
|
{
|
||||||
public class MiniGamesPatches
|
public class GrandpaStoryPatch
|
||||||
{
|
{
|
||||||
public static string grandpaStoryQuery = " ";
|
public static string grandpaStoryQuery = " ";
|
||||||
public static string introQuery = " ";
|
|
||||||
|
|
||||||
internal static void IntroPatch(Intro __instance, int ___currentState)
|
internal static void DrawPatch(GrandpaStory __instance, StardewValley.Menus.LetterViewerMenu ___letterView, bool ___drawGrandpa, bool ___letterReceived, bool ___mouseActive, Queue<string> ___grandpaSpeech, int ___grandpaSpeechTimer, int ___totalMilliseconds, int ___scene, int ___parallaxPan)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (MainClass.ModHelper == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string toSpeak = " ";
|
|
||||||
|
|
||||||
if (___currentState == 3)
|
|
||||||
{
|
|
||||||
toSpeak = MainClass.ModHelper.Translation.Get("intro.scene3");
|
|
||||||
}
|
|
||||||
else if (___currentState == 4)
|
|
||||||
{
|
|
||||||
toSpeak = MainClass.ModHelper.Translation.Get("intro.scene4");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toSpeak != " " && introQuery != toSpeak)
|
|
||||||
{
|
|
||||||
introQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void GrandpaStoryPatch(GrandpaStory __instance, StardewValley.Menus.LetterViewerMenu ___letterView, bool ___drawGrandpa, bool ___letterReceived, bool ___mouseActive, Queue<string> ___grandpaSpeech, int ___grandpaSpeechTimer, int ___totalMilliseconds, int ___scene, int ___parallaxPan)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -49,7 +17,7 @@ namespace stardew_access.Patches
|
||||||
|
|
||||||
if (___letterView != null)
|
if (___letterView != null)
|
||||||
{
|
{
|
||||||
DialoguePatches.NarrateLetterContent(___letterView);
|
LetterViwerMenuPatch.narrateLetterContent(___letterView);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MainClass.ModHelper == null)
|
if (MainClass.ModHelper == null)
|
|
@ -0,0 +1,40 @@
|
||||||
|
using StardewValley.Minigames;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
public class IntroPatch
|
||||||
|
{
|
||||||
|
public static string introQuery = " ";
|
||||||
|
|
||||||
|
internal static void DrawPatch(Intro __instance, int ___currentState)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (MainClass.ModHelper == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string toSpeak = " ";
|
||||||
|
|
||||||
|
if (___currentState == 3)
|
||||||
|
{
|
||||||
|
toSpeak = MainClass.ModHelper.Translation.Get("intro.scene3");
|
||||||
|
}
|
||||||
|
else if (___currentState == 4)
|
||||||
|
{
|
||||||
|
toSpeak = MainClass.ModHelper.Translation.Get("intro.scene4");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toSpeak != " " && introQuery != toSpeak)
|
||||||
|
{
|
||||||
|
introQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in intro minigame patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
using StardewValley;
|
using StardewValley.Menus;
|
||||||
using StardewValley.Menus;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
namespace stardew_access.Patches
|
||||||
{
|
{
|
||||||
internal class ChatMenuPatches
|
internal class ChatBoxPatch
|
||||||
{
|
{
|
||||||
private static int currentChatMessageIndex = 0;
|
private static int currentChatMessageIndex = 0;
|
||||||
private static bool isChatRunning = false;
|
private static bool isChatRunning = false;
|
||||||
|
|
||||||
internal static void ChatBoxPatch(ChatBox __instance, List<ChatMessage> ___messages)
|
internal static void UpdatePatch(ChatBox __instance, List<ChatMessage> ___messages)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -19,8 +18,8 @@ namespace stardew_access.Patches
|
||||||
bool isPrevButtonPressed = MainClass.Config.ChatMenuNextKey.JustPressed();
|
bool isPrevButtonPressed = MainClass.Config.ChatMenuNextKey.JustPressed();
|
||||||
bool isNextButtonPressed = MainClass.Config.ChatMenuPreviousKey.JustPressed();
|
bool isNextButtonPressed = MainClass.Config.ChatMenuPreviousKey.JustPressed();
|
||||||
|
|
||||||
if (___messages.Count > 0)
|
if (___messages.Count <= 0) return;
|
||||||
{
|
|
||||||
#region To narrate previous and next chat messages
|
#region To narrate previous and next chat messages
|
||||||
if (isNextButtonPressed && !isChatRunning)
|
if (isNextButtonPressed && !isChatRunning)
|
||||||
{
|
{
|
||||||
|
@ -36,7 +35,6 @@ namespace stardew_access.Patches
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (___messages.Count > 0)
|
else if (___messages.Count > 0)
|
||||||
{
|
{
|
||||||
#region To narrate latest chat message
|
#region To narrate latest chat message
|
|
@ -0,0 +1,128 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class DialogueBoxPatch
|
||||||
|
{
|
||||||
|
private static string currentDialogue = "";
|
||||||
|
private static bool isDialogueAppearingFirstTime = true;
|
||||||
|
|
||||||
|
internal static void DrawPatch(DialogueBox __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (__instance.transitioning) return;
|
||||||
|
|
||||||
|
if (narrateCharacterDialogue(__instance)) return;
|
||||||
|
if (narrateQuestionDialogue(__instance)) return;
|
||||||
|
narrateBasicDialogue(__instance.getCurrentString());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void RecieveLeftClickPatch()
|
||||||
|
{
|
||||||
|
// CLears the currentDialogue string on closing dialog
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateCharacterDialogue(DialogueBox __instance)
|
||||||
|
{
|
||||||
|
if (__instance.characterDialogue == null) return false;
|
||||||
|
|
||||||
|
// For Normal Character dialogues
|
||||||
|
Dialogue dialogue = __instance.characterDialogue;
|
||||||
|
string speakerName = dialogue.speaker.displayName;
|
||||||
|
string dialogueText = "";
|
||||||
|
string responseText = "";
|
||||||
|
bool hasResponses = dialogue.isCurrentDialogueAQuestion();
|
||||||
|
|
||||||
|
dialogueText = $"{speakerName} said {__instance.getCurrentString()}";
|
||||||
|
|
||||||
|
if (hasResponses)
|
||||||
|
{
|
||||||
|
responseText = getCurrentResponseText(__instance);
|
||||||
|
|
||||||
|
CheckAndSpeak(isDialogueAppearingFirstTime ? $"{dialogueText} \n\t {responseText}" : responseText, responseText);
|
||||||
|
if (isDialogueAppearingFirstTime) isDialogueAppearingFirstTime = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CheckAndSpeak(dialogueText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool narrateQuestionDialogue(DialogueBox __instance)
|
||||||
|
{
|
||||||
|
if (!__instance.isQuestion) return false;
|
||||||
|
|
||||||
|
// For Dialogues with responses/answers like the dialogue when we click on tv
|
||||||
|
string questionText = "";
|
||||||
|
string responseText = "";
|
||||||
|
bool hasResponses = false;
|
||||||
|
|
||||||
|
if (__instance.responses.Count > 0) hasResponses = true;
|
||||||
|
if (!hasResponses) return false;
|
||||||
|
|
||||||
|
questionText = __instance.getCurrentString();
|
||||||
|
|
||||||
|
responseText = getCurrentResponseText(__instance);
|
||||||
|
|
||||||
|
CheckAndSpeak(isDialogueAppearingFirstTime ? $"{questionText} \n\t {responseText}" : responseText, responseText);
|
||||||
|
if (isDialogueAppearingFirstTime) isDialogueAppearingFirstTime = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateBasicDialogue(string dialogue)
|
||||||
|
{
|
||||||
|
// Basic dialogues like `No mails in the mail box`
|
||||||
|
if (Game1.activeClickableMenu is not DialogueBox) return;
|
||||||
|
CheckAndSpeak(dialogue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string getCurrentResponseText(DialogueBox __instance)
|
||||||
|
{
|
||||||
|
List<Response> responses = __instance.responses;
|
||||||
|
if (__instance.selectedResponse >= 0 && __instance.selectedResponse < responses.Count)
|
||||||
|
{
|
||||||
|
return $"{__instance.selectedResponse + 1}: {responses[__instance.selectedResponse].responseText}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// When the dialogue is not finished writing then the selectedResponse is <0 and this results
|
||||||
|
// in the first response not being detcted, so this sets the first response option to be the default
|
||||||
|
// if the current dialogue is a question or has responses
|
||||||
|
return $"1: {responses[0].responseText}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckAndSpeak(string toSpeak)
|
||||||
|
{
|
||||||
|
if (currentDialogue == toSpeak) return;
|
||||||
|
currentDialogue = toSpeak;
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckAndSpeak(string toSpeak, string checkQuery)
|
||||||
|
{
|
||||||
|
if (currentDialogue == checkQuery) return;
|
||||||
|
currentDialogue = checkQuery;
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
currentDialogue = "";
|
||||||
|
isDialogueAppearingFirstTime = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
using Microsoft.Xna.Framework;
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewModdingAPI;
|
||||||
|
using StardewValley;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class Game1Patch
|
||||||
|
{
|
||||||
|
private static Vector2? prevTile = null;
|
||||||
|
|
||||||
|
internal static void ExitActiveMenuPatch()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IClickableMenuPatch.Cleanup(Game1.activeClickableMenu);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool PlaySoundPatch(string cueName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!Context.IsPlayerFree)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!Game1.player.isMoving())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (cueName == "grassyStep" || cueName == "sandyStep" || cueName == "snowyStep" || cueName == "stoneStep" || cueName == "thudStep" || cueName == "woodyStep")
|
||||||
|
{
|
||||||
|
Vector2 nextTile = CurrentPlayer.FacingTile;
|
||||||
|
if (TileInfo.isCollidingAtTile((int)nextTile.X, (int)nextTile.Y))
|
||||||
|
{
|
||||||
|
if (prevTile != nextTile)
|
||||||
|
{
|
||||||
|
prevTile = nextTile;
|
||||||
|
//Game1.playSound("colliding");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,326 @@
|
||||||
|
using stardew_access.Features;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
// These patches are global, i.e. work on every menus
|
||||||
|
internal class IClickableMenuPatch
|
||||||
|
{
|
||||||
|
internal static void DrawHoverTextPatch(string? text, int moneyAmountToDisplayAtBottom = -1, string? boldTitleText = null, int extraItemToShowIndex = -1, int extraItemToShowAmount = -1, string[]? buffIconsToDisplay = null, Item? hoveredItem = null, CraftingRecipe? craftingIngredients = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#region Skip narrating hover text for certain menus
|
||||||
|
if (Game1.activeClickableMenu is TitleMenu && !(((TitleMenu)Game1.activeClickableMenu).GetChildMenu() is CharacterCustomization))
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is LetterViewerMenu || Game1.activeClickableMenu is QuestLog)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is Billboard)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is GeodeMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is InventoryPage)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is CraftingPage)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is OptionsPage)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is ExitPage)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is GameMenu && ((GameMenu)Game1.activeClickableMenu).GetCurrentPage() is SocialPage)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ItemGrabMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ShopMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ConfirmationDialog)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is JunimoNoteMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is CarpenterMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is PurchaseAnimalsMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is CraftingPage)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is AnimalQueryMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ConfirmationDialog)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ReadyCheckDialog)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is JojaCDMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is TailoringMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is PondQueryMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ForgeMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is ItemListMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is FieldOfficeMenu)
|
||||||
|
return;
|
||||||
|
else if (Game1.activeClickableMenu is MuseumMenu)
|
||||||
|
return;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
string toSpeak = " ";
|
||||||
|
|
||||||
|
#region Add item count before title
|
||||||
|
if (hoveredItem != null && hoveredItem.HasBeenInInventory)
|
||||||
|
{
|
||||||
|
int count = hoveredItem.Stack;
|
||||||
|
if (count > 1)
|
||||||
|
toSpeak = $"{toSpeak} {count} ";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add title if any
|
||||||
|
if (boldTitleText != null)
|
||||||
|
toSpeak = $"{toSpeak} {boldTitleText}\n";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add quality of item
|
||||||
|
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).Quality > 0)
|
||||||
|
{
|
||||||
|
int quality = ((StardewValley.Object)hoveredItem).Quality;
|
||||||
|
if (quality == 1)
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} Silver quality";
|
||||||
|
}
|
||||||
|
else if (quality == 2 || quality == 3)
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} Gold quality";
|
||||||
|
}
|
||||||
|
else if (quality >= 4)
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} Iridium quality";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Narrate hovered required ingredients
|
||||||
|
if (extraItemToShowIndex != -1)
|
||||||
|
{
|
||||||
|
string itemName = Game1.objectInformation[extraItemToShowIndex].Split('/')[0];
|
||||||
|
|
||||||
|
if (extraItemToShowAmount != -1)
|
||||||
|
toSpeak = $"{toSpeak} Required: {extraItemToShowAmount} {itemName}";
|
||||||
|
else
|
||||||
|
toSpeak = $"{toSpeak} Required: {itemName}";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add money
|
||||||
|
if (moneyAmountToDisplayAtBottom != -1)
|
||||||
|
toSpeak = $"{toSpeak} \nCost: {moneyAmountToDisplayAtBottom}g\n";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add the base text
|
||||||
|
if (text == "???")
|
||||||
|
toSpeak = "unknown";
|
||||||
|
else
|
||||||
|
toSpeak = $"{toSpeak} {text}";
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add crafting ingredients
|
||||||
|
if (craftingIngredients != null)
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} \n{craftingIngredients.description}";
|
||||||
|
toSpeak = $"{toSpeak} \nIngredients\n";
|
||||||
|
|
||||||
|
craftingIngredients.recipeList.ToList().ForEach(recipe =>
|
||||||
|
{
|
||||||
|
int count = recipe.Value;
|
||||||
|
int item = recipe.Key;
|
||||||
|
string name = craftingIngredients.getNameFromIndex(item);
|
||||||
|
|
||||||
|
toSpeak = $"{toSpeak} ,{count} {name}";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add health & stamina
|
||||||
|
if (hoveredItem is StardewValley.Object && ((StardewValley.Object)hoveredItem).Edibility != -300)
|
||||||
|
{
|
||||||
|
int stamina_recovery = ((StardewValley.Object)hoveredItem).staminaRecoveredOnConsumption();
|
||||||
|
toSpeak = $"{toSpeak} {stamina_recovery} Energy\n";
|
||||||
|
if (stamina_recovery >= 0)
|
||||||
|
{
|
||||||
|
int health_recovery = ((StardewValley.Object)hoveredItem).healthRecoveredOnConsumption();
|
||||||
|
toSpeak = $"{toSpeak} {health_recovery} Health";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Add buff items (effects like +1 walking speed)
|
||||||
|
if (buffIconsToDisplay != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < buffIconsToDisplay.Length; i++)
|
||||||
|
{
|
||||||
|
string buffName = ((Convert.ToInt32(buffIconsToDisplay[i]) > 0) ? "+" : "") + buffIconsToDisplay[i] + " ";
|
||||||
|
if (i <= 11)
|
||||||
|
{
|
||||||
|
buffName = Game1.content.LoadString("Strings\\UI:ItemHover_Buff" + i, buffName);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int count = int.Parse(buffName.Substring(0, buffName.IndexOf(' ')));
|
||||||
|
if (count != 0)
|
||||||
|
toSpeak = $"{toSpeak} {buffName}\n";
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Narrate toSpeak
|
||||||
|
// To prevent it from getting conflicted by two hover texts at the same time, two seperate methods are used.
|
||||||
|
// For example, sometimes `Welcome to Pierre's` and the items in seeds shop get conflicted causing it to speak infinitely.
|
||||||
|
|
||||||
|
if (toSpeak.ToString() != " ")
|
||||||
|
{
|
||||||
|
if (StardewModdingAPI.Context.IsPlayerFree)
|
||||||
|
MainClass.ScreenReader.SayWithChecker(toSpeak.ToString(), true); // Normal Checker
|
||||||
|
else
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker(toSpeak.ToString(), true); // Menu Checker
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate dialog:\n{e.StackTrace}\n{e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ExitThisMenuPatch(IClickableMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Cleanup(__instance);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup(IClickableMenu menu)
|
||||||
|
{
|
||||||
|
if (menu is TitleMenu)
|
||||||
|
{
|
||||||
|
TitleMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is CoopMenu)
|
||||||
|
{
|
||||||
|
CoopMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is LoadGameMenu)
|
||||||
|
{
|
||||||
|
LoadGameMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is AdvancedGameOptions)
|
||||||
|
{
|
||||||
|
AdvancedGameOptionsPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is LetterViewerMenu)
|
||||||
|
{
|
||||||
|
LetterViwerMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is LevelUpMenu)
|
||||||
|
{
|
||||||
|
LevelUpMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is Billboard)
|
||||||
|
{
|
||||||
|
BillboardPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is GameMenu)
|
||||||
|
{
|
||||||
|
GameMenuPatch.Cleanup();
|
||||||
|
ExitPagePatch.Cleanup();
|
||||||
|
OptionsPagePatch.Cleanup();
|
||||||
|
SocialPagePatch.Cleanup();
|
||||||
|
InventoryPagePatch.Cleanup();
|
||||||
|
CraftingPagePatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is JunimoNoteMenu)
|
||||||
|
{
|
||||||
|
JunimoNoteMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is ShopMenu)
|
||||||
|
{
|
||||||
|
ShopMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is ItemGrabMenu)
|
||||||
|
{
|
||||||
|
ItemGrabMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is GeodeMenu)
|
||||||
|
{
|
||||||
|
GeodeMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is CarpenterMenu)
|
||||||
|
{
|
||||||
|
CarpenterMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is PurchaseAnimalsMenu)
|
||||||
|
{
|
||||||
|
PurchaseAnimalsMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is AnimalQueryMenu)
|
||||||
|
{
|
||||||
|
AnimalQueryMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is DialogueBox)
|
||||||
|
{
|
||||||
|
DialogueBoxPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is JojaCDMenu)
|
||||||
|
{
|
||||||
|
JojaCDMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is QuestLog)
|
||||||
|
{
|
||||||
|
QuestLogPatch.Cleaup();
|
||||||
|
}
|
||||||
|
else if (menu is TailoringMenu)
|
||||||
|
{
|
||||||
|
TailoringMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is ForgeMenu)
|
||||||
|
{
|
||||||
|
ForgeMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is ItemListMenu)
|
||||||
|
{
|
||||||
|
ItemListMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is FieldOfficeMenu)
|
||||||
|
{
|
||||||
|
FieldOfficeMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is MuseumMenu)
|
||||||
|
{
|
||||||
|
MuseumMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is PondQueryMenu)
|
||||||
|
{
|
||||||
|
PondQueryMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is GeodeMenu)
|
||||||
|
{
|
||||||
|
GeodeMenuPatch.Cleanup();
|
||||||
|
}
|
||||||
|
else if (menu is SpecialOrdersBoard)
|
||||||
|
{
|
||||||
|
SpecialOrdersBoardPatch.Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
InventoryUtils.Cleanup();
|
||||||
|
TextBoxPatch.activeTextBoxes = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class InstanceGamePatch
|
||||||
|
{
|
||||||
|
internal static void ExitPatch()
|
||||||
|
{
|
||||||
|
if (MainClass.ScreenReader != null)
|
||||||
|
MainClass.ScreenReader.CloseScreenReader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using StardewValley;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class NPCPatch
|
||||||
|
{
|
||||||
|
internal static void DrawAboveAlwaysFrontLayerPatch(NPC __instance, string ___textAboveHead, int ___textAboveHeadTimer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (___textAboveHeadTimer > 2900 && ___textAboveHead != null)
|
||||||
|
{
|
||||||
|
MainClass.ScreenReader.SayWithChecker($"{__instance.displayName} says {___textAboveHead}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Error in patch:NPCShowTextAboveHeadPatch \n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class TextBoxPatch
|
||||||
|
{
|
||||||
|
internal static string textBoxQuery = " ";
|
||||||
|
internal static string activeTextBoxes = "";
|
||||||
|
internal static bool isAnyTextBoxActive => activeTextBoxes != "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(StardewValley.Menus.TextBox __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string uniqueIdentifier = $"{__instance.X}:{__instance.Y}:{__instance.Height}:{__instance.Width}";
|
||||||
|
if (!__instance.Selected)
|
||||||
|
{
|
||||||
|
if (activeTextBoxes.Contains(uniqueIdentifier)) activeTextBoxes = activeTextBoxes.Replace(uniqueIdentifier, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activeTextBoxes.Contains(uniqueIdentifier)) activeTextBoxes += uniqueIdentifier;
|
||||||
|
|
||||||
|
bool isEscPressed = StardewValley.Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape);
|
||||||
|
string toSpeak = __instance.Text;
|
||||||
|
|
||||||
|
if (isEscPressed)
|
||||||
|
{
|
||||||
|
__instance.Selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textBoxQuery != toSpeak)
|
||||||
|
{
|
||||||
|
textBoxQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in DrawPatch() in TextBoxPatch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class AnimalQueryMenuPatch
|
||||||
|
{
|
||||||
|
internal static bool isNarratingAnimalInfo = false;
|
||||||
|
internal static string animalQueryMenuQuery = "";
|
||||||
|
internal static AnimalQueryMenu? animalQueryMenu;
|
||||||
|
internal static FarmAnimal? animalBeingMoved = null;
|
||||||
|
internal static bool isOnFarm = false;
|
||||||
|
|
||||||
|
internal static void DrawPatch(AnimalQueryMenu __instance, bool ___confirmingSell, FarmAnimal ___animal, TextBox ___textBox, string ___parentName, bool ___movingAnimal)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (TextBoxPatch.isAnyTextBoxActive) return;
|
||||||
|
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
isOnFarm = ___movingAnimal;
|
||||||
|
animalQueryMenu = __instance;
|
||||||
|
animalBeingMoved = ___animal;
|
||||||
|
|
||||||
|
narrateAnimalDetailsOnKeyPress(___animal, ___parentName);
|
||||||
|
|
||||||
|
narrateHoveredButton(__instance, ___animal, ___confirmingSell, x, y);
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in AnimalQueryMenuPatch()->DrawPatch():\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateAnimalDetailsOnKeyPress(FarmAnimal ___animal, string ___parentName)
|
||||||
|
{
|
||||||
|
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||||
|
if (!isPrimaryInfoKeyPressed | isNarratingAnimalInfo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string name = ___animal.displayName;
|
||||||
|
string type = ___animal.displayType;
|
||||||
|
int age = (___animal.GetDaysOwned() + 1) / 28 + 1;
|
||||||
|
string ageText = (age <= 1) ? Game1.content.LoadString("Strings\\UI:AnimalQuery_Age1") : Game1.content.LoadString("Strings\\UI:AnimalQuery_AgeN", age);
|
||||||
|
string parent = "";
|
||||||
|
if ((int)___animal.age.Value < (byte)___animal.ageWhenMature.Value)
|
||||||
|
{
|
||||||
|
ageText += Game1.content.LoadString("Strings\\UI:AnimalQuery_AgeBaby");
|
||||||
|
}
|
||||||
|
if (___parentName != null)
|
||||||
|
{
|
||||||
|
parent = Game1.content.LoadString("Strings\\UI:AnimalQuery_Parent", ___parentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
isNarratingAnimalInfo = true;
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isNarratingAnimalInfo = false; }); // Adds delay
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say($"Name: {name} Type: {type} \n\t Age: {ageText} {parent}", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateHoveredButton(AnimalQueryMenu __instance, FarmAnimal ___animal, bool ___confirmingSell, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
toSpeak = "OK button";
|
||||||
|
else if (__instance.sellButton != null && __instance.sellButton.containsPoint(x, y))
|
||||||
|
toSpeak = $"Sell for {___animal.getSellPrice()}g button";
|
||||||
|
else if (___confirmingSell && __instance.yesButton != null && __instance.yesButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Confirm selling animal";
|
||||||
|
else if (___confirmingSell && __instance.noButton != null && __instance.noButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Cancel selling animal";
|
||||||
|
else if (__instance.moveHomeButton != null && __instance.moveHomeButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Change home building button";
|
||||||
|
else if (__instance.allowReproductionButton != null && __instance.allowReproductionButton.containsPoint(x, y))
|
||||||
|
toSpeak = ((___animal.allowReproduction.Value) ? "Enabled" : "Disabled") + " allow reproduction button";
|
||||||
|
else if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
||||||
|
toSpeak = "Animal name text box";
|
||||||
|
|
||||||
|
if (animalQueryMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
animalQueryMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say($"{toSpeak}", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
AnimalQueryMenuPatch.animalQueryMenuQuery = "";
|
||||||
|
AnimalQueryMenuPatch.animalQueryMenu = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,174 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class CarpenterMenuPatch
|
||||||
|
{
|
||||||
|
internal static CarpenterMenu? carpenterMenu = null;
|
||||||
|
internal static string carpenterMenuQuery = "";
|
||||||
|
internal static bool isSayingBlueprintInfo = false;
|
||||||
|
internal static string prevBlueprintInfo = "";
|
||||||
|
internal static bool isOnFarm = false, isUpgrading = false, isDemolishing = false, isPainting = false, isConstructing = false, isMoving = false, isMagicalConstruction = false;
|
||||||
|
|
||||||
|
internal static void DrawPatch(
|
||||||
|
CarpenterMenu __instance, bool ___onFarm, List<Item> ___ingredients, int ___price,
|
||||||
|
List<BluePrint> ___blueprints, int ___currentBlueprintIndex, bool ___upgrading, bool ___demolishing, bool ___moving,
|
||||||
|
bool ___painting, bool ___magicalConstruction)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
isOnFarm = ___onFarm;
|
||||||
|
carpenterMenu = __instance;
|
||||||
|
isMagicalConstruction = ___magicalConstruction;
|
||||||
|
if (!___onFarm)
|
||||||
|
{
|
||||||
|
isUpgrading = false;
|
||||||
|
isDemolishing = false;
|
||||||
|
isPainting = false;
|
||||||
|
isMoving = false;
|
||||||
|
isConstructing = false;
|
||||||
|
|
||||||
|
BluePrint currentBlueprint = __instance.CurrentBlueprint;
|
||||||
|
if (currentBlueprint == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||||
|
string blueprintInfo = getCurrentBlueprintInfo(currentBlueprint, ___price, ___ingredients);
|
||||||
|
|
||||||
|
if (isPrimaryInfoKeyPressed && !isSayingBlueprintInfo)
|
||||||
|
{
|
||||||
|
SpeakAndWait(blueprintInfo);
|
||||||
|
}
|
||||||
|
else if (prevBlueprintInfo != blueprintInfo)
|
||||||
|
{
|
||||||
|
prevBlueprintInfo = blueprintInfo;
|
||||||
|
SpeakAndWait(blueprintInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
narrateHoveredButton(__instance, ___blueprints, ___currentBlueprintIndex, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (___demolishing)
|
||||||
|
isDemolishing = true;
|
||||||
|
else if (___upgrading)
|
||||||
|
isUpgrading = true;
|
||||||
|
else if (___painting)
|
||||||
|
isPainting = true;
|
||||||
|
else if (___moving)
|
||||||
|
isMoving = true;
|
||||||
|
else
|
||||||
|
isConstructing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string getCurrentBlueprintInfo(BluePrint currentBlueprint, int ___price, List<Item> ___ingredients)
|
||||||
|
{
|
||||||
|
string ingredients = "";
|
||||||
|
string name = currentBlueprint.displayName;
|
||||||
|
string upgradeName = currentBlueprint.nameOfBuildingToUpgrade;
|
||||||
|
string description = currentBlueprint.description;
|
||||||
|
string price = $"{___price}g";
|
||||||
|
int width = currentBlueprint.tilesWidth;
|
||||||
|
int height = currentBlueprint.tilesHeight;
|
||||||
|
|
||||||
|
#region Get ingredients
|
||||||
|
for (int i = 0; i < ___ingredients.Count; i++)
|
||||||
|
{
|
||||||
|
string itemName = ___ingredients[i].DisplayName;
|
||||||
|
int itemStack = ___ingredients[i].Stack;
|
||||||
|
string itemQuality = "";
|
||||||
|
|
||||||
|
int qualityValue = ((StardewValley.Object)___ingredients[i]).Quality;
|
||||||
|
if (qualityValue == 1)
|
||||||
|
{
|
||||||
|
itemQuality = "Silver quality";
|
||||||
|
}
|
||||||
|
else if (qualityValue == 2 || qualityValue == 3)
|
||||||
|
{
|
||||||
|
itemQuality = "Gold quality";
|
||||||
|
}
|
||||||
|
else if (qualityValue >= 4)
|
||||||
|
{
|
||||||
|
itemQuality = "Iridium quality";
|
||||||
|
}
|
||||||
|
|
||||||
|
ingredients = $"{ingredients}, {itemStack} {itemName} {itemQuality}";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
return $"{name}, Price: {price}, Ingredients: {ingredients}, Dimensions: {width} width and {height} height, Description: {description}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async void SpeakAndWait(string toSpeak)
|
||||||
|
{
|
||||||
|
isSayingBlueprintInfo = true;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
await Task.Delay(300);
|
||||||
|
isSayingBlueprintInfo = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateHoveredButton(CarpenterMenu __instance, List<BluePrint> ___blueprints, int ___currentBlueprintIndex, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Previous Blueprint";
|
||||||
|
}
|
||||||
|
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Next Blueprint";
|
||||||
|
}
|
||||||
|
else if (__instance.demolishButton != null && __instance.demolishButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = $"Demolish Building" + (__instance.CanDemolishThis(___blueprints[___currentBlueprintIndex]) ? "" : ", cannot demolish building");
|
||||||
|
}
|
||||||
|
else if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Construct Building" + (___blueprints[___currentBlueprintIndex].doesFarmerHaveEnoughResourcesToBuild() ? "" : ", cannot cunstrut building, not enough resources to build.");
|
||||||
|
}
|
||||||
|
else if (__instance.moveButton != null && __instance.moveButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Move Building";
|
||||||
|
}
|
||||||
|
else if (__instance.paintButton != null && __instance.paintButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Paint Building";
|
||||||
|
}
|
||||||
|
else if (__instance.cancelButton != null && __instance.cancelButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Cancel Button";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (carpenterMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
carpenterMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
CarpenterMenuPatch.carpenterMenuQuery = "";
|
||||||
|
CarpenterMenuPatch.isUpgrading = false;
|
||||||
|
CarpenterMenuPatch.isDemolishing = false;
|
||||||
|
CarpenterMenuPatch.isPainting = false;
|
||||||
|
CarpenterMenuPatch.isMoving = false;
|
||||||
|
CarpenterMenuPatch.isConstructing = false;
|
||||||
|
CarpenterMenuPatch.carpenterMenu = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ChooseFromListMenuPatch
|
||||||
|
{
|
||||||
|
internal static void DrawPatch(ChooseFromListMenu __instance, List<string> ___options, int ___index, bool ___isJukebox)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Select " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[___index]) : ___options[___index]) + " button";
|
||||||
|
else if (__instance.cancelButton != null && __instance.cancelButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Cancel button";
|
||||||
|
else if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Previous option: " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[Math.Max(0, ___index - 1)]) : ___options[Math.Max(0, ___index - 1)]) + " button";
|
||||||
|
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Next option: " + (___isJukebox ? Utility.getSongTitleFromCueName(___options[Math.Min(___options.Count, ___index + 1)]) : ___options[Math.Min(___options.Count, ___index + 1)]) + " button";
|
||||||
|
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ConfirmationDialogMenuPatch
|
||||||
|
{
|
||||||
|
internal static void DrawPatch(ConfirmationDialog __instance, string ___message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||||
|
string toSpeak = ___message;
|
||||||
|
|
||||||
|
if (__instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak += "\n\tOk Button";
|
||||||
|
}
|
||||||
|
else if (__instance.cancelButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak += "\n\tCancel Button";
|
||||||
|
}
|
||||||
|
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ItemListMenuPatch
|
||||||
|
{
|
||||||
|
private static string itemListMenuQuery = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(ItemListMenu __instance, string ___title, int ___currentTab, int ___totalValueOfItems, List<Item> ___itemsToList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
string toSpeak = "", currentList = "";
|
||||||
|
|
||||||
|
for (int i = ___currentTab * __instance.itemsPerCategoryPage; i < ___currentTab * __instance.itemsPerCategoryPage + __instance.itemsPerCategoryPage; i++)
|
||||||
|
{
|
||||||
|
if (i == 0) currentList = ___title;
|
||||||
|
if (___itemsToList.Count <= i) continue;
|
||||||
|
|
||||||
|
if (___itemsToList[i] == null)
|
||||||
|
{
|
||||||
|
currentList = $"{currentList}, \n" + Game1.content.LoadString("Strings\\UI:ItemList_ItemsLostValue", ___totalValueOfItems);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentList = $"{currentList}, \n {___itemsToList[i].Stack} {___itemsToList[i].DisplayName}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
toSpeak = $"Page {___currentTab + 1} of {((int)___itemsToList.Count / __instance.itemsPerCategoryPage) + 1} \n {currentList} \n ok button";
|
||||||
|
else if (__instance.forwardButton != null && __instance.forwardButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Next page button";
|
||||||
|
else if (__instance.backButton != null && __instance.backButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Previous page button";
|
||||||
|
|
||||||
|
if (itemListMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
itemListMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
itemListMenuQuery = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class LanguageSelectionMenuPatch
|
||||||
|
{
|
||||||
|
internal static void DrawPatch(LanguageSelectionMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (__instance.nextPageButton != null && __instance.nextPageButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker($"Next Page Button", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.previousPageButton != null && __instance.previousPageButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker($"Previous Page Button", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < __instance.languages.Count; i++)
|
||||||
|
{
|
||||||
|
if (__instance.languages[i].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker($"{__instance.languageList[i]} Button", true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class LetterViwerMenuPatch
|
||||||
|
{
|
||||||
|
private static string currentLetterText = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(LetterViewerMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!__instance.IsActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
narrateLetterContent(__instance);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void narrateLetterContent(LetterViewerMenu __instance)
|
||||||
|
{
|
||||||
|
int x = Game1.getMousePosition().X, y = Game1.getMousePosition().Y;
|
||||||
|
#region Texts in the letter
|
||||||
|
string message = __instance.mailMessage[__instance.page];
|
||||||
|
|
||||||
|
string toSpeak = $"{message}";
|
||||||
|
|
||||||
|
if (__instance.ShouldShowInteractable())
|
||||||
|
{
|
||||||
|
if (__instance.moneyIncluded > 0)
|
||||||
|
{
|
||||||
|
string moneyText = Game1.content.LoadString("Strings\\UI:LetterViewer_MoneyIncluded", __instance.moneyIncluded);
|
||||||
|
toSpeak += $"\t\n\t ,Included money: {moneyText}";
|
||||||
|
}
|
||||||
|
else if (__instance.learnedRecipe != null && __instance.learnedRecipe.Length > 0)
|
||||||
|
{
|
||||||
|
string recipeText = Game1.content.LoadString("Strings\\UI:LetterViewer_LearnedRecipe", __instance.cookingOrCrafting);
|
||||||
|
toSpeak += $"\t\n\t ,Learned Recipe: {recipeText}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentLetterText != toSpeak)
|
||||||
|
{
|
||||||
|
currentLetterText = toSpeak;
|
||||||
|
|
||||||
|
// snap mouse to accept quest button
|
||||||
|
if (__instance.acceptQuestButton != null && __instance.questID != -1)
|
||||||
|
{
|
||||||
|
toSpeak += "\t\n Left click to accept quest.";
|
||||||
|
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
||||||
|
}
|
||||||
|
if (__instance.mailMessage.Count > 1)
|
||||||
|
toSpeak = $"Page {__instance.page + 1} of {__instance.mailMessage.Count}:\n\t{toSpeak}";
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Narrate items given in the mail
|
||||||
|
if (__instance.ShouldShowInteractable())
|
||||||
|
{
|
||||||
|
foreach (ClickableComponent c in __instance.itemsToGrab)
|
||||||
|
{
|
||||||
|
if (c.item == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string name = c.item.DisplayName;
|
||||||
|
|
||||||
|
if (c.containsPoint(x, y))
|
||||||
|
MainClass.ScreenReader.SayWithChecker($"Left click to collect {name}", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Narrate buttons
|
||||||
|
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
||||||
|
MainClass.ScreenReader.SayWithChecker($"Previous page button", false);
|
||||||
|
|
||||||
|
if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
||||||
|
MainClass.ScreenReader.SayWithChecker($"Next page button", false);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
currentLetterText = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class LevelUpMenuPatch
|
||||||
|
{
|
||||||
|
private static string currentLevelUpTitle = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(LevelUpMenu __instance, List<int> ___professionsToChoose, List<string> ___leftProfessionDescription, List<string> ___rightProfessionDescription, List<string> ___extraInfoForLevel, List<CraftingRecipe> ___newCraftingRecipes, string ___title, bool ___isActive, bool ___isProfessionChooser)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||||
|
string leftProfession = "", rightProfession = "", extraInfo = "", newCraftingRecipe = "", toSpeak = "";
|
||||||
|
|
||||||
|
if (!__instance.informationUp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (__instance.isProfessionChooser)
|
||||||
|
{
|
||||||
|
if (___professionsToChoose.Count() == 0) return;
|
||||||
|
|
||||||
|
for (int j = 0; j < ___leftProfessionDescription.Count; j++)
|
||||||
|
{
|
||||||
|
leftProfession += ___leftProfessionDescription[j] + ", ";
|
||||||
|
}
|
||||||
|
for (int i = 0; i < ___rightProfessionDescription.Count; i++)
|
||||||
|
{
|
||||||
|
rightProfession += ___rightProfessionDescription[i] + ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.leftProfession.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if ((MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed()) && __instance.readyToClose())
|
||||||
|
{
|
||||||
|
Game1.player.professions.Add(___professionsToChoose[0]);
|
||||||
|
__instance.getImmediateProfessionPerk(___professionsToChoose[0]);
|
||||||
|
___isActive = false;
|
||||||
|
__instance.informationUp = false;
|
||||||
|
___isProfessionChooser = false;
|
||||||
|
__instance.RemoveLevelFromLevelList();
|
||||||
|
__instance.exitThisMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toSpeak = $"Selected: {leftProfession} Left click to choose.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.rightProfession.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if ((MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed()) && __instance.readyToClose())
|
||||||
|
{
|
||||||
|
Game1.player.professions.Add(___professionsToChoose[1]);
|
||||||
|
__instance.getImmediateProfessionPerk(___professionsToChoose[1]);
|
||||||
|
___isActive = false;
|
||||||
|
__instance.informationUp = false;
|
||||||
|
___isProfessionChooser = false;
|
||||||
|
__instance.RemoveLevelFromLevelList();
|
||||||
|
__instance.exitThisMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toSpeak = $"Selected: {rightProfession} Left click to choose.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (string s2 in ___extraInfoForLevel)
|
||||||
|
{
|
||||||
|
extraInfo += s2 + ", ";
|
||||||
|
}
|
||||||
|
foreach (CraftingRecipe s in ___newCraftingRecipes)
|
||||||
|
{
|
||||||
|
string cookingOrCrafting = Game1.content.LoadString("Strings\\UI:LearnedRecipe_" + (s.isCookingRecipe ? "cooking" : "crafting"));
|
||||||
|
string message = Game1.content.LoadString("Strings\\UI:LevelUp_NewRecipe", cookingOrCrafting, s.DisplayName);
|
||||||
|
|
||||||
|
newCraftingRecipe += $"{message}, ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if (MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed())
|
||||||
|
__instance.okButtonClicked();
|
||||||
|
|
||||||
|
toSpeak = $"{___title} {extraInfo} {newCraftingRecipe}. Left click to close.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toSpeak != "")
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
||||||
|
else if (__instance.isProfessionChooser && currentLevelUpTitle != $"{___title}. Select a new profession.")
|
||||||
|
{
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker($"{___title}. Select a new profession.", true);
|
||||||
|
currentLevelUpTitle = $"{___title}. Select a new profession.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
currentLevelUpTitle = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class MineElevatorMenuPatch
|
||||||
|
{
|
||||||
|
internal static void DrawPatch(List<ClickableComponent> ___elevators)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
for (int i = 0; i < ___elevators.Count; i++)
|
||||||
|
{
|
||||||
|
if (___elevators[i].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
MainClass.ScreenReader.SayWithMenuChecker($"{___elevators[i].name} level", true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class NamingMenuPatch
|
||||||
|
{
|
||||||
|
internal static bool firstTimeInNamingMenu = true;
|
||||||
|
|
||||||
|
internal static void DrawPatch(NamingMenu __instance, TextBox ___textBox, string ___title)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (firstTimeInNamingMenu)
|
||||||
|
{
|
||||||
|
firstTimeInNamingMenu = false;
|
||||||
|
___textBox.Selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TextBoxPatch.isAnyTextBoxActive) return;
|
||||||
|
|
||||||
|
string toSpeak = "";
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
||||||
|
|
||||||
|
if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
||||||
|
toSpeak = $"{___title} text box";
|
||||||
|
else if (__instance.doneNamingButton != null && __instance.doneNamingButton.containsPoint(x, y))
|
||||||
|
toSpeak = $"Done naming button";
|
||||||
|
else if (__instance.randomButton != null && __instance.randomButton.containsPoint(x, y))
|
||||||
|
toSpeak = $"Random button";
|
||||||
|
|
||||||
|
if (toSpeak != "")
|
||||||
|
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Buildings;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class PondQueryMenuPatch
|
||||||
|
{
|
||||||
|
private static string pondQueryMenuQuery = "";
|
||||||
|
private static bool isNarratingPondInfo = false;
|
||||||
|
|
||||||
|
internal static void DrawPatch(PondQueryMenu __instance, StardewValley.Object ____fishItem, FishPond ____pond, string ____statusText, bool ___confirmingEmpty)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||||
|
string toSpeak = "", extra = "";
|
||||||
|
|
||||||
|
if (___confirmingEmpty)
|
||||||
|
{
|
||||||
|
if (__instance.yesButton != null && __instance.yesButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Confirm button";
|
||||||
|
else if (__instance.noButton != null && __instance.noButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Cancel button";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (isPrimaryInfoKeyPressed && !isNarratingPondInfo)
|
||||||
|
{
|
||||||
|
string pond_name_text = Game1.content.LoadString("Strings\\UI:PondQuery_Name", ____fishItem.DisplayName);
|
||||||
|
string population_text = Game1.content.LoadString("Strings\\UI:PondQuery_Population", string.Concat(____pond.FishCount), ____pond.maxOccupants.Value);
|
||||||
|
bool has_unresolved_needs = ____pond.neededItem.Value != null && ____pond.HasUnresolvedNeeds() && !____pond.hasCompletedRequest.Value;
|
||||||
|
string bring_text = "";
|
||||||
|
|
||||||
|
if (has_unresolved_needs && ____pond.neededItem.Value != null)
|
||||||
|
bring_text = Game1.content.LoadString("Strings\\UI:PondQuery_StatusRequest_Bring") + $": {____pond.neededItemCount} {____pond.neededItem.Value.DisplayName}";
|
||||||
|
|
||||||
|
extra = $"{pond_name_text} {population_text} {bring_text} Status: {____statusText}";
|
||||||
|
pondQueryMenuQuery = "";
|
||||||
|
|
||||||
|
isNarratingPondInfo = true;
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isNarratingPondInfo = false; });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Ok button";
|
||||||
|
else if (__instance.changeNettingButton != null && __instance.changeNettingButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Change netting button";
|
||||||
|
else if (__instance.emptyButton != null && __instance.emptyButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Empty pond button";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pondQueryMenuQuery != toSpeak)
|
||||||
|
{
|
||||||
|
pondQueryMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
pondQueryMenuQuery = "";
|
||||||
|
isNarratingPondInfo = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class PurchaseAnimalsMenuPatch
|
||||||
|
{
|
||||||
|
internal static FarmAnimal? animalBeingPurchased = null;
|
||||||
|
internal static bool isOnFarm = false;
|
||||||
|
internal static string purchaseAnimalMenuQuery = "";
|
||||||
|
internal static PurchaseAnimalsMenu? purchaseAnimalsMenu;
|
||||||
|
internal static bool firstTimeInNamingMenu = true;
|
||||||
|
|
||||||
|
internal static void DrawPatch(PurchaseAnimalsMenu __instance, bool ___onFarm, bool ___namingAnimal, TextBox ___textBox, FarmAnimal ___animalBeingPurchased)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (TextBoxPatch.isAnyTextBoxActive) return;
|
||||||
|
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
purchaseAnimalsMenu = __instance;
|
||||||
|
isOnFarm = ___onFarm;
|
||||||
|
animalBeingPurchased = ___animalBeingPurchased;
|
||||||
|
|
||||||
|
if (___onFarm && ___namingAnimal)
|
||||||
|
{
|
||||||
|
narrateNamingMenu(__instance, x, y);
|
||||||
|
}
|
||||||
|
else if (___onFarm && !___namingAnimal)
|
||||||
|
{
|
||||||
|
firstTimeInNamingMenu = true;
|
||||||
|
}
|
||||||
|
else if (!___onFarm && !___namingAnimal)
|
||||||
|
{
|
||||||
|
firstTimeInNamingMenu = true;
|
||||||
|
narratePurchasingMenu(__instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateNamingMenu(PurchaseAnimalsMenu __instance, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Cancel Button";
|
||||||
|
}
|
||||||
|
else if (__instance.doneNamingButton != null && __instance.doneNamingButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "OK Button";
|
||||||
|
}
|
||||||
|
else if (__instance.randomButton != null && __instance.randomButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Random Name Button";
|
||||||
|
}
|
||||||
|
else if (__instance.textBoxCC != null && __instance.textBoxCC.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Name Text Box";
|
||||||
|
// string? value = ___textBox.Text;
|
||||||
|
// if (value != "" && value != null && value != "null")
|
||||||
|
// toSpeak = $"{toSpeak}, Value: {value}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (purchaseAnimalMenuQuery == toSpeak) return;
|
||||||
|
|
||||||
|
purchaseAnimalMenuQuery = toSpeak;
|
||||||
|
|
||||||
|
if (firstTimeInNamingMenu)
|
||||||
|
{
|
||||||
|
toSpeak = $"Enter the name of animal in the name text box. {toSpeak}";
|
||||||
|
firstTimeInNamingMenu = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narratePurchasingMenu(PurchaseAnimalsMenu __instance)
|
||||||
|
{
|
||||||
|
if (__instance.hovered == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string toSpeak = "";
|
||||||
|
if (((StardewValley.Object)__instance.hovered.item).Type != null)
|
||||||
|
{
|
||||||
|
toSpeak = ((StardewValley.Object)__instance.hovered.item).Type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string displayName = PurchaseAnimalsMenu.getAnimalTitle(__instance.hovered.hoverText);
|
||||||
|
int price = __instance.hovered.item.salePrice();
|
||||||
|
string description = PurchaseAnimalsMenu.getAnimalDescription(__instance.hovered.hoverText);
|
||||||
|
|
||||||
|
toSpeak = $"{displayName}, Price: {price}g, Description: {description}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (purchaseAnimalMenuQuery == toSpeak) return;
|
||||||
|
|
||||||
|
purchaseAnimalMenuQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
purchaseAnimalMenuQuery = "";
|
||||||
|
firstTimeInNamingMenu = true;
|
||||||
|
purchaseAnimalsMenu = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class ShippingMenuPatch
|
||||||
|
{
|
||||||
|
internal static int prevSlotIndex = -999;
|
||||||
|
|
||||||
|
internal static void DrawPatch(ShippingMenu __instance, List<int> ___categoryTotals)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (__instance.currentPage == -1)
|
||||||
|
{
|
||||||
|
int total = ___categoryTotals[5];
|
||||||
|
string toSpeak;
|
||||||
|
if (__instance.okButton.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||||
|
{
|
||||||
|
// Perform Left Click
|
||||||
|
if (MainClass.Config.LeftClickMainKey.JustPressed() || MainClass.Config.LeftClickAlternateKey.JustPressed())
|
||||||
|
{
|
||||||
|
Game1.activeClickableMenu.receiveLeftClick(Game1.getMouseX(true), Game1.getMouseY(true));
|
||||||
|
}
|
||||||
|
toSpeak = $"{total}g in total. Press left mouse button to save.";
|
||||||
|
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < __instance.categories.Count; i++)
|
||||||
|
{
|
||||||
|
if (__instance.categories[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||||
|
{
|
||||||
|
toSpeak = $"Money recieved from {__instance.getCategoryName(i)}: {___categoryTotals[i]}g.";
|
||||||
|
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class TitleTextInputMenuPatch
|
||||||
|
{
|
||||||
|
internal static void DrawPatch(TitleTextInputMenu __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (__instance.pasteButton != null && __instance.pasteButton.containsPoint(x, y))
|
||||||
|
toSpeak = $"Paste button";
|
||||||
|
|
||||||
|
if (toSpeak != "")
|
||||||
|
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,287 +0,0 @@
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
|
||||||
using StardewValley;
|
|
||||||
using StardewValley.Menus;
|
|
||||||
using StardewValley.Quests;
|
|
||||||
|
|
||||||
namespace stardew_access.Patches
|
|
||||||
{
|
|
||||||
internal class QuestPatches
|
|
||||||
{
|
|
||||||
internal static string currentDailyQuestText = " ";
|
|
||||||
internal static string questLogQuery = " ";
|
|
||||||
internal static bool isNarratingQuestInfo = false, firstTimeInIndividualQuest = true;
|
|
||||||
|
|
||||||
#region For Special Orders Board
|
|
||||||
internal static void SpecialOrdersBoardPatch(SpecialOrdersBoard __instance)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
|
|
||||||
if (__instance.acceptLeftQuestButton.visible && __instance.acceptLeftQuestButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = getSpecialOrderDetails(__instance.leftOrder);
|
|
||||||
|
|
||||||
toSpeak = $"Left Quest:\n\t{toSpeak}\n\tPress left click to accept this quest.";
|
|
||||||
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.acceptRightQuestButton.visible && __instance.acceptRightQuestButton.containsPoint(x, y))
|
|
||||||
{
|
|
||||||
string toSpeak = getSpecialOrderDetails(__instance.rightOrder);
|
|
||||||
|
|
||||||
toSpeak = $"Right Quest:\n\t{toSpeak}\n\tPress left click to accept this quest.";
|
|
||||||
|
|
||||||
MainClass.ScreenReader.SayWithMenuChecker(toSpeak, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string getSpecialOrderDetails(SpecialOrder order)
|
|
||||||
{
|
|
||||||
int daysLeft = order.GetDaysLeft();
|
|
||||||
string description = order.GetDescription();
|
|
||||||
string objectiveDescription = "";
|
|
||||||
string name = order.GetName();
|
|
||||||
int moneyReward = order.GetMoneyReward();
|
|
||||||
|
|
||||||
// Get each objectives
|
|
||||||
for (int i = 0; i < order.GetObjectiveDescriptions().Count; i++)
|
|
||||||
{
|
|
||||||
objectiveDescription += order.GetObjectiveDescriptions()[i] + ", \n";
|
|
||||||
}
|
|
||||||
|
|
||||||
string toReturn = $"{name}\n\tDescription:{description}\n\tObjectives: {objectiveDescription}";
|
|
||||||
|
|
||||||
if (order.IsTimedQuest())
|
|
||||||
{
|
|
||||||
toReturn = $"{toReturn}\n\tTime: {daysLeft} days";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (order.HasMoneyReward())
|
|
||||||
{
|
|
||||||
toReturn = $"{toReturn}\n\tReward: {moneyReward}g";
|
|
||||||
}
|
|
||||||
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region For Normal Billboard in the town
|
|
||||||
internal static void BillboardPatch(Billboard __instance, bool ___dailyQuestBoard)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!___dailyQuestBoard)
|
|
||||||
{
|
|
||||||
#region Callender
|
|
||||||
for (int i = 0; i < __instance.calendarDays.Count; i++)
|
|
||||||
{
|
|
||||||
if (__instance.calendarDays[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
|
||||||
{
|
|
||||||
string toSpeak = $"Day {i + 1}";
|
|
||||||
|
|
||||||
if (__instance.calendarDays[i].name.Length > 0)
|
|
||||||
{
|
|
||||||
toSpeak += $", {__instance.calendarDays[i].name}";
|
|
||||||
}
|
|
||||||
if (__instance.calendarDays[i].hoverText.Length > 0)
|
|
||||||
{
|
|
||||||
toSpeak += $", {__instance.calendarDays[i].hoverText}";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Game1.dayOfMonth == i + 1)
|
|
||||||
toSpeak += $", Current";
|
|
||||||
|
|
||||||
MainClass.ScreenReader.SayWithChecker(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#region Daily Quest Board
|
|
||||||
if (Game1.questOfTheDay == null || Game1.questOfTheDay.currentObjective == null || Game1.questOfTheDay.currentObjective.Length == 0)
|
|
||||||
{
|
|
||||||
// No quests
|
|
||||||
string toSpeak = "No quests for today!";
|
|
||||||
if (currentDailyQuestText != toSpeak)
|
|
||||||
{
|
|
||||||
currentDailyQuestText = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SpriteFont font = ((LocalizedContentManager.CurrentLanguageCode == LocalizedContentManager.LanguageCode.ko) ? Game1.smallFont : Game1.dialogueFont);
|
|
||||||
string description = Game1.parseText(Game1.questOfTheDay.questDescription, font, 640);
|
|
||||||
string toSpeak = description;
|
|
||||||
|
|
||||||
if (currentDailyQuestText != toSpeak)
|
|
||||||
{
|
|
||||||
currentDailyQuestText = toSpeak;
|
|
||||||
|
|
||||||
// Snap to accept quest button
|
|
||||||
if (__instance.acceptQuestButton.visible)
|
|
||||||
{
|
|
||||||
toSpeak += "\t\n Left click to accept quest.";
|
|
||||||
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
|
||||||
}
|
|
||||||
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Journal Menu
|
|
||||||
internal static void QuestLogPatch(QuestLog __instance, int ___questPage, List<List<IQuest>> ___pages, int ___currentPage, IQuest ____shownQuest, List<string> ____objectiveText)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
|
||||||
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
|
||||||
string toSpeak = " ", extra = "";
|
|
||||||
|
|
||||||
if (___questPage == -1)
|
|
||||||
{
|
|
||||||
#region Quest Lists
|
|
||||||
if (!firstTimeInIndividualQuest)
|
|
||||||
firstTimeInIndividualQuest = true;
|
|
||||||
|
|
||||||
for (int i = 0; i < __instance.questLogButtons.Count; i++)
|
|
||||||
{
|
|
||||||
if (___pages.Count() > 0 && ___pages[___currentPage].Count() > i)
|
|
||||||
{
|
|
||||||
if (!__instance.questLogButtons[i].containsPoint(x, y))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
string name = ___pages[___currentPage][i].GetName();
|
|
||||||
int daysLeft = ___pages[___currentPage][i].GetDaysLeft();
|
|
||||||
toSpeak = $"{name}";
|
|
||||||
|
|
||||||
if (daysLeft > 0 && ___pages[___currentPage][i].ShouldDisplayAsComplete())
|
|
||||||
toSpeak += $"\t\n {daysLeft} days left";
|
|
||||||
|
|
||||||
toSpeak += ___pages[___currentPage][i].ShouldDisplayAsComplete() ? " completed!" : "";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Previous page button";
|
|
||||||
else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Next page button";
|
|
||||||
else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Close menu button";
|
|
||||||
|
|
||||||
if (questLogQuery != toSpeak)
|
|
||||||
{
|
|
||||||
questLogQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(toSpeak, true);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#region Individual quest
|
|
||||||
bool containsReward = __instance.HasReward() || __instance.HasMoneyReward();
|
|
||||||
string description = Game1.parseText(____shownQuest.GetDescription(), Game1.dialogueFont, __instance.width - 128);
|
|
||||||
string title = ____shownQuest.GetName();
|
|
||||||
|
|
||||||
if (firstTimeInIndividualQuest || (isPrimaryInfoKeyPressed && !isNarratingQuestInfo))
|
|
||||||
{
|
|
||||||
if (firstTimeInIndividualQuest)
|
|
||||||
toSpeak = "Back button";
|
|
||||||
|
|
||||||
if (____shownQuest.ShouldDisplayAsComplete())
|
|
||||||
{
|
|
||||||
#region Quest completed menu
|
|
||||||
|
|
||||||
extra = $"Quest: {title} Completed!";
|
|
||||||
|
|
||||||
if (__instance.HasMoneyReward())
|
|
||||||
extra += $"you recieved {____shownQuest.GetMoneyReward()}g";
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#region Quest in-complete menu
|
|
||||||
extra = $"Title: {title}. \t\n Description: {description}";
|
|
||||||
|
|
||||||
for (int j = 0; j < ____objectiveText.Count; j++)
|
|
||||||
{
|
|
||||||
string parsed_text = Game1.parseText(____objectiveText[j], width: __instance.width - 192, whichFont: Game1.dialogueFont);
|
|
||||||
if (____shownQuest != null && ____shownQuest is SpecialOrder)
|
|
||||||
{
|
|
||||||
OrderObjective order_objective = ((SpecialOrder)____shownQuest).objectives[j];
|
|
||||||
if (order_objective.GetMaxCount() > 1 && order_objective.ShouldShowProgress())
|
|
||||||
parsed_text += "\n\t" + order_objective.GetCount() + " of " + order_objective.GetMaxCount() + " completed";
|
|
||||||
}
|
|
||||||
|
|
||||||
extra += $"\t\nOrder {j + 1}: {parsed_text} \t\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (____shownQuest != null)
|
|
||||||
{
|
|
||||||
int daysLeft = ____shownQuest.GetDaysLeft();
|
|
||||||
|
|
||||||
if (daysLeft > 0)
|
|
||||||
extra += $"\t\n{daysLeft} days left.";
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
isNarratingQuestInfo = true;
|
|
||||||
Task.Delay(200).ContinueWith(_ => { isNarratingQuestInfo = false; });
|
|
||||||
questLogQuery = " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!firstTimeInIndividualQuest)
|
|
||||||
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
|
||||||
toSpeak = (___currentPage > 0) ? "Previous page button" : "Back button";
|
|
||||||
else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Next page button";
|
|
||||||
else if (__instance.cancelQuestButton != null && __instance.cancelQuestButton.visible && __instance.cancelQuestButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Cancel quest button";
|
|
||||||
else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y))
|
|
||||||
toSpeak = "Close menu button";
|
|
||||||
else if (containsReward && __instance.rewardBox.containsPoint(x, y))
|
|
||||||
toSpeak = "Left click to collect reward";
|
|
||||||
|
|
||||||
if (firstTimeInIndividualQuest || (questLogQuery != toSpeak))
|
|
||||||
{
|
|
||||||
questLogQuery = toSpeak;
|
|
||||||
MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true);
|
|
||||||
|
|
||||||
if (firstTimeInIndividualQuest)
|
|
||||||
firstTimeInIndividualQuest = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class BillboardPatch
|
||||||
|
{
|
||||||
|
private static string billboardQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(Billboard __instance, bool ___dailyQuestBoard)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (___dailyQuestBoard)
|
||||||
|
{
|
||||||
|
narrateDailyQuestBoard(__instance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
narrateCallendar(__instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateCallendar(Billboard __instance)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < __instance.calendarDays.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.calendarDays[i].containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string toSpeak = $"Day {i + 1}";
|
||||||
|
|
||||||
|
if (__instance.calendarDays[i].name.Length > 0)
|
||||||
|
{
|
||||||
|
toSpeak += $", {__instance.calendarDays[i].name}";
|
||||||
|
}
|
||||||
|
if (__instance.calendarDays[i].hoverText.Length > 0)
|
||||||
|
{
|
||||||
|
toSpeak += $", {__instance.calendarDays[i].hoverText}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Game1.dayOfMonth == i + 1)
|
||||||
|
toSpeak += $", Current";
|
||||||
|
|
||||||
|
if (billboardQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
billboardQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateDailyQuestBoard(Billboard __instance)
|
||||||
|
{
|
||||||
|
if (Game1.questOfTheDay == null || Game1.questOfTheDay.currentObjective == null || Game1.questOfTheDay.currentObjective.Length == 0)
|
||||||
|
{
|
||||||
|
// No quests
|
||||||
|
string toSpeak = "No quests for today!";
|
||||||
|
if (billboardQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
billboardQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpriteFont font = ((LocalizedContentManager.CurrentLanguageCode == LocalizedContentManager.LanguageCode.ko) ? Game1.smallFont : Game1.dialogueFont);
|
||||||
|
string description = Game1.parseText(Game1.questOfTheDay.questDescription, font, 640);
|
||||||
|
string toSpeak = description;
|
||||||
|
|
||||||
|
if (billboardQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
billboardQueryKey = toSpeak;
|
||||||
|
|
||||||
|
// Snap to accept quest button
|
||||||
|
if (__instance.acceptQuestButton.visible)
|
||||||
|
{
|
||||||
|
toSpeak += "\t\n Left click to accept quest.";
|
||||||
|
__instance.acceptQuestButton.snapMouseCursorToCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
billboardQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using StardewValley.Quests;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
// a.k.a. Journal Menu
|
||||||
|
internal class QuestLogPatch
|
||||||
|
{
|
||||||
|
internal static string questLogQuery = "";
|
||||||
|
internal static bool isNarratingQuestInfo = false;
|
||||||
|
internal static bool firstTimeInIndividualQuest = true;
|
||||||
|
|
||||||
|
internal static void DrawPatch(QuestLog __instance, int ___questPage, List<List<IQuest>> ___pages, int ___currentPage, IQuest ____shownQuest, List<string> ____objectiveText)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (___questPage == -1)
|
||||||
|
{
|
||||||
|
narrateQuestList(__instance, ___pages, ___currentPage, x, y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
narrateIndividualQuest(__instance, ___currentPage, ____shownQuest, ____objectiveText, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateQuestList(QuestLog __instance, List<List<IQuest>> ___pages, int ___currentPage, int x, int y)
|
||||||
|
{
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
if (!firstTimeInIndividualQuest) firstTimeInIndividualQuest = true;
|
||||||
|
|
||||||
|
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Previous page button";
|
||||||
|
else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Next page button";
|
||||||
|
else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Close menu button";
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < __instance.questLogButtons.Count; i++)
|
||||||
|
{
|
||||||
|
if (___pages.Count() <= 0 || ___pages[___currentPage].Count() <= i)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!__instance.questLogButtons[i].containsPoint(x, y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string name = ___pages[___currentPage][i].GetName();
|
||||||
|
int daysLeft = ___pages[___currentPage][i].GetDaysLeft();
|
||||||
|
toSpeak = $"{name}";
|
||||||
|
|
||||||
|
if (daysLeft > 0 && ___pages[___currentPage][i].ShouldDisplayAsComplete())
|
||||||
|
toSpeak += $"\t\n {daysLeft} days left";
|
||||||
|
|
||||||
|
toSpeak += ___pages[___currentPage][i].ShouldDisplayAsComplete() ? " completed!" : "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (questLogQuery != toSpeak)
|
||||||
|
{
|
||||||
|
questLogQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void narrateIndividualQuest(QuestLog __instance, int ___currentPage, IQuest ____shownQuest, List<string> ____objectiveText, int x, int y)
|
||||||
|
{
|
||||||
|
bool isPrimaryInfoKeyPressed = MainClass.Config.PrimaryInfoKey.JustPressed();
|
||||||
|
bool containsReward = __instance.HasReward() || __instance.HasMoneyReward();
|
||||||
|
string description = Game1.parseText(____shownQuest.GetDescription(), Game1.dialogueFont, __instance.width - 128);
|
||||||
|
string title = ____shownQuest.GetName();
|
||||||
|
string toSpeak = "";
|
||||||
|
string extra = "";
|
||||||
|
|
||||||
|
if (firstTimeInIndividualQuest || (isPrimaryInfoKeyPressed && !isNarratingQuestInfo))
|
||||||
|
{
|
||||||
|
if (firstTimeInIndividualQuest)
|
||||||
|
toSpeak = "Back button";
|
||||||
|
|
||||||
|
if (____shownQuest.ShouldDisplayAsComplete())
|
||||||
|
{
|
||||||
|
#region Quest completed menu
|
||||||
|
|
||||||
|
extra = $"Quest: {title} Completed!";
|
||||||
|
|
||||||
|
if (__instance.HasMoneyReward())
|
||||||
|
extra += $"you recieved {____shownQuest.GetMoneyReward()}g";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#region Quest in-complete menu
|
||||||
|
extra = $"Title: {title}. \t\n Description: {description}";
|
||||||
|
|
||||||
|
for (int j = 0; j < ____objectiveText.Count; j++)
|
||||||
|
{
|
||||||
|
string parsed_text = Game1.parseText(____objectiveText[j], width: __instance.width - 192, whichFont: Game1.dialogueFont);
|
||||||
|
if (____shownQuest != null && ____shownQuest is SpecialOrder)
|
||||||
|
{
|
||||||
|
OrderObjective order_objective = ((SpecialOrder)____shownQuest).objectives[j];
|
||||||
|
if (order_objective.GetMaxCount() > 1 && order_objective.ShouldShowProgress())
|
||||||
|
parsed_text += "\n\t" + order_objective.GetCount() + " of " + order_objective.GetMaxCount() + " completed";
|
||||||
|
}
|
||||||
|
|
||||||
|
extra += $"\t\nOrder {j + 1}: {parsed_text} \t\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (____shownQuest != null)
|
||||||
|
{
|
||||||
|
int daysLeft = ____shownQuest.GetDaysLeft();
|
||||||
|
|
||||||
|
if (daysLeft > 0)
|
||||||
|
extra += $"\t\n{daysLeft} days left.";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
isNarratingQuestInfo = true;
|
||||||
|
Task.Delay(200).ContinueWith(_ => { isNarratingQuestInfo = false; });
|
||||||
|
questLogQuery = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstTimeInIndividualQuest)
|
||||||
|
{
|
||||||
|
if (__instance.backButton != null && __instance.backButton.visible && __instance.backButton.containsPoint(x, y))
|
||||||
|
toSpeak = (___currentPage > 0) ? "Previous page button" : "Back button";
|
||||||
|
else if (__instance.forwardButton != null && __instance.forwardButton.visible && __instance.forwardButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Next page button";
|
||||||
|
else if (__instance.cancelQuestButton != null && __instance.cancelQuestButton.visible && __instance.cancelQuestButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Cancel quest button";
|
||||||
|
else if (__instance.upperRightCloseButton != null && __instance.upperRightCloseButton.visible && __instance.upperRightCloseButton.containsPoint(x, y))
|
||||||
|
toSpeak = "Close menu button";
|
||||||
|
else if (containsReward && __instance.rewardBox.containsPoint(x, y))
|
||||||
|
toSpeak = "Left click to collect reward";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstTimeInIndividualQuest || (questLogQuery != toSpeak))
|
||||||
|
{
|
||||||
|
questLogQuery = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(extra + " \n\t" + toSpeak, true);
|
||||||
|
|
||||||
|
if (firstTimeInIndividualQuest) firstTimeInIndividualQuest = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleaup()
|
||||||
|
{
|
||||||
|
questLogQuery = "";
|
||||||
|
isNarratingQuestInfo = false;
|
||||||
|
firstTimeInIndividualQuest = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class SpecialOrdersBoardPatch
|
||||||
|
{
|
||||||
|
private static string specialOrdersBoardQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(SpecialOrdersBoard __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
|
||||||
|
if (__instance.acceptLeftQuestButton.visible && __instance.acceptLeftQuestButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
string toSpeak = getSpecialOrderDetails(__instance.leftOrder);
|
||||||
|
|
||||||
|
toSpeak = $"Left Quest:\n\t{toSpeak}\n\tPress left click to accept this quest.";
|
||||||
|
|
||||||
|
Speak(toSpeak);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__instance.acceptRightQuestButton.visible && __instance.acceptRightQuestButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
string toSpeak = getSpecialOrderDetails(__instance.rightOrder);
|
||||||
|
|
||||||
|
toSpeak = $"Right Quest:\n\t{toSpeak}\n\tPress left click to accept this quest.";
|
||||||
|
|
||||||
|
Speak(toSpeak);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string getSpecialOrderDetails(SpecialOrder order)
|
||||||
|
{
|
||||||
|
int daysLeft = order.GetDaysLeft();
|
||||||
|
string description = order.GetDescription();
|
||||||
|
string objectiveDescription = "";
|
||||||
|
string name = order.GetName();
|
||||||
|
int moneyReward = order.GetMoneyReward();
|
||||||
|
|
||||||
|
// Get each objectives
|
||||||
|
for (int i = 0; i < order.GetObjectiveDescriptions().Count; i++)
|
||||||
|
{
|
||||||
|
objectiveDescription += order.GetObjectiveDescriptions()[i] + ", \n";
|
||||||
|
}
|
||||||
|
|
||||||
|
string toReturn = $"{name}\n\tDescription:{description}\n\tObjectives: {objectiveDescription}";
|
||||||
|
|
||||||
|
if (order.IsTimedQuest())
|
||||||
|
{
|
||||||
|
toReturn = $"{toReturn}\n\tTime: {daysLeft} days";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order.HasMoneyReward())
|
||||||
|
{
|
||||||
|
toReturn = $"{toReturn}\n\tReward: {moneyReward}g";
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Speak(string toSpeak)
|
||||||
|
{
|
||||||
|
if (specialOrdersBoardQueryKey == toSpeak) return;
|
||||||
|
|
||||||
|
specialOrdersBoardQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
specialOrdersBoardQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,85 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class AdvancedGameOptionsPatch
|
||||||
|
{
|
||||||
|
public static string advancedGameOptionsQueryKey = " ";
|
||||||
|
|
||||||
|
internal static void DrawPatch(AdvancedGameOptions __instance)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int currentItemIndex = Math.Max(0, Math.Min(__instance.options.Count - 7, __instance.currentItemIndex));
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||||
|
|
||||||
|
if (__instance.okButton != null && __instance.okButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
string toSpeak = "OK Button";
|
||||||
|
if (advancedGameOptionsQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
advancedGameOptionsQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < __instance.optionSlots.Count; i++)
|
||||||
|
{
|
||||||
|
if (!__instance.optionSlots[i].bounds.Contains(x, y)
|
||||||
|
|| currentItemIndex + i >= __instance.options.Count
|
||||||
|
|| !__instance.options[currentItemIndex + i].bounds.Contains(x - __instance.optionSlots[i].bounds.X, y - __instance.optionSlots[i].bounds.Y))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
OptionsElement optionsElement = __instance.options[currentItemIndex + i];
|
||||||
|
string toSpeak = optionsElement.label;
|
||||||
|
|
||||||
|
if (optionsElement is OptionsButton)
|
||||||
|
toSpeak = $" {toSpeak} Button";
|
||||||
|
else if (optionsElement is OptionsCheckbox)
|
||||||
|
toSpeak = (((OptionsCheckbox)optionsElement).isChecked ? "Enabled" : "Disabled") + $" {toSpeak} Checkbox";
|
||||||
|
else if (optionsElement is OptionsDropDown)
|
||||||
|
toSpeak = $"{toSpeak} Dropdown, option {((OptionsDropDown)optionsElement).dropDownDisplayOptions[((OptionsDropDown)optionsElement).selectedOption]} selected";
|
||||||
|
else if (optionsElement is OptionsSlider)
|
||||||
|
toSpeak = $"{((OptionsSlider)optionsElement).value}% {toSpeak} Slider";
|
||||||
|
else if (optionsElement is OptionsPlusMinus)
|
||||||
|
toSpeak = $"{((OptionsPlusMinus)optionsElement).displayOptions[((OptionsPlusMinus)optionsElement).selected]} selected of {toSpeak}";
|
||||||
|
else if (optionsElement is OptionsInputListener)
|
||||||
|
{
|
||||||
|
string buttons = "";
|
||||||
|
((OptionsInputListener)optionsElement).buttonNames.ForEach(name => { buttons += $", {name}"; });
|
||||||
|
toSpeak = $"{toSpeak} is bound to {buttons}. Left click to change.";
|
||||||
|
}
|
||||||
|
else if (optionsElement is OptionsTextEntry)
|
||||||
|
{
|
||||||
|
toSpeak = $"Seed text box";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (toSpeak.Contains(":"))
|
||||||
|
toSpeak = toSpeak.Replace(":", "");
|
||||||
|
|
||||||
|
toSpeak = $"{toSpeak} Options:";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advancedGameOptionsQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
advancedGameOptionsQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in advanced game menu patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
advancedGameOptionsQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
using StardewValley;
|
using StardewValley;
|
||||||
using StardewValley.Menus;
|
using StardewValley.Menus;
|
||||||
|
|
||||||
namespace stardew_access.Patches {
|
namespace stardew_access.Patches
|
||||||
internal class CharacterCustomizationPatches {
|
{
|
||||||
|
internal class CharacterCustomizationMenuPatch
|
||||||
|
{
|
||||||
private static bool isRunning = false;
|
private static bool isRunning = false;
|
||||||
private static int saveGameIndex = -1;
|
private static int saveGameIndex = -1;
|
||||||
public static string characterCreationMenuQueryKey = " ";
|
public static string characterCreationMenuQueryKey = " ";
|
||||||
|
@ -28,12 +30,14 @@ namespace stardew_access.Patches {
|
||||||
public static bool characterDesignToggleShouldSpeak = true;
|
public static bool characterDesignToggleShouldSpeak = true;
|
||||||
public static ClickableComponent? currentComponent = null;
|
public static ClickableComponent? currentComponent = null;
|
||||||
|
|
||||||
internal static void CharacterCustomizationMenuPatch(CharacterCustomization __instance, bool ___skipIntro,
|
internal static void DrawPatch(CharacterCustomization __instance, bool ___skipIntro,
|
||||||
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
|
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
|
||||||
TextBox ___farmnameBox, TextBox ___favThingBox)
|
TextBox ___farmnameBox, TextBox ___favThingBox)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (TextBoxPatch.isAnyTextBoxActive) return;
|
||||||
|
|
||||||
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
bool isEscPressed = Game1.input.GetKeyboardState().IsKeyDown(Microsoft.Xna.Framework.Input.Keys.Escape); // For escaping/unselecting from the animal name text box
|
||||||
string toSpeak = "";
|
string toSpeak = "";
|
||||||
if (characterDesignToggleShouldSpeak)
|
if (characterDesignToggleShouldSpeak)
|
||||||
|
@ -44,34 +48,7 @@ namespace stardew_access.Patches {
|
||||||
string itemsToSpeak = "";
|
string itemsToSpeak = "";
|
||||||
string changesToSpeak = "";
|
string changesToSpeak = "";
|
||||||
|
|
||||||
if (___nameBox.Selected)
|
if (MainClass.Config.CharacterCreationMenuNextKey.JustPressed() && !isRunning)
|
||||||
{
|
|
||||||
toSpeak = ___nameBox.Text;
|
|
||||||
|
|
||||||
if (isEscPressed)
|
|
||||||
{
|
|
||||||
___nameBox.Selected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (___farmnameBox.Selected)
|
|
||||||
{
|
|
||||||
toSpeak = ___farmnameBox.Text;
|
|
||||||
|
|
||||||
if (isEscPressed)
|
|
||||||
{
|
|
||||||
___farmnameBox.Selected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (___favThingBox.Selected)
|
|
||||||
{
|
|
||||||
toSpeak = ___favThingBox.Text;
|
|
||||||
|
|
||||||
if (isEscPressed)
|
|
||||||
{
|
|
||||||
___favThingBox.Selected = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (MainClass.Config.CharacterCreationMenuNextKey.JustPressed() && !isRunning)
|
|
||||||
{
|
{
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
itemsToSpeak = CycleThroughItems(true, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel, ___nameBox, ___farmnameBox, ___favThingBox);
|
itemsToSpeak = CycleThroughItems(true, __instance, ___skipIntro, ___startingCabinsLabel, ___difficultyModifierLabel, ___nameBox, ___farmnameBox, ___favThingBox);
|
||||||
|
@ -122,7 +99,9 @@ namespace stardew_access.Patches {
|
||||||
if (characterDesignToggle)
|
if (characterDesignToggle)
|
||||||
{
|
{
|
||||||
displayState = "shown";
|
displayState = "shown";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
displayState = "hidden";
|
displayState = "hidden";
|
||||||
}
|
}
|
||||||
toSpeak = $"Character design controls {displayState}. \n {toSpeak}";
|
toSpeak = $"Character design controls {displayState}. \n {toSpeak}";
|
||||||
|
@ -140,7 +119,7 @@ namespace stardew_access.Patches {
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
MainClass.ErrorLog($"Unable to narrate Text:\n{e.Message}\n{e.StackTrace}");
|
MainClass.ErrorLog($"An error occured in character customization menu patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +189,9 @@ namespace stardew_access.Patches {
|
||||||
prevEyeColorHue = currentEyeColorHue;
|
prevEyeColorHue = currentEyeColorHue;
|
||||||
if (currentEyeColorHue != "")
|
if (currentEyeColorHue != "")
|
||||||
toSpeak = $"{toSpeak} \n Hue: {currentEyeColorHue}";
|
toSpeak = $"{toSpeak} \n Hue: {currentEyeColorHue}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevEyeColorHue = "";
|
prevEyeColorHue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +203,9 @@ namespace stardew_access.Patches {
|
||||||
prevEyeColorSaturation = currentEyeColorSaturation;
|
prevEyeColorSaturation = currentEyeColorSaturation;
|
||||||
if (currentEyeColorSaturation != "")
|
if (currentEyeColorSaturation != "")
|
||||||
toSpeak = $"{toSpeak} \n Saturation: {currentEyeColorSaturation}";
|
toSpeak = $"{toSpeak} \n Saturation: {currentEyeColorSaturation}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevEyeColorSaturation = "";
|
prevEyeColorSaturation = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +217,9 @@ namespace stardew_access.Patches {
|
||||||
prevEyeColorValue = currentEyeColorValue;
|
prevEyeColorValue = currentEyeColorValue;
|
||||||
if (currentEyeColorValue != "")
|
if (currentEyeColorValue != "")
|
||||||
toSpeak = $"{toSpeak} \n Value: {currentEyeColorValue}";
|
toSpeak = $"{toSpeak} \n Value: {currentEyeColorValue}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevEyeColorValue = "";
|
prevEyeColorValue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,7 +241,9 @@ namespace stardew_access.Patches {
|
||||||
prevHairColorHue = currentHairColorHue;
|
prevHairColorHue = currentHairColorHue;
|
||||||
if (currentHairColorHue != "")
|
if (currentHairColorHue != "")
|
||||||
toSpeak = $"{toSpeak} \n Hue: {currentHairColorHue}";
|
toSpeak = $"{toSpeak} \n Hue: {currentHairColorHue}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevHairColorHue = "";
|
prevHairColorHue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +255,9 @@ namespace stardew_access.Patches {
|
||||||
prevHairColorSaturation = currentHairColorSaturation;
|
prevHairColorSaturation = currentHairColorSaturation;
|
||||||
if (currentHairColorSaturation != "")
|
if (currentHairColorSaturation != "")
|
||||||
toSpeak = $"{toSpeak} \n Saturation: {currentHairColorSaturation}";
|
toSpeak = $"{toSpeak} \n Saturation: {currentHairColorSaturation}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevHairColorSaturation = "";
|
prevHairColorSaturation = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +269,9 @@ namespace stardew_access.Patches {
|
||||||
prevHairColorValue = currentHairColorValue;
|
prevHairColorValue = currentHairColorValue;
|
||||||
if (currentHairColorValue != "")
|
if (currentHairColorValue != "")
|
||||||
toSpeak = $"{toSpeak} \n Value: {currentHairColorValue}";
|
toSpeak = $"{toSpeak} \n Value: {currentHairColorValue}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevHairColorValue = "";
|
prevHairColorValue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,7 +293,9 @@ namespace stardew_access.Patches {
|
||||||
prevPantsColorHue = currentPantsColorHue;
|
prevPantsColorHue = currentPantsColorHue;
|
||||||
if (currentPantsColorHue != "")
|
if (currentPantsColorHue != "")
|
||||||
toSpeak = $"{toSpeak} \n Hue: {currentPantsColorHue}";
|
toSpeak = $"{toSpeak} \n Hue: {currentPantsColorHue}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevPantsColorHue = "";
|
prevPantsColorHue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,7 +307,9 @@ namespace stardew_access.Patches {
|
||||||
prevPantsColorSaturation = currentPantsColorSaturation;
|
prevPantsColorSaturation = currentPantsColorSaturation;
|
||||||
if (currentPantsColorSaturation != "")
|
if (currentPantsColorSaturation != "")
|
||||||
toSpeak = $"{toSpeak} \n Saturation: {currentPantsColorSaturation}";
|
toSpeak = $"{toSpeak} \n Saturation: {currentPantsColorSaturation}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevPantsColorSaturation = "";
|
prevPantsColorSaturation = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -326,7 +321,9 @@ namespace stardew_access.Patches {
|
||||||
prevPantsColorValue = currentPantsColorValue;
|
prevPantsColorValue = currentPantsColorValue;
|
||||||
if (currentPantsColorValue != "")
|
if (currentPantsColorValue != "")
|
||||||
toSpeak = $"{toSpeak} \n Value: {currentPantsColorValue}";
|
toSpeak = $"{toSpeak} \n Value: {currentPantsColorValue}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
prevPantsColorValue = "";
|
prevPantsColorValue = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,7 +348,6 @@ namespace stardew_access.Patches {
|
||||||
return toSpeak.Trim();
|
return toSpeak.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static string CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro,
|
private static string CycleThroughItems(bool increase, CharacterCustomization __instance, bool ___skipIntro,
|
||||||
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
|
ClickableComponent ___startingCabinsLabel, ClickableComponent ___difficultyModifierLabel, TextBox ___nameBox,
|
||||||
TextBox ___farmnameBox, TextBox ___favThingBox)
|
TextBox ___farmnameBox, TextBox ___favThingBox)
|
||||||
|
@ -369,7 +365,9 @@ namespace stardew_access.Patches {
|
||||||
if (___nameBox.Text != "")
|
if (___nameBox.Text != "")
|
||||||
{
|
{
|
||||||
postText = $": {___nameBox.Text}";
|
postText = $": {___nameBox.Text}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
postText = " Text Box";
|
postText = " Text Box";
|
||||||
}
|
}
|
||||||
buttons.Add(__instance.nameBoxCC, $"Farmer's Name{postText}");
|
buttons.Add(__instance.nameBoxCC, $"Farmer's Name{postText}");
|
||||||
|
@ -380,7 +378,9 @@ namespace stardew_access.Patches {
|
||||||
if (___farmnameBox.Text != "")
|
if (___farmnameBox.Text != "")
|
||||||
{
|
{
|
||||||
postText = $": {___farmnameBox.Text}";
|
postText = $": {___farmnameBox.Text}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
postText = " Text Box";
|
postText = " Text Box";
|
||||||
}
|
}
|
||||||
buttons.Add(__instance.farmnameBoxCC, $"Farm's Name{postText}");
|
buttons.Add(__instance.farmnameBoxCC, $"Farm's Name{postText}");
|
||||||
|
@ -391,7 +391,9 @@ namespace stardew_access.Patches {
|
||||||
if (___favThingBox.Text != "")
|
if (___favThingBox.Text != "")
|
||||||
{
|
{
|
||||||
postText = $": {___favThingBox.Text}";
|
postText = $": {___favThingBox.Text}";
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
postText = " Text Box";
|
postText = " Text Box";
|
||||||
}
|
}
|
||||||
buttons.Add(__instance.favThingBoxCC, $"Favourite Thing{postText}");
|
buttons.Add(__instance.favThingBoxCC, $"Favourite Thing{postText}");
|
||||||
|
@ -655,7 +657,9 @@ namespace stardew_access.Patches {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return sb;
|
return sb;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -675,7 +679,9 @@ namespace stardew_access.Patches {
|
||||||
{
|
{
|
||||||
value = Math.Min(value + amount, 99d);
|
value = Math.Min(value + amount, 99d);
|
||||||
x = Math.Min(Math.Ceiling((value * step)), (double)sb.bounds.Width);
|
x = Math.Min(Math.Ceiling((value * step)), (double)sb.bounds.Width);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
value = Math.Max(value - amount, 0d);
|
value = Math.Max(value - amount, 0d);
|
||||||
x = Math.Max(Math.Ceiling((value * step)), 0d);
|
x = Math.Max(Math.Ceiling((value * step)), 0d);
|
||||||
}
|
}
|
||||||
|
@ -821,7 +827,9 @@ namespace stardew_access.Patches {
|
||||||
if (currentComponent != null && currentComponent.name == "Pet")
|
if (currentComponent != null && currentComponent.name == "Pet")
|
||||||
{
|
{
|
||||||
return ((Game1.player.catPerson) ? "Cat" : "Dog") + " Breed: " + Game1.player.whichPetBreed;
|
return ((Game1.player.catPerson) ? "Cat" : "Dog") + " Breed: " + Game1.player.whichPetBreed;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class CoopMenuPatch
|
||||||
|
{
|
||||||
|
private static string coopMenuQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(CoopMenu __instance, CoopMenu.Tab ___currentTab)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
#region Join/Host Button (Important! This should be checked before checking other buttons)
|
||||||
|
if (__instance.slotButtons[0].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
if (___currentTab == CoopMenu.Tab.JOIN_TAB)
|
||||||
|
toSpeak = "Join lan game";
|
||||||
|
if (___currentTab == CoopMenu.Tab.HOST_TAB)
|
||||||
|
toSpeak = "Host new farm";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Other Buttons
|
||||||
|
if (__instance.joinTab.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Join Tab Button";
|
||||||
|
}
|
||||||
|
else if (__instance.hostTab.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Host Tab Button";
|
||||||
|
}
|
||||||
|
else if (__instance.refreshButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Refresh Button";
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
if (coopMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
coopMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in co-op menu patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
coopMenuQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
using static StardewValley.Menus.LoadGameMenu;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class LoadGameMenuPatch
|
||||||
|
{
|
||||||
|
private static string loadGameMenuQueryKey = "";
|
||||||
|
private static bool firstTimeInMenu = true;
|
||||||
|
|
||||||
|
internal static void DrawPatch(SaveFileSlot __instance, LoadGameMenu ___menu, int i)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true);
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
if (!___menu.slotButtons[i].containsPoint(x, y)) return;
|
||||||
|
if (__instance.Farmer == null) return;
|
||||||
|
|
||||||
|
if (___menu.deleteButtons.Count > 0 && ___menu.deleteButtons[i].containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = $"Delete {__instance.Farmer.farmName.Value} Farm";
|
||||||
|
if (loadGameMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
loadGameMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (___menu.deleteConfirmationScreen)
|
||||||
|
{
|
||||||
|
if (firstTimeInMenu)
|
||||||
|
{
|
||||||
|
firstTimeInMenu = false;
|
||||||
|
toSpeak = "Really delete farm?";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (___menu.okDeleteButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} Ok button";
|
||||||
|
}
|
||||||
|
else if (___menu.cancelDeleteButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = $"{toSpeak} Cancel button";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadGameMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
loadGameMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String farmerName = __instance.Farmer.displayName;
|
||||||
|
String farmName = __instance.Farmer.farmName.Value;
|
||||||
|
String money = __instance.Farmer.Money.ToString();
|
||||||
|
String hoursPlayed = Utility.getHoursMinutesStringFromMilliseconds(__instance.Farmer.millisecondsPlayed);
|
||||||
|
string dateStringForSaveGame = ((!__instance.Farmer.dayOfMonthForSaveGame.HasValue ||
|
||||||
|
!__instance.Farmer.seasonForSaveGame.HasValue ||
|
||||||
|
!__instance.Farmer.yearForSaveGame.HasValue) ? __instance.Farmer.dateStringForSaveGame : Utility.getDateStringFor(__instance.Farmer.dayOfMonthForSaveGame.Value, __instance.Farmer.seasonForSaveGame.Value, __instance.Farmer.yearForSaveGame.Value));
|
||||||
|
|
||||||
|
toSpeak = $"{farmName} Farm Selected, \t\n Farmer: {farmerName}, \t\nMoney: {money}, \t\nHours Played: {hoursPlayed}, \t\nDate: {dateStringForSaveGame}";
|
||||||
|
|
||||||
|
if (loadGameMenuQueryKey != toSpeak)
|
||||||
|
{
|
||||||
|
loadGameMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in load game menu patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
loadGameMenuQueryKey = "";
|
||||||
|
firstTimeInMenu = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
using StardewValley;
|
||||||
|
using StardewValley.Menus;
|
||||||
|
|
||||||
|
namespace stardew_access.Patches
|
||||||
|
{
|
||||||
|
internal class TitleMenuPatch
|
||||||
|
{
|
||||||
|
private static string titleMenuQueryKey = "";
|
||||||
|
|
||||||
|
internal static void DrawPatch(TitleMenu __instance, bool ___isTransitioningButtons)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (___isTransitioningButtons)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int x = Game1.getMouseX(true), y = Game1.getMouseY(true); // Mouse x and y position
|
||||||
|
string toSpeak = "";
|
||||||
|
|
||||||
|
if (__instance.muteMusicButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Mute Music Button";
|
||||||
|
}
|
||||||
|
else if (__instance.aboutButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "About Button";
|
||||||
|
}
|
||||||
|
else if (__instance.languageButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Language Button";
|
||||||
|
}
|
||||||
|
else if (__instance.windowedButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
toSpeak = "Fullscreen: " + ((Game1.isFullscreen) ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
else if (TitleMenu.subMenu != null && __instance.backButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
string text = "Back Button";
|
||||||
|
MainClass.ScreenReader.SayWithChecker(text, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__instance.buttons.ForEach(component =>
|
||||||
|
{
|
||||||
|
if (!component.containsPoint(Game1.getMouseX(true), Game1.getMouseY(true)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
string name = component.name;
|
||||||
|
string label = component.label;
|
||||||
|
toSpeak = $"{name} {label} Button";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fix for back button not working using keyboard
|
||||||
|
if (TitleMenu.subMenu is CharacterCustomization && ((CharacterCustomization)TitleMenu.subMenu).backButton.containsPoint(x, y))
|
||||||
|
{
|
||||||
|
// Perform Left Click
|
||||||
|
if (MainClass.Config.LeftClickMainKey.JustPressed())
|
||||||
|
{
|
||||||
|
__instance.backButtonPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TitleMenu.subMenu == null && titleMenuQueryKey!=toSpeak)
|
||||||
|
{
|
||||||
|
titleMenuQueryKey = toSpeak;
|
||||||
|
MainClass.ScreenReader.Say(toSpeak, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
MainClass.ErrorLog($"An error occured in title menu patch:\n{e.Message}\n{e.StackTrace}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Cleanup()
|
||||||
|
{
|
||||||
|
titleMenuQueryKey = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Loading…
Reference in New Issue