Added GemRB sources

This commit is contained in:
pelya
2010-12-14 09:47:29 +00:00
parent 674da851ef
commit 38bceffddd
455 changed files with 137680 additions and 0 deletions

View File

@@ -0,0 +1,33 @@
# The application settings for Android libSDL port
AppSettingVersion=15
LibSdlVersion=1.2
AppName="GemRB"
AppFullName=net.sourceforge.gemrb
ScreenOrientation=h
InhibitSuspend=n
AppDataDownloadUrl="GemRB data(local)|data.zip"
SdlVideoResize=y
SdlVideoResizeKeepAspect=y
NeedDepthBuffer=n
AppUsesMouse=y
AppNeedsTwoButtonMouse=y
AppNeedsArrowKeys=n
AppNeedsTextInput=y
AppUsesJoystick=y
AppHandlesJoystickSensitivity=n
AppUsesMultitouch=n
NonBlockingSwapBuffers=n
RedefinedKeys="LCTRL c p o e"
AppTouchscreenKeyboardKeysAmount=0
AppTouchscreenKeyboardKeysAmountAutoFire=0
MultiABI=y
AppVersionCode=063
AppVersionName="0.6.3"
CompiledLibraries="sdl_mixer ogg vorbis openal png python"
CustomBuildScript=n
AppCflags='-fexceptions -finline-functions -O2 -DSTATIC_LINK=Yes'
AppLdflags=''
AppSubdirsBuild=''
AppUseCrystaXToolchain=y
AppCmdline='GemRB'
ReadmeText='^You may press "Home" now - the data will be downloaded in background'

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,17 @@
GemRB authors listed in Alphabetical Order
Alyssa Milburn <fuzzie@users.sourceforge.net>
Avenger <avenger_teambg@users.sourceforge.net>
Balrog994 <Balrog994@yahoo.com>
Brian Tanedo <behteh@users.sourceforge.net>
Dark-Star <doc_wagon@users.sourceforge.net>
Divide <divide@users.sourceforge.net>
Edheldil <edheldil@users.sourceforge.net>
GuidoJ <guidoj@users.sourceforge.net>
Jaka Kranjc <lynxlupodian@users.sourceforge.net>
Lotana <lotana@users.sourceforge.net>
Marshall Mattingly III <mattinm@users.sourceforge.net>
Thuy Nguyen <ndthuy@users.sourceforge.net>
Tom Prince <tom.prince@ualberta.net>
Willem Jan Palenstijn <wjpalenstijn@users.sourceforge.net>
Zefklop <zefklop@users.sourceforge.net>

View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
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 Program or any portion
of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
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 Program, 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 Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) 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; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, 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 executable. However, as a
special exception, the source code 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.
If distribution of executable or 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 counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program 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.
5. 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 Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program 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 to
this License.
7. 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 Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program 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 Program.
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.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program 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.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies 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 Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, 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
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. 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 PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
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 program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,71 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
// GemRB.cpp : Defines the entry point for the application.
#include "win32def.h" // logging
#include <cstdio>
#include "Interface.h"
//this supposed to convince SDL to work on OS/X
//WARNING: commenting this out will cause SDL 1.2.x to crash
#ifdef __APPLE_CC__ // we need startup SDL here
#include <SDL.h>
#endif
#ifdef ANDROID
#include <SDL.h>
#include "audio.h"
// pause audio playing if app goes in background
static void appPutToBackground()
{
core->GetAudioDrv()->Pause();
}
// resume audio playing if app return to foreground
static void appPutToForeground()
{
core->GetAudioDrv()->Resume();
}
#endif
int main(int argc, char* argv[])
{
#ifdef ANDROID
SDL_ANDROID_SetApplicationPutToBackgroundCallback(&appPutToBackground, &appPutToForeground);
#endif
Interface::SanityCheck(VERSION_GEMRB);
core = new Interface( argc, argv );
if (core->Init() == GEM_ERROR) {
delete( core );
printf("Press enter to continue...");
textcolor(DEFAULT);
getc(stdin);
return -1;
}
core->Main();
delete( core );
textcolor(DEFAULT);
return 0;
}

View File

@@ -0,0 +1,381 @@
GemRB git (2bd6d0e):
New features:
-
Improved features:
-
- bugfixes
Applied patches:
GemRB V0.6.3 git (2010-11-21)
New features:
- IWD:HoW is now completable!
- casting sounds and footsteps
- autodetection of secret doors, detect illusions
- basic bardsong support and selective magic resistance (bg2-style)
- proper store economics, ergonomics and dragging
- custom blood color (creature-dependant)
- new actions, iwd effects and triggers
- Importing a SoA game into ToB
Improved features:
- actor selection and action bar (for summons and illusions too!)
- door bashing and traps
- loading screens, ambushes, worldmap
- sparkles, panic and other effects
- actions, dialogs, object matching
- personal items support (swap/equip/remove)
- bugfixes
Applied patches:
iwd regression fix from Eggert Jón Magnússon
GemRB V0.6.2 (2010-08-21):
New features:
- a basic SDL_mixer plugin for faster, but lower-quality audio
- dualclassing for bg1 and iwd
- new triggers, actions, infravision
- feet circle flickering on portrait hover, coloration in dialog
- wisdom xp bonus (pst)
Improved features:
- actions, triggers, object matching
- item loading and ability selection, inventory
- projectiles, effects, subtitles, verbal constants
- the core and guiscript design was cleaned up in many places
- bugfixes
Applied patches:
backslash check patch from anthiste
bg1 character generation patch from Maighstir
a crosscompiling fix from F.Fischer
GemRB V0.6.1 (2010-06-16):
New features:
- a minimal dataset
- reputation penalties on death or injury
- casting level bonus/malus (wild mages, clerics)
- tinting for different times of the day and weather effects
- a BI(n)K player plugin for the IWD2 movies
- new actions, turn undead
Improved features:
- the internal design was cleaned up in many places
- game saving, modal actions, combat, effects, spawns
- magic missiles are now drawn properly
- various guiscripts (no more flickering!)
- bugfixes
Applied patches:
two patches from Brendan Molloy
GemRB V0.6.0 (2009-11-03):
New features:
- BG1 and IWD are roughly completable!
- levelup support for bg1 and iwd, dream cutscenes in ToB
- more hardcoded projectiles and avatar animations
- evasion, backstabbing and basic hide in shadows
- compatibility with the widescreen mod (unreleased) allows for multiple
custom resolutions
- contingency and sequencer spells, beginnings of wild magic support
Improved features:
- combat, travelling and feedback
- better spellcasting timing
- actions, effects and triggers
- various guiscripts
- bugfixes
Applied patches:
a few patches from nugrud for how/totl support
GemRB V0.5.1 (2009-08-27):
New features:
- BG2:SoA is roughly completable!
- almost all missing IE's hardcoded projectiles, spell hit projectiles,
projectile trails, projectile failure (spell), projectile effectlists
- auto-reloading of projectile weapons in case the ammo stack runs out
- damage resistance
- sorcerer style spellbooks, reading of iwd2 spellbooks
- target following to other areas
- the null sound plugin is now always loaded last by default; for old
installs see the provided configuration example (DelayPlugin)
- intelligence and wisdom dictated lore bonus
- a GUIEnhancements config option (on by default) that enables a few
extra controls (for convenience and larger mods)
- PST death counters (don't anger the Lady)
- initial support for targetting by portrait
Improved features:
- actions, effects and triggers
- pathfinding, feet circles, fog of war and worldmap travel
- combat and spellcasting (especially summoning)
- projectiles
- config and default table value parsing is smarter about spaces
- various guiscripts
- bugfixes
Applied patches:
various patches from nugrud for bg2 gui enhancements
fix compilation (with cmake) on OS X, by hanicka
GemRB V0.5.0 (2009-06-25):
New features:
- SoA, ToB and PST are roughly playable beyond their first levels
- combat: dual-wielding, APR, proficiency and style boni, dexterity
bonus, initiatitive and speed factor, individual combat rounds
- many IE's hardcoded projectiles and support for projectile sounds
- IWD2 GUI now works after chargen too
- bg2 chargen now levels to the correct level
- summoned and charmed creatures can be ordered around
- actor tooltips (name and injury status)
- running, initial variable values and portal animations in PST
- hardcoded monk bonuses
Improved features:
- dialog, actions and triggers
- combat mechanics, animation, feedback, ranged combat
- matters of time and matter
- levelup, dual classing, multiclass handling
- focus: scrolling while paused is now possible
- animations (projectile, creature)
- pathfinding
- area music restarts when there's no music playing
- disarm trap checks skills
- various guiscripts
- bugfixes
Applied patches:
#2802190 jbmetz (improve the rpm spec handling)
#2802437 danamin (patch bomb sanitizing bg1 chargen + bg2 code share)
GemRB V0.4.0 (2009-05-25):
New features:
- level up support in bg2
- basic party reordering
- bashing of containers and doors
- persistent area effects (cloudkill, stinking cloud, web, etc.)
- item amount window for stack splitting (shift+click or doubleclick)
- depletion of item charges
- opcodes: disable spellcasting, cutscene2 (pocketplane travel), knock,
clear air, polymorph, disable button
- dynamic scrollbar creation (display of more than 10 kits, 24 spells)
- portrait effect icons
- item ability selection
- character customization
Improved features:
- fog of war
- party reformation
- iwd and how guiscripts have been merged
- traps
- pst dialogs
- regeneration, hp bonuses, healing
- animations and projectiles
- rewritten MVE player
- ranged combat
- various guiscripts
- bugfixes
Applied patches:
#2770564 Whiteclone (pst options window bug)
numerous patches from mattinm finishing the level up support
a few patches from ape fixing and extending iwd
#2579743 jbmetz added RPM spec files
GemRB V0.3.2 (2009-02-16):
New features:
- default cancel button, bound to the escape key
- tooltip animations and a shortcut (tab)
- wrapper python classes that simplified the GUIScripts
- trap detection, removal, triggering, xp, feedback, autopause
- modal effects
- proper xp award for dual- and multiclass actors
- double click (used in the map window)
- click-and-hold incrementing/decrementing
- accumulate kill statistics
- characters can move while the map is open
- sound on item equip
- arbitrary feat prerequisites in iwd2
- hard pause for all games (originally a ToB feature); triggered with 'h'
- extended night areas (originally a bg2 feature)
Improved features:
- walking animation timing
- formations (arbitrary sizes, rotation, cursor)
- ppc support (no more crashes)
- container/door/infopoint cursor and highlight handling
- various guiscripts
- cmake build system (now really works on *nix)
- magic item exclusion
- stores and bags
- fixed attack loop when target dies
- bugfixes
Applied patches:
#2159734 Zefklop (Mouse activity during movies)
#2243323 Zefklop (correct Openal cleanup)
#2263333 Whiteclone (bg1 guiinv)
#2380891 Amikrop (iwd1 guicommonwindows)
GemRB V0.3.1 (2008-09-25):
New features:
- mouse scroll support
- starting tob inventory
- character import in iwd and how
- spritecover for area animations
- proper XP bonus for thieving and learning spells
Improved features:
- gcc 4.3 compatibility
- PST bestiary
- bg2 and tob game modes have been merged
- bg2 and iwd2 character generation was simplified and improved
- stricter dualclassing prerequisites
- the cmake build system is available for other platforms too
- pathfinding
- starting time is now at day 0
- less memory leaks
- bugfixes
GemRB V0.3.0 (2008-02-17):
New features:
- TLK override handling (custom biographies and map notes)
- weapon immunities
- party AI
- expansion playmode
- more actions, triggers and effects
- loading of projectile explosion animations
- kit information window
- optional CMake build system (windows only)
Improved features:
- sound (now perfect!)
- character generation
- opcodes
- character record window
- pathfinding
- tooltip delay
- bugfixes
GemRB V0.2.9 (2007-07-06):
New features:
- thieving
- tracking
- graphical feedback (color pulse, blur, mirror image, vvc overlays etc)
- projectiles
- spell casting
- item use
- challenge rating calculation
Improved features:
- more opcodes
- bugfixes
- shop/inventory gui
GemRB V0.2.8 (2006-12-24):
New features:
- equipment is rendered both on paperdoll and avatar
- weather (snow/rain) is now rendered
Improved features:
- action menus
- game scripting (actions/triggers)
GemRB V0.2.7 (2006-08-30):
New features:
- large animations
- worldmap travel
- dialogue portraits
- translucent shadows option
- personal space of actors
- combat
- many new effects
- overlay animation
Improved features:
- Script fixes
- Action menus
- TextScreen
- doors
- animated overlays
- new actions
GemRB V0.2.6 (2005-12-06):
New features:
- Effects are in a different plugin
- DoxyGen docs
- Wallgroup covers
- Door triggers
- Action menus (talk/attack)
- party/protagonist death handled
Improved features:
- Textscreen graphic fixed
- script workflow
- compilation and running on different systems (MacOSX, PPC Linux)
- various leaks/instabilities fixed
- Saving games
- inventory screens in many games
GemRB V0.2.5 (2005-08-22):
New features:
- Save game
- Effects are now loaded
- Equipping effects in items
- Spawn points in areas
- Textscreen (scrolled text between chapters)
Improved features:
- GameScript is now much more reliable: Action override works, triggers fire once and then get cleared
- fully working Store screen
- fixed padding of message window rows (in dialogs)
GemRB V0.2.4 (2005-05-29):
New features:
- Store dialogs (Temple, Inn, Container, Tavern, Store)
- Fog of war with line of sight
- Doors block path and line of sight
- Window frames at higher resolutions
- Animated buttons (PST portraits, Donation window)
- Store opens when appropriate
- Containers
Improved features:
- Fixed dialogs
- new GUIScript functions with documentation
- Fog of war/door/store related gamescript actions
- fixed object distance and area variable handling in gamescript
- other new gamescript actions/triggers
- Implemented PCs fidget animations
Documentation:
- Introduction to writing GUIScript scripts
GemRB v0.2.3 (2005-02-13):
New features:
- GUI for most of the games, especially interactive Inventory and Spellbook
- Map and WorldMap
- Load screen interstitials with progress bar
- Spell and item cache to speed up object management
- Added gamescript actions/triggers
- Selection of spells during character generation
- First attempt on effects code
- First attempt on Fog-Of-War
- Tooltips
- Overhead text
- Ambient sounds
- Volume control
- Manual page gemrb(1)
- Documentation for GemRB Python API and our custom override files
Improved features:
- Character generation
- GUI
- Build infrastructure on Linux and Un*x systems
- Progress towards portability to 64 bit and big endian machines
- Many bugfixes and new bugs as well ;-)
- Shortened version numbers
- Simplified user configuration, game specific settings are now
in gemrb/override dir

View File

@@ -0,0 +1,77 @@
Introduction
------------
GemRB (Game Engine Made with preRendered Background) is a "port"
(actually a new implementation) of the original Infinity Engine (the one
of Baldur's Gate, Icewind Dale, Planescape: Torment, ...) to
Linux/Unix, MacOS X and Windows with some enhancements. Would you like to
create a game like Baldur's Gate?
It means that you either need some of the original game's data
somewhere on your harddisk, or you can try to use the data from the
Dragonlance Total Conversion project - see the link below.
The original game data has to be installed on a windows
partition and mounted to your Linux/Unix filesystem, installed on
windows and then copied to your filesystem, installed with WINE or
extracted manually from the CDs using the tool `unshield'.
What little documentation exists is mostly in gemrb/docs/en/ and
subdirectories, the gemrb.6 man page and this file.
Supported platforms
-------------------
Supported (i.e. we got reports about successfully running GemRB) systems:
Linux x86, x86-64, ppc
FreeBSD x86
MS Windows (98, XP or Vista)
various Macintosh systems (even pre x86) also should work ...
some smart phones (Symbian, Android)
some consoles (OpenPandora, Dingoo)
some exotic OSes (ReactOS, SyllableOS, Haiku)
Requirements
------------
See the INSTALL file.
Contacts
--------
Our homepage:
http://gemrb.sourceforge.net
Our project at sourceforge.net:
http://sourceforge.net/projects/gemrb
New GemRB forum (users):
http://forums.gibberlings3.net/index.php?showforum=91
IRC channel:
The best way to talk with us is by joining the #GemRB channel
on the FreeNode IRC network. There's somebody to talk with most of
the time.
Useful links
------------
IESDP, documentation for the Infinity Engine file formats and more:
http://iesdp.gibberlings3.net/
Near Infinity, Java viewer and editor for data files of the original games:
http://www.idi.ntnu.no/~joh/ni/index.html
DLTCEP, MS Windows viewer and editor for data files of the original games:
http://forums.gibberlings3.net/index.php?showforum=137
Unshield, extractor for .CAB files created by InstallShield
http://synce.sourceforge.net/synce/unshield.php
Valgrind, a powerful developer tool to fix programmer errors (leaks, buffer overflows and all the like that happen)
http://valgrind.org/
SDL, Simple Directmedia Layer, the graphical library used for GemRB
http://www.libsdl.org/index.php
OpenAL, Cross-Platform 3D audio libraries, the sound library used for GemRB
http://openal.org/
WINE, Open Source implementation of the Windows API, useful for installing the games
http://www.winehq.org

View File

@@ -0,0 +1,101 @@
Scripts:
1. (DONE?) ToB specific actions/triggers, like pocketplane (so ToB will work)
2. (PARTLY) Properly detect the play mode (sp/mp, normal/extended)
Strings:
1. fix (finish implementation of) talk table override
2. implement feature: "<GENDER?stref1:strref2>" (or even more ambitious stat specific strref tokens)
Combat:
1. (PARTLY) fix combat round timings
2. implement customisable combat calculation, it should be general enough to
simulate all games, without any hardcoded parts
Items:
1. (DONE-almost) Break items, count charges
2. (PARTLY) Implement switching weapon abilities
3. (DONE-almost) Implement item usage (similar to spells)
Effects:
1. (DONE-almost) Implement common effects
2. (PARTLY) Implement IWD2 effects
3. (DONE-almost) Implement TOB effects
4. (PARTLY) Implement PST effects
5. (DONE-almost) Implement area/non-living affecting effects
Area:
1. (PARTLY) Don't load scripts for pile items? (research when a script is unused)
2. (DONE) Create real streaming ambients (do not preload them, just use them when needed)
3. (DONE) in pathfinder, calculate with the actor's feet circle size (npc blocking still needed)
4. (DONE-almost) fix overlaid tiles - bug #1623839
Store:
1. Store caching (especially bags)
Animation:
1. (PARTLY) fix char animation sequences
2. stanceID is still fuzzy. Fix it. (FIXED?)
3. (PARTLY) Implement projectile animations (area, cone, fragments, hardcoded features)
Actor:
1. (PARTLY) Use the character sheet (Actor.cpp) itself to store attributes of the character
during character generation.
Benefits: data is already stored in the destination, data constraints and relations
are easily implemented.
How to: replace GemRB.SetVar with GemRB.SetPlayerStat. Don't forget to create
the character first. - see bg1 chargen for a complete solution
2. Move position of actor (and ground circle) to the center of a searchmap cell
3. (PARTLY) Actually handle the iwd2 spelllists. Exporter is still needed.
Game GUI:
1. (PARTLY) implement class based (but customisable) action button bar. Generally port
the IWD2 system to all engines
2. implement grabbing mouse pointer by a control to fix dragging of PST Float menu window
3. (PARTLY) Fix drop capitals (initials) Calculate text height/width correctly, display
it correctly too.
4. (PARTLY) Fix unwanted screen shake (especially when on bottom of area)
5. (DONE-almost) Level up code, this should be written mostly in GuiScript!!!
6. (PARTLY) Contingency, spell trigger setup windows
7. (PARTLY) Customize windows (part of character record window)
General:
1. The Cache and Variables classes could be rewritten to incorporate the release
function more smoothly (use templates?)
2. various directories (GemRB override, game override ...) should be resolved
right after loading config files and remain static afterwards. Maybe define
some PATH variable describing all the directories searched for files
3. valgrind reports a big heap of unreleased python objects
4. Implement at least all the options accessible from the GUI options setup,
rewrite baldur|torment|icewind.ini
Graphics:
1. use scaling in Video::SpriteScaleDown() instead of in Video::GetPreview()
and in BMPImporter
2. move SDLVideoDriver sprite functions to their own file, rename them to
SpriteIsPixelTransparent etc.
3. (PARTLY) Add PNG support? (still image done)
4. Fog of war: fully visible squares with one corner neighbour invisible need alpha of the adjacent corner to the invisible square tuned down (uh, i hope it is clear what to do, look for artifacts in the fog of war edge)
Sound:
1. valgrind reports invalid memory access due to Unqueueing buffers and using
them in another thread (openal weirdness?)
2. (PARTLY) sounds get sometimes distorted, might be connected to problem #1
3. (PARTLY) Separate OpenAL interface from ACM loader and MVE player
4. implement sound handles so looping, moving sound, stopping sound is possible
5. fix sound settings (currently the volumes get reset on area change, for example)
6. implement and use as much from EAX (echo, damping, etc) as possible
Release:
2. Get a sample game with some free license which could be distributed
with GemRB.
Documentation:
1. (PARTLY) make tool to scan source files for those with non-standard
copyright notices
2. Add Doxygen doc comments to more objects
3. Write GemRB overview, structure and high-level flow docs
Community:
2. Move this todo to bug/task tracker at Sourceforge :-)

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "ActorMgr.h"
ActorMgr::ActorMgr(void)
{
}
ActorMgr::~ActorMgr(void)
{
}

View File

@@ -0,0 +1,41 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef ACTORMGR_H
#define ACTORMGR_H
#include "Plugin.h"
#include "Scriptable/Actor.h"
#include "System/DataStream.h"
class GEM_EXPORT ActorMgr : public Plugin {
public:
ActorMgr(void);
virtual ~ActorMgr(void);
virtual bool Open(DataStream* stream, bool autoFree = true) = 0;
virtual Actor* GetActor(unsigned char is_in_party) = 0;
//returns saved size, updates internal offsets before save
virtual int GetStoredFileSize(Actor *ac) = 0;
//saves file
virtual int PutActor(DataStream *stream, Actor *actor, bool chr=false) = 0;
};
#endif

View File

@@ -0,0 +1,36 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2004 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Ambient.h"
Ambient::Ambient()
{
}
Ambient::~Ambient()
{
unsigned int i=sounds.size();
while(i--) {
free(sounds[i]);
}
}
void Ambient::setActive() { flags |= IE_AMBI_ENABLED; }
void Ambient::setInactive() { flags &= ~IE_AMBI_ENABLED; }

View File

@@ -0,0 +1,77 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2004 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef AMBIENT_H
#define AMBIENT_H
#include "exports.h"
#include "globals.h"
#include "ie_types.h"
#include <bitset>
#include <string>
#include <vector>
#define IE_AMBI_ENABLED 1
#define IE_AMBI_POINT 2
#define IE_AMBI_MAIN 4
#define IE_AMBI_AREA 8
class GEM_EXPORT Ambient {
public:
Ambient();
~Ambient();
/* there is a good reason to have these in the header:
* they are automatically inlined, so we have
* no roundtrips and no overhead for accessors --Divide */
const char *getName() const { return name; }
const Point &getOrigin() const { return origin; }
ieWord getRadius() const { return radius; }
ieWord getHeight() const { return height; }
ieWord getGain() const { return gain; }
char *getSound(ieDword i) const
{
if(i<sounds.size()) return sounds[i];
return NULL;
}
ieDword getInterval() const { return interval; }
ieDword getPerset() const { return perset; }
ieDword getAppearance() const { return appearance; }
ieDword getFlags() const { return flags; }
void setActive();
void setInactive();
public:
char name[32];
Point origin;
ieWord radius;
ieWord height;
ieWord gain; // percent
std::vector<char *> sounds;
ieDword interval; // no pauses if zero
ieDword perset;
ieDword appearance;
ieDword flags;
};
#endif

View File

@@ -0,0 +1,62 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2004 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "AmbientMgr.h"
#include "Ambient.h"
AmbientMgr::AmbientMgr()
{
}
AmbientMgr::~AmbientMgr()
{
reset();
}
void AmbientMgr::activate(const std::string &name)
{
for (std::vector<Ambient *>::iterator it = ambients.begin(); it != ambients.end(); ++it) {
if ((*it) -> getName() == name) {
(*it) -> setActive();
break;
}
}
}
void AmbientMgr::deactivate(const std::string &name)
{
for (std::vector<Ambient *>::iterator it = ambients.begin(); it != ambients.end(); ++it) {
if ((*it) -> getName() == name) {
(*it) -> setInactive();
break;
}
}
}
bool AmbientMgr::isActive(const std::string &name) const
{
for (std::vector<Ambient *>::const_iterator it = ambients.begin(); it != ambients.end(); ++it) {
if ((*it) -> getName() == name) {
return (*it) -> getFlags() & IE_AMBI_ENABLED;
}
}
return false;
}

View File

@@ -0,0 +1,48 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2004 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef AMBIENTMGR_H
#define AMBIENTMGR_H
#include "exports.h"
#include "win32def.h"
#include <string>
#include <vector>
class Ambient;
class GEM_EXPORT AmbientMgr {
public:
AmbientMgr();
virtual ~AmbientMgr();
virtual void reset() { ambients = std::vector<Ambient *> (); }
virtual void setAmbients(const std::vector<Ambient *> &a) { reset(); ambients = a; activate(); }
virtual void activate(const std::string &name);
virtual void activate() { active = true; } // hard play ;-)
virtual void deactivate(const std::string &name);
virtual void deactivate() { active = false; } // hard stop
virtual bool isActive(const std::string &name) const;
protected:
std::vector<Ambient *> ambients;
bool active;
};
#endif

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef ANIMSTRUCTURES_H
#define ANIMSTRUCTURES_H
struct CycleEntry {
ieWord FramesCount;
ieWord FirstFrame;
};
#endif

View File

@@ -0,0 +1,261 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Animation.h"
#include "win32def.h"
#include "Game.h"
#include "Interface.h"
#include "Map.h"
#include "Video.h"
Animation::Animation(int count)
{
frames = (Sprite2D **) calloc(count, sizeof(Sprite2D *));
indicesCount = count;
if (count) {
pos = rand() % count;
}
else {
pos = 0;
}
starttime = 0;
x = 0;
y = 0;
Flags = A_ANI_ACTIVE;
fps = 15;
endReached = false;
//behaviour flags
playReversed = false;
gameAnimation = false;
}
Animation::~Animation(void)
{
Video *video = core->GetVideoDriver();
for (unsigned int i = 0; i < indicesCount; i++) {
video->FreeSprite( frames[i] );
}
free(frames);
}
void Animation::SetPos(unsigned int index)
{
if (index<indicesCount) {
pos=index;
}
starttime = 0;
endReached = false;
}
/* when adding NULL, it means we already added a frame of index */
void Animation::AddFrame(Sprite2D* frame, unsigned int index)
{
if (index>=indicesCount) {
printf("You tried to write past a buffer in animation, BAD!\n");
abort();
}
core->GetVideoDriver()->FreeSprite(frames[index]);
frames[index]=frame;
int x = -frame->XPos;
int y = -frame->YPos;
int w = frame->Width;
int h = frame->Height;
if (x < animArea.x) {
animArea.w += (animArea.x - x);
animArea.x = x;
}
if (y < animArea.y) {
animArea.h += (animArea.y - y);
animArea.y = y;
}
if (x+w > animArea.x+animArea.w) {
animArea.w = x+w-animArea.x;
}
if (y+h > animArea.y+animArea.h) {
animArea.h = y+h-animArea.y;
}
}
unsigned int Animation::GetCurrentFrame() const
{
if (playReversed)
return indicesCount-pos-1;
return pos;
}
Sprite2D* Animation::LastFrame(void)
{
if (!Flags&A_ANI_ACTIVE) {
printf("Frame fetched while animation is inactive!\n");
return NULL;
}
if (gameAnimation) {
starttime = core->GetGame()->Ticks;
} else {
GetTime( starttime );
}
Sprite2D* ret;
if (playReversed)
ret = frames[indicesCount-pos-1];
else
ret = frames[pos];
return ret;
}
Sprite2D* Animation::NextFrame(void)
{
if (!Flags&A_ANI_ACTIVE) {
printf("Frame fetched while animation is inactive!\n");
return NULL;
}
if (starttime == 0) {
if (gameAnimation) {
starttime = core->GetGame()->Ticks;
} else {
GetTime( starttime );
}
}
Sprite2D* ret;
if (playReversed)
ret = frames[indicesCount-pos-1];
else
ret = frames[pos];
if (endReached && (Flags&A_ANI_PLAYONCE) )
return ret;
unsigned long time;
if (gameAnimation) {
time = core->GetGame()->Ticks;
} else {
GetTime(time);
}
//it could be that we skip more than one frame in case of slow rendering
//large, composite animations (dragons, multi-part area anims) require synchronisation
if (( time - starttime ) >= ( unsigned long ) ( 1000 / fps )) {
int inc = (time-starttime)*fps/1000;
pos += inc;
starttime += inc*1000/fps;
}
if (pos >= indicesCount ) {
if (indicesCount) {
if (Flags&A_ANI_PLAYONCE) {
pos = indicesCount-1;
endReached = true;
} else {
pos = pos%indicesCount;
endReached = false; //looping, there is no end
}
} else {
pos = 0;
endReached = true;
}
starttime = 0;
}
return ret;
}
Sprite2D* Animation::GetSyncedNextFrame(Animation* master)
{
if (!Flags&A_ANI_ACTIVE) {
printf("Frame fetched while animation is inactive!\n");
return NULL;
}
Sprite2D* ret;
if (playReversed)
ret = frames[indicesCount-pos-1];
else
ret = frames[pos];
starttime = master->starttime;
pos = master->pos;
endReached = master->endReached;
return ret;
}
void Animation::release(void)
{
delete this;
}
/** Gets the i-th frame */
Sprite2D* Animation::GetFrame(unsigned int i)
{
if (i >= indicesCount) {
return NULL;
}
return frames[i];
}
void Animation::MirrorAnimation()
{
Video *video = core->GetVideoDriver();
for (size_t i = 0; i < indicesCount; i++) {
Sprite2D * tmp = frames[i];
frames[i] = video->MirrorSpriteHorizontal( tmp, true );
video->FreeSprite(tmp);
}
// flip animArea horizontally as well
animArea.x = -animArea.w - animArea.x;
}
void Animation::MirrorAnimationVert()
{
Video *video = core->GetVideoDriver();
for (size_t i = 0; i < indicesCount; i++) {
Sprite2D * tmp = frames[i];
frames[i] = video->MirrorSpriteVertical( tmp, true );
video->FreeSprite(tmp);
}
// flip animArea vertically as well
// animArea.y = -animArea.h - animArea.y;
}
void Animation::AddAnimArea(Animation* slave)
{
int x = slave->animArea.x;
int y = slave->animArea.y;
int w = slave->animArea.w;
int h = slave->animArea.h;
if (x < animArea.x) {
animArea.w += (animArea.x - x);
animArea.x = x;
}
if (y < animArea.y) {
animArea.h += (animArea.y - y);
animArea.y = y;
}
if (x+w > animArea.x+animArea.w) {
animArea.w = x+w-animArea.x;
}
if (y+h > animArea.y+animArea.h) {
animArea.h = y+h-animArea.y;
}
}

View File

@@ -0,0 +1,72 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef ANIMATION_H
#define ANIMATION_H
#include "RGBAColor.h"
#include "exports.h"
#include "globals.h"
#include "Region.h"
#include "Sprite2D.h"
#include <vector>
class GEM_EXPORT Animation {
private:
Sprite2D **frames;
unsigned int indicesCount;
unsigned long starttime;
public:
bool endReached;
unsigned int pos;
int x, y;
unsigned char fps;
bool playReversed;
bool gameAnimation;
Region animArea;
ieDword Flags;
Animation(int count);
~Animation(void);
void AddFrame(Sprite2D* frame, unsigned int index);
Sprite2D* LastFrame(void);
Sprite2D* NextFrame(void);
Sprite2D* GetSyncedNextFrame(Animation* master);
void release(void);
/** Gets the i-th frame */
Sprite2D* GetFrame(unsigned int i);
/** Mirrors all the frames vertically */
void MirrorAnimationVert();
/** Mirrors all the frames horizontally */
void MirrorAnimation();
/** sets frame index */
void SetPos(unsigned int index);
/** Sets ScriptName for area animation */
void SetScriptName(const char *name);
/** returns the frame count */
unsigned int GetFrameCount() const { return indicesCount; }
/** returns the current frame's index */
unsigned int GetCurrentFrame() const;
/** add other animation's animarea to self */
void AddAnimArea(Animation* slave);
};
#endif

View File

@@ -0,0 +1,168 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "AnimationFactory.h"
#include "win32def.h"
#include "Interface.h"
#include "Video.h"
AnimationFactory::AnimationFactory(const char* ResRef)
: FactoryObject( ResRef, IE_BAM_CLASS_ID )
{
FLTable = NULL;
FrameData = NULL;
datarefcount = 0;
}
AnimationFactory::~AnimationFactory(void)
{
for (unsigned int i = 0; i < frames.size(); i++) {
core->GetVideoDriver()->FreeSprite( frames[i] );
}
if (FLTable)
free( FLTable);
// FIXME: track down where sprites are being leaked
if (datarefcount) {
fprintf(stderr, "AnimationFactory %s has refcount %d\n", ResRef, datarefcount);
//assert(datarefcount == 0);
}
if (FrameData)
free( FrameData);
}
void AnimationFactory::AddFrame(Sprite2D* frame)
{
frames.push_back( frame );
}
void AnimationFactory::AddCycle(CycleEntry cycle)
{
cycles.push_back( cycle );
}
void AnimationFactory::LoadFLT(unsigned short* buffer, int count)
{
if (FLTable) {
free( FLTable );
}
//FLTable = new unsigned short[count];
FLTable = (unsigned short *) malloc(count * sizeof( unsigned short ) );
memcpy( FLTable, buffer, count * sizeof( unsigned short ) );
}
void AnimationFactory::SetFrameData(unsigned char* FrameData)
{
this->FrameData = FrameData;
}
Animation* AnimationFactory::GetCycle(unsigned char cycle)
{
if (cycle >= cycles.size()) {
return NULL;
}
int ff = cycles[cycle].FirstFrame;
int lf = ff + cycles[cycle].FramesCount;
Animation* anim = new Animation( cycles[cycle].FramesCount );
int c = 0;
for (int i = ff; i < lf; i++) {
frames[FLTable[i]]->acquire();
anim->AddFrame( frames[FLTable[i]], c++ );
}
return anim;
}
/* returns the required frame of the named cycle, cycle defaults to 0 */
Sprite2D* AnimationFactory::GetFrame(unsigned short index, unsigned char cycle) const
{
if (cycle >= cycles.size()) {
return NULL;
}
int ff = cycles[cycle]. FirstFrame, fc = cycles[cycle].FramesCount;
if(index >= fc) {
return NULL;
}
Sprite2D* spr = frames[FLTable[ff+index]];
spr->acquire();
return spr;
}
Sprite2D* AnimationFactory::GetFrameWithoutCycle(unsigned short index) const
{
if(index >= frames.size()) {
return NULL;
}
Sprite2D* spr = frames[index];
spr->acquire();
return spr;
}
Sprite2D* AnimationFactory::GetPaperdollImage(ieDword *Colors,
Sprite2D *&Picture2, unsigned int type) const
{
if (frames.size()<2) {
return NULL;
}
Video* video = core->GetVideoDriver();
Picture2 = video->DuplicateSprite(frames[1]);
if (!Picture2) {
return NULL;
}
if (Colors) {
Palette* palette = Picture2->GetPalette();
palette->SetupPaperdollColours(Colors, type);
Picture2->SetPalette(palette);
palette->Release();
}
Picture2->XPos = (short)frames[1]->XPos;
Picture2->YPos = (short)frames[1]->YPos - 80;
Sprite2D* spr = core->GetVideoDriver()->DuplicateSprite(frames[0]);
if (Colors) {
Palette* palette = spr->GetPalette();
palette->SetupPaperdollColours(Colors, type);
spr->SetPalette(palette);
palette->Release();
}
spr->XPos = (short)frames[0]->XPos;
spr->YPos = (short)frames[0]->YPos;
//don't free pixels, createsprite stores it in spr
return spr;
}
void AnimationFactory::IncDataRefCount()
{
++datarefcount;
}
void AnimationFactory::DecDataRefCount()
{
assert(datarefcount > 0);
--datarefcount;
}

View File

@@ -0,0 +1,58 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef ANIMATIONFACTORY_H
#define ANIMATIONFACTORY_H
#include "exports.h"
#include "globals.h"
#include "Animation.h"
#include "FactoryObject.h"
class GEM_EXPORT AnimationFactory : public FactoryObject {
private:
std::vector< Sprite2D*> frames;
std::vector< CycleEntry> cycles;
unsigned short* FLTable; // Frame Lookup Table
unsigned char* FrameData;
int datarefcount;
public:
AnimationFactory(const char* ResRef);
~AnimationFactory(void);
void AddFrame(Sprite2D* frame);
void AddCycle(CycleEntry cycle);
void LoadFLT(unsigned short* buffer, int count);
void SetFrameData(unsigned char* FrameData);
Animation* GetCycle(unsigned char cycle);
/** No descriptions */
Sprite2D* GetFrame(unsigned short index, unsigned char cycle=0) const;
Sprite2D* GetFrameWithoutCycle(unsigned short index) const;
size_t GetCycleCount() const { return cycles.size(); }
size_t GetFrameCount() const { return frames.size(); }
int GetCycleSize(int idx) const { return cycles[idx].FramesCount; }
Sprite2D* GetPaperdollImage(ieDword *Colors, Sprite2D *&Picture2,
unsigned int type) const;
void IncDataRefCount();
void DecDataRefCount();
};
#endif

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "AnimationMgr.h"
AnimationMgr::AnimationMgr(void)
{
}
AnimationMgr::~AnimationMgr(void)
{
}

View File

@@ -0,0 +1,47 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef ANIMATIONMGR_H
#define ANIMATIONMGR_H
#include "globals.h"
#include "Animation.h"
#include "AnimationFactory.h"
#include "Font.h"
#include "Plugin.h"
class GEM_EXPORT AnimationMgr : public Plugin {
public:
AnimationMgr(void);
virtual ~AnimationMgr(void);
virtual bool Open(DataStream* stream, bool autoFree = true) = 0;
virtual int GetCycleSize(unsigned char Cycle) = 0;
virtual AnimationFactory* GetAnimationFactory(const char* ResRef,
unsigned char mode = IE_NORMAL) = 0;
/** This function will load the Animation as a Font */
virtual Font* GetFont() = 0;
/** Debug Function: Returns the Global Animation Palette as a Sprite2D Object.
If the Global Animation Palette is NULL, returns NULL. */
virtual Sprite2D* GetPalette() = 0;
virtual int GetCycleCount() = 0;
};
#endif

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "ArchiveImporter.h"
ArchiveImporter::ArchiveImporter(void)
{
}
ArchiveImporter::~ArchiveImporter(void)
{
}

View File

@@ -0,0 +1,40 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef ARCHIVEIMPORTER_H
#define ARCHIVEIMPORTER_H
#include "globals.h"
#include "Plugin.h"
class GEM_EXPORT ArchiveImporter : public Plugin {
public:
ArchiveImporter(void);
virtual ~ArchiveImporter(void);
virtual int OpenArchive(const char* filename) = 0;
virtual int CreateArchive(DataStream *stream) = 0;
//decompressing a .sav file similar to CBF
virtual int DecompressSaveGame(DataStream *compressed) = 0;
virtual int AddToSaveGame(DataStream *str, DataStream *uncompressed) = 0;
virtual DataStream* GetStream(unsigned long Resource, unsigned long Type) = 0;
};
#endif

View File

@@ -0,0 +1,35 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003-2004 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Audio.h"
const TypeID Audio::ID = { "Audio" };
Audio::Audio(void)
{
}
Audio::~Audio(void)
{
}
SoundHandle::~SoundHandle()
{
}

View File

@@ -0,0 +1,82 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003-2004 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef AUDIO_H_INCLUDED
#define AUDIO_H_INCLUDED
#include "globals.h"
#include "win32def.h"
#include "Plugin.h"
#include "Holder.h"
#define GEM_SND_RELATIVE 1
#define GEM_SND_LOOPING 2
#define GEM_SND_SPEECH IE_STR_SPEECH // 4
#define GEM_SND_VOL_MUSIC 1
#define GEM_SND_VOL_AMBIENTS 2
class AmbientMgr;
class SoundMgr;
class GEM_EXPORT SoundHandle : public Held<SoundHandle> {
public:
virtual bool Playing() = 0;
virtual void SetPos(int XPos, int YPos) = 0;
virtual void Stop() = 0;
virtual void StopLooping() = 0;
virtual ~SoundHandle();
};
class GEM_EXPORT Audio : public Plugin {
public:
static const TypeID ID;
public:
Audio(void);
virtual ~Audio();
virtual bool Init(void) = 0;
virtual Holder<SoundHandle> Play(const char* ResRef, int XPos, int YPos, unsigned int flags = 0, unsigned int *length = 0) = 0;
virtual Holder<SoundHandle> Play(const char* ResRef, unsigned int *length = 0) { return Play(ResRef, 0, 0, GEM_SND_RELATIVE, length); }
virtual bool IsSpeaking() = 0;
virtual AmbientMgr* GetAmbientMgr() { return ambim; }
virtual void UpdateVolume(unsigned int flags = GEM_SND_VOL_MUSIC | GEM_SND_VOL_AMBIENTS) = 0;
virtual bool CanPlay() = 0;
virtual void ResetMusics() = 0;
virtual bool Play() = 0;
virtual bool Stop() = 0;
virtual bool Pause() = 0;
virtual bool Resume() = 0;
virtual int CreateStream(Holder<SoundMgr>) = 0;
virtual void UpdateListenerPos(int XPos, int YPos ) = 0;
virtual void GetListenerPos(int &XPos, int &YPos ) = 0;
virtual bool ReleaseStream(int stream, bool HardStop=false ) = 0;
virtual int SetupNewStream( ieWord x, ieWord y, ieWord z,
ieWord gain, bool point, bool Ambient) = 0;
virtual int QueueAmbient(int stream, const char* sound) = 0;
virtual void SetAmbientStreamVolume(int stream, int volume) = 0;
virtual void QueueBuffer(int stream, unsigned short bits,
int channels, short* memory, int size, int samplerate) = 0;
protected:
AmbientMgr* ambim;
};
#endif // AUDIO_H_INCLUDED

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2007 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "Bitmap.h"
Bitmap::Bitmap(unsigned int w, unsigned int h)
: height(h), width(w), data(new unsigned char[height*width])
{
}
Bitmap::~Bitmap()
{
delete[] data;
}

View File

@@ -0,0 +1,55 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2007 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef BITMAP_H
#define BITMAP_H
#include "exports.h"
class GEM_EXPORT Bitmap {
public:
Bitmap(unsigned int height, unsigned int width);
~Bitmap();
unsigned char GetAt(unsigned int x, unsigned int y) const
{
if (x >= width || y >= height)
return 0;
return data[width*y+x];
}
void SetAt(unsigned int x, unsigned int y, unsigned char idx)
{
if (x >= width || y >= height)
return;
data[width*y+x] = idx;
}
unsigned int GetHeight() const
{
return height;
}
unsigned int GetWidth() const
{
return width;
}
private:
unsigned int height, width;
unsigned char *data;
};
#endif

View File

@@ -0,0 +1,49 @@
ADD_DEFINITIONS(-DGEM_BUILD_DLL)
FILE(GLOB gemrb_core_LIB_SRCS "*.cpp"
GameScript/Actions.cpp
GameScript/GSUtils.cpp
GameScript/GameScript.cpp
GameScript/Matching.cpp
GameScript/Objects.cpp
GameScript/Triggers.cpp
GUI/Button.cpp
GUI/Console.cpp
GUI/Control.cpp
GUI/EventMgr.cpp
GUI/GameControl.cpp
GUI/Label.cpp
GUI/MapControl.cpp
GUI/Progressbar.cpp
GUI/ScrollBar.cpp
GUI/Slider.cpp
GUI/TextArea.cpp
GUI/TextEdit.cpp
GUI/Window.cpp
GUI/WorldMapControl.cpp
Scriptable/Actor.cpp
Scriptable/ActorBlock.cpp
Scriptable/PCStatStruct.cpp
System/CachedFileStream.cpp
System/DataStream.cpp
System/FileStream.cpp
System/MemoryStream.cpp
System/VFS.cpp
System/snprintf.cpp
)
if (STATIC_LINK)
ADD_LIBRARY(gemrb_core STATIC ${gemrb_core_LIB_SRCS})
else (STATIC_LINK)
ADD_LIBRARY(gemrb_core SHARED ${gemrb_core_LIB_SRCS})
IF(WIN32)
INSTALL(TARGETS gemrb_core RUNTIME DESTINATION ${LIB_DIR})
ELSE(WIN32)
INSTALL(TARGETS gemrb_core LIBRARY DESTINATION ${LIB_DIR})
ENDIF(WIN32)
endif (STATIC_LINK)
SET_TARGET_PROPERTIES(gemrb_core PROPERTIES
COMPILE_DEFINITIONS
"PLUGINDIR=\"${PLUGIN_DIR}\";DATADIR=\"${DATA_DIR}\";SYSCONFDIR=\"${SYSCONF_DIR}\""
)

View File

@@ -0,0 +1,311 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Cache.h"
#include <ctype.h>
// private inlines
inline unsigned int Cache::MyHashKey(const char* key) const
{
int nHash = tolower(key[0]);
for (int i=1;(i<KEYSIZE) && key[i];i++) {
nHash = (nHash << 5) ^ tolower(key[i]);
}
return nHash % m_nHashTableSize;
}
Cache::Cache(int nBlockSize, int nHashTableSize)
{
assert( nBlockSize > 0 );
assert( nHashTableSize > 16 );
m_pHashTable = NULL;
m_nHashTableSize = nHashTableSize; // default size
m_nCount = 0;
m_pFreeList = NULL;
m_pBlocks = NULL;
m_nBlockSize = nBlockSize;
}
void Cache::InitHashTable(unsigned int nHashSize, bool bAllocNow)
//Used to force allocation of a hash table or to override the default
//hash table size of (which is fairly small)
{
assert( m_nCount == 0 );
assert( nHashSize > 16 );
if (m_pHashTable != NULL) {
// free hash table
free( m_pHashTable);
m_pHashTable = NULL;
}
if (bAllocNow) {
m_pHashTable = (Cache::MyAssoc **) malloc( sizeof( Cache::MyAssoc * ) * nHashSize );
memset( m_pHashTable, 0, sizeof( Cache::MyAssoc * ) * nHashSize );
}
m_nHashTableSize = nHashSize;
}
void Cache::RemoveAll(ReleaseFun fun)
{
if (m_pHashTable) {
for (unsigned int nHash = 0; nHash < m_nHashTableSize; nHash++)
{
MyAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
pAssoc = pAssoc->pNext)
{
if (fun)
fun(pAssoc->data);
pAssoc->MyAssoc::~MyAssoc();
}
}
// free hash table
free( m_pHashTable );
m_pHashTable = NULL;
}
m_nCount = 0;
m_pFreeList = NULL;
// free memory blocks
MemBlock* p = m_pBlocks;
while (p != NULL) {
MemBlock* pNext = p->pNext;
free( p );
p = pNext;
}
m_pBlocks = NULL;
}
Cache::~Cache()
{
RemoveAll(NULL);
}
Cache::MyAssoc* Cache::NewAssoc()
{
if (m_pFreeList == NULL) {
// add another block
Cache::MemBlock* newBlock = ( Cache::MemBlock* ) malloc(m_nBlockSize * sizeof( Cache::MyAssoc ) + sizeof( Cache::MemBlock ));
assert( newBlock != NULL ); // we must have something
newBlock->pNext = m_pBlocks;
m_pBlocks = newBlock;
// chain them into free list
Cache::MyAssoc* pAssoc = ( Cache::MyAssoc* )
( newBlock + 1 );
for (int i = 0; i < m_nBlockSize; i++) {
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc++;
}
}
Cache::MyAssoc* pAssoc = m_pFreeList;
m_pFreeList = m_pFreeList->pNext;
m_nCount++;
assert( m_nCount > 0 ); // make sure we don't overflow
#ifdef _DEBUG
pAssoc->key[0] = 0;
pAssoc->data = 0;
#endif
pAssoc->nRefCount=1;
return pAssoc;
}
void Cache::FreeAssoc(Cache::MyAssoc* pAssoc)
{
if(pAssoc->pNext) {
pAssoc->pNext->pPrev=pAssoc->pPrev;
}
*pAssoc->pPrev = pAssoc->pNext;
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
m_nCount--;
assert( m_nCount >= 0 ); // make sure we don't underflow
// if no more elements, cleanup completely
if (m_nCount == 0) {
RemoveAll(NULL);
}
}
Cache::MyAssoc *Cache::GetNextAssoc(Cache::MyAssoc *Position) const
{
if (m_pHashTable == NULL || m_nCount==0) {
return NULL;
}
Cache::MyAssoc* pAssocRet = (Cache::MyAssoc*)Position;
if (pAssocRet == NULL)
{
// find the first association
for (unsigned int nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
break;
return pAssocRet;
}
Cache::MyAssoc* pAssocNext = pAssocRet->pNext;
if (pAssocNext == NULL)
{
// go to next bucket
for (unsigned int nBucket = MyHashKey(pAssocRet->key) + 1;
nBucket < m_nHashTableSize; nBucket++)
if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
break;
}
return pAssocNext;
}
Cache::MyAssoc* Cache::GetAssocAt(const ieResRef key) const
// find association (or return NULL)
{
if (m_pHashTable == NULL) {
return NULL;
}
unsigned int nHash = MyHashKey( key );
// see if it exists
Cache::MyAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash];
pAssoc != NULL;
pAssoc = pAssoc->pNext) {
if (!strnicmp( pAssoc->key, key, KEYSIZE )) {
return pAssoc;
}
}
return NULL;
}
void *Cache::GetResource(const ieResRef key) const
{
Cache::MyAssoc* pAssoc = GetAssocAt( key );
if (pAssoc == NULL) {
return NULL;
} // not in map
pAssoc->nRefCount++;
return pAssoc->data;
}
//returns true if it was successful
bool Cache::SetAt(const ieResRef key, void *rValue)
{
int i;
if (m_pHashTable == NULL) {
InitHashTable( m_nHashTableSize );
}
Cache::MyAssoc* pAssoc=GetAssocAt( key );
if (pAssoc) {
//already exists, but we return true if it is the same
return (pAssoc->data==rValue);
}
// it doesn't exist, add a new Association
pAssoc = NewAssoc();
for (i=0;i<KEYSIZE && key[i];i++) {
pAssoc->key[i]=tolower(key[i]);
}
for (;i<KEYSIZE;i++) {
pAssoc->key[i]=0;
}
pAssoc->data=rValue;
// put into hash table
unsigned int nHash = MyHashKey(pAssoc->key);
pAssoc->pNext = m_pHashTable[nHash];
pAssoc->pPrev = &m_pHashTable[nHash];
if (pAssoc->pNext) {
pAssoc->pNext->pPrev = &pAssoc->pNext;
}
m_pHashTable[nHash] = pAssoc;
return true;
}
int Cache::RefCount(const ieResRef key) const
{
Cache::MyAssoc* pAssoc=GetAssocAt( key );
if (pAssoc) {
return pAssoc->nRefCount;
}
return -1;
}
int Cache::DecRef(void *data, const ieResRef key, bool remove)
{
Cache::MyAssoc* pAssoc;
if (key) {
pAssoc=GetAssocAt( key );
if (pAssoc && (pAssoc->data==data) ) {
if (!pAssoc->nRefCount) {
return -1;
}
--pAssoc->nRefCount;
if (remove && !pAssoc->nRefCount) {
FreeAssoc(pAssoc);
return 0;
}
return pAssoc->nRefCount;
}
return -1;
}
pAssoc=(Cache::MyAssoc *) GetNextAssoc(NULL);
while (pAssoc) {
if (pAssoc->data == data) {
if (!pAssoc->nRefCount) {
return -1;
}
--pAssoc->nRefCount;
if (remove && !pAssoc->nRefCount) {
FreeAssoc(pAssoc);
return 0;
}
return pAssoc->nRefCount;
}
pAssoc=GetNextAssoc(pAssoc);
}
return -1;
}
void Cache::Cleanup()
{
Cache::MyAssoc* pAssoc=(Cache::MyAssoc *) GetNextAssoc(NULL);
while (pAssoc)
{
Cache::MyAssoc* nextAssoc = GetNextAssoc(pAssoc);
if (pAssoc->nRefCount == 0) {
FreeAssoc(pAssoc);
}
pAssoc=nextAssoc;
}
}

View File

@@ -0,0 +1,93 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 |Avenger|
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef CACHE_H
#define CACHE_H
#include "globals.h"
#include "win32def.h"
#define KEYSIZE 8
#ifndef ReleaseFun
typedef void (*ReleaseFun)(void *);
#endif
class Cache
{
protected:
// Association
struct MyAssoc {
MyAssoc* pNext;
MyAssoc** pPrev;
char key[KEYSIZE]; //not ieResRef!
ieDword nRefCount;
void* data;
};
struct MemBlock {
MemBlock* pNext;
};
public:
// Construction
Cache(int nBlockSize = 10, int nHashTableSize = 129);
// Attributes
// number of elements
inline int GetCount() const
{
return m_nCount;
}
inline bool IsEmpty() const
{
return m_nCount==0;
}
// Lookup
void *GetResource(const ieResRef key) const;
// Operations
bool SetAt(const ieResRef key, void *rValue);
// decreases refcount or drops data
//if name is supplied it is faster, it will use rValue to validate the request
int DecRef(void *rValue, const ieResRef name, bool free);
int RefCount(const ieResRef key) const;
void RemoveAll(ReleaseFun fun);//removes all refcounts
void Cleanup(); //removes only zero refcounts
void InitHashTable(unsigned int hashSize, bool bAllocNow = true);
// Implementation
protected:
MyAssoc** m_pHashTable;
unsigned int m_nHashTableSize;
int m_nCount;
MyAssoc* m_pFreeList;
MemBlock* m_pBlocks;
int m_nBlockSize;
Cache::MyAssoc* NewAssoc();
void FreeAssoc(Cache::MyAssoc*);
Cache::MyAssoc* GetAssocAt(const ieResRef) const;
Cache::MyAssoc *GetNextAssoc(Cache::MyAssoc * rNextPosition) const;
unsigned int MyHashKey(const ieResRef) const;
public:
~Cache();
};
#endif //CACHE_H

View File

@@ -0,0 +1,96 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2009 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Calendar.h"
#include "win32def.h"
#include "Interface.h"
#include "TableMgr.h"
#include "Variables.h"
Calendar::Calendar(void)
{
int i;
AutoTable tab("months");
if (!tab) {
monthnamecount=-1;
monthnames = NULL;
days = NULL;
return;
}
monthnamecount = tab->GetRowCount();
monthnames = (int *) malloc(sizeof(int) * monthnamecount);
days = (int *) malloc(sizeof(int) * monthnamecount);
daysinyear=0;
for(i=0;i<monthnamecount;i++) {
days[i]=atoi(tab->QueryField(i,0));
daysinyear+=days[i];
monthnames[i]=atoi(tab->QueryField(i,1));
}
}
Calendar::~Calendar(void)
{
if (monthnames) free(monthnames);
if (days) free(days);
}
void Calendar::GetMonthName(int dayandmonth) const
{
int month=1;
for(int i=0;i<monthnamecount;i++) {
if (dayandmonth<days[i]) {
char *tmp;
core->GetTokenDictionary()->SetAtCopy("DAY", dayandmonth+1);
tmp = core->GetString( monthnames[i] );
core->GetTokenDictionary()->SetAt("MONTHNAME",tmp);
//must not free tmp, SetAt doesn't copy the pointer!
core->GetTokenDictionary()->SetAtCopy("MONTH", month);
return;
}
dayandmonth-=days[i];
//ignoring single days (they are not months)
if (days[i]!=1) month++;
}
}
int Calendar::GetCalendarDay(int date) const
{
int dayandmonth;
int month=1;
if (!daysinyear) return 0;
dayandmonth = date%daysinyear;
for(int i=0;i<monthnamecount;i++) {
if (dayandmonth<days[i]) {
break;
}
dayandmonth-=days[i];
//ignoring single days (they are not months)
if (days[i]!=1) month++;
}
return dayandmonth+1;
}

View File

@@ -0,0 +1,40 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2009 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef CALENDAR_H
#define CALENDAR_H
#include "exports.h"
class GEM_EXPORT Calendar {
private:
int daysinyear;
int monthnamecount;
int *days;
int *monthnames;
public:
Calendar(void);
~Calendar(void);
void GetMonthName(int dayandmonth) const;
int GetCalendarDay(int date) const;
};
#endif

View File

@@ -0,0 +1,33 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "Callback.h"
Callback::~Callback()
{
}
bool Callback::call()
{
return true;
}
bool Callback::call(int)
{
return true;
}

View File

@@ -0,0 +1,35 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef CALLBACK_H
#define CALLBACK_H
#include "exports.h"
#include "Holder.h"
class GEM_EXPORT Callback : public Held<Callback> {
public:
virtual ~Callback();
virtual bool call ();
virtual bool call (int);
};
typedef Holder<Callback> EventHandler;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,231 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef CHARANIMATIONS_H
#define CHARANIMATIONS_H
#include "RGBAColor.h"
#include "exports.h"
#include "Animation.h"
#include "Palette.h"
#include "TableMgr.h"
#include <vector>
#define AV_PREFIX1 0
#define AV_PREFIX2 1
#define AV_PREFIX3 2
#define AV_PREFIX4 3
#define AV_ANIMTYPE 4
#define AV_CIRCLESIZE 5
#define AV_USE_PALETTE 6
#define AV_SIZE 7
#define MAX_ANIMS 19
#define IE_ANI_ATTACK 0
#define IE_ANI_AWAKE 1
#define IE_ANI_CAST 2
#define IE_ANI_CONJURE 3
#define IE_ANI_DAMAGE 4
#define IE_ANI_DIE 5
#define IE_ANI_HEAD_TURN 6
#define IE_ANI_READY 7
#define IE_ANI_SHOOT 8
#define IE_ANI_TWITCH 9
#define IE_ANI_WALK 10
#define IE_ANI_ATTACK_SLASH 11
#define IE_ANI_ATTACK_BACKSLASH 12
#define IE_ANI_ATTACK_JAB 13
#define IE_ANI_EMERGE 14
#define IE_ANI_HIDE 15
#define IE_ANI_RUN 15 //pst has no hide, i hope
#define IE_ANI_SLEEP 16
#define IE_ANI_GET_UP 17
#define IE_ANI_PST_START 18
//BG2, IWD animation types
#define IE_ANI_CODE_MIRROR 0
#define IE_ANI_ONE_FILE 1
#define IE_ANI_FOUR_FILES 2
#define IE_ANI_TWO_FILES 3
#define IE_ANI_CODE_MIRROR_2 4
#define IE_ANI_SIX_FILES_2 5 //MOGR
#define IE_ANI_TWENTYTWO 6
#define IE_ANI_BIRD 7
#define IE_ANI_SIX_FILES 8 //MCAR/MWYV
#define IE_ANI_TWO_FILES_3 9 //iwd animations
#define IE_ANI_TWO_FILES_2 10 //low res bg1 anim
#define IE_ANI_FOUR_FRAMES 11 //wyvern anims
#define IE_ANI_NINE_FRAMES 12 //dragon anims
#define IE_ANI_FRAGMENT 13 //fragment animation
#define IE_ANI_FOUR_FILES_2 14 //METT
#define IE_ANI_CODE_MIRROR_3 15 //MSPS
#define IE_ANI_TWO_FILES_3B 16 //iwd animations (eg. MBBM)
//PST animation types
#define IE_ANI_PST_ANIMATION_1 56 //full animation
#define IE_ANI_PST_GHOST 57 //no orientations
#define IE_ANI_PST_STAND 58 //has orientations
#define IE_ANI_PST_ANIMATION_2 59 //full animation std-->stc
#define IE_ANI_PST_ANIMATION_3 60 //full animation stc-->std
//armour levels
#define IE_ANI_NO_ARMOR 0
#define IE_ANI_LIGHT_ARMOR 1
#define IE_ANI_MEDIUM_ARMOR 2
#define IE_ANI_HEAVY_ARMOR 3
#define IE_ANI_WEAPON_1H 0
#define IE_ANI_WEAPON_2H 1
#define IE_ANI_WEAPON_2W 2
#define IE_ANI_RANGED_BOW 0
#define IE_ANI_RANGED_XBOW 1
#define IE_ANI_RANGED_THROW 2
struct AvatarStruct {
/* entries from avatars.2da */
unsigned int AnimID;
unsigned int PaletteType;
ieResRef Prefixes[4];
unsigned char AnimationType;
unsigned char CircleSize;
char Size;
/* comes from bloodclr.2da */
char BloodColor;
/* resdata.ini entries */
unsigned int WalkScale; /* 1000 / walkscale */
unsigned int RunScale; /* 1000 / runscale */
int Bestiary;
/* comes from walksnd.2da */
ieResRef WalkSound;
ieByte WalkSoundCount;
};
struct EquipResRefData;
class GEM_EXPORT CharAnimations {
private:
Animation** Anims[MAX_ANIMS][MAX_ORIENT];
char HelmetRef[2];
char WeaponRef[2];
char OffhandRef[2];
public:
const ieDword *Colors; //these are the custom color indices
RGBModifier ColorMods[32]; // color modification effects
unsigned long lastModUpdate;
RGBModifier GlobalColorMod; // global color modification effect
Palette* palette[4];
Palette* modifiedPalette[4];
unsigned int AvatarsRowNum;
unsigned char ArmorType, WeaponType, RangedType;
ieResRef ResRef;
ieResRef PaletteResRef;
unsigned char nextStanceID, StanceID;
bool autoSwitchOnEnd;
bool lockPalette;
public:
CharAnimations(unsigned int AnimID, ieDword ArmourLevel);
~CharAnimations(void);
static void ReleaseMemory();
void SetArmourLevel(int ArmourLevel);
void SetRangedType(int Ranged);
void SetWeaponType(int WeaponType);
void SetHelmetRef(const char* ref);
void SetWeaponRef(const char* ref);
void SetOffhandRef(const char* ref);
void SetupColors(PaletteType type);
void SetColors(const ieDword *Colors);
void LockPalette(const ieDword *Colors);
// returns an array of animations of size GetTotalPartCount()
Animation** GetAnimation(unsigned char Stance, unsigned char Orient);
int GetTotalPartCount() const;
const int* GetZOrder(unsigned char Orient);
// returns Palette for a given part (unlocked)
Palette* GetPartPalette(int part); // TODO: clean this up
public: //attribute functions
static int GetAvatarsCount();
static AvatarStruct *GetAvatarStruct(int RowNum);
unsigned int GetAnimationID() const;
int GetCircleSize() const;
int NoPalette() const;
int GetAnimType() const;
int GetSize() const;
int GetBloodColor() const;
const ieResRef &GetWalkSound() const;
int GetWalkSoundCount() const;
void PulseRGBModifiers();
private:
void DropAnims();
void InitAvatarsTable();
int GetActorPartCount() const;
void AddPSTSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddFFSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient, int Part);
void AddNFSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient, int Part);
void AddVHR2Suffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddVHRSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient, EquipResRefData*& equip);
void AddVHR3Suffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void GetVHREquipmentRef(char* ResRef, unsigned char& Cycle,
const char* equipRef, bool offhand, EquipResRefData* equip);
void AddSixSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddMHRSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient, EquipResRefData*& equip);
void GetMHREquipmentRef(char* ResRef, unsigned char& Cycle,
const char* equipRef, bool offhand, EquipResRefData* equip);
void AddMMRSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddMMR2Suffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddTwoFileSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddLRSuffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient, EquipResRefData*& equip);
void AddLRSuffix2( char* ResRef, unsigned char StanceID,
unsigned char& Cycle, unsigned char Orient, EquipResRefData *&EquipData);
void GetLREquipmentRef(char* ResRef, unsigned char& Cycle,
const char* equipRef, bool offhand, EquipResRefData* equip);
void AddLR2Suffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void AddLR3Suffix(char* ResRef, unsigned char AnimID,
unsigned char& Cycle, unsigned char Orient);
void GetAnimResRef(unsigned char AnimID, unsigned char Orient,
char* ResRef, unsigned char& Cycle, int Part, EquipResRefData*& equip);
void GetEquipmentResRef(const char* equipRef, bool offhand,
char* ResRef, unsigned char& Cycle, EquipResRefData* equip);
};
#endif

View File

@@ -0,0 +1,37 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Compressor.h"
#include "globals.h"
Compressor::Compressor(void)
{
}
Compressor::~Compressor(void)
{
}
// Initialization Function. Returns FALSE if there was an error during initialization, else returns TRUE.
int Compressor::Init(void)
{
return GEM_OK;
}

View File

@@ -0,0 +1,41 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef COMPRESSOR_H
#define COMPRESSOR_H
#include "Plugin.h"
#include "System/DataStream.h"
#include <cstdio>
class GEM_EXPORT Compressor : public Plugin {
public:
Compressor(void);
virtual ~Compressor(void);
/** Initialization Function. Returns FALSE if there was an error during initialization, else returns TRUE. */
virtual int Init(void);
/** decompresses a datastream (memory or file) to a FILE * stream */
virtual int Decompress(FILE* dest, DataStream* source, unsigned int size_guess = 0) const = 0;
/** compresses a datastream (memory or file) to another DataStream */
virtual int Compress(DataStream *dest, DataStream* source) const = 0;
};
#endif

View File

@@ -0,0 +1,138 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "ControlAnimation.h"
#include "win32def.h"
#include "GameData.h"
#include "Interface.h"
#include "Palette.h" /* needed only for paperdoll palettes */
#include "Video.h" /* needed only for paperdoll palettes */
#include "GUI/Button.h"
ControlAnimation::ControlAnimation(Control* ctl, const ieResRef ResRef, int Cycle)
{
control = NULL;
bam = NULL;
cycle = Cycle;
frame = 0;
anim_phase = 0;
bam = ( AnimationFactory* ) gamedata->GetFactoryResource( ResRef,
IE_BAM_CLASS_ID, IE_NORMAL );
if (! bam)
return;
control = ctl;
control->animation = this;
has_palette = false;
}
//freeing the bitmaps only once, but using an intelligent algorithm
ControlAnimation::~ControlAnimation(void)
{
//removing from timer first
core->timer->RemoveAnimation( this );
bam = NULL;
}
bool ControlAnimation::SameResource(const ieResRef ResRef, int Cycle)
{
if (!control ) return false;
if (!bam) return false;
if (strnicmp(ResRef, bam->ResRef, sizeof(ieResRef) )) return false;
int c = cycle;
if (control->Flags&IE_GUI_BUTTON_PLAYRANDOM) {
c&=~1;
}
if (Cycle!=c) return false;
return true;
}
void ControlAnimation::UpdateAnimation(void)
{
unsigned long time;
int Cycle = cycle;
if (control->Flags & IE_GUI_BUTTON_PLAYRANDOM) {
// simple Finite-State Machine
if (anim_phase == 0) {
frame = 0;
anim_phase = 1;
time = 500 + 500 * (rand() % 20);
cycle&=~1;
Cycle=cycle;
} else if (anim_phase == 1) {
if (rand() % 30 == 0) {
cycle|=1;
Cycle=cycle;
}
anim_phase = 2;
time = 100;
} else {
frame++;
time = 100;
}
} else {
frame ++;
if (has_palette) {
time = 100; //hack for slower movement
} else {
time = 15;
}
}
Sprite2D* pic = bam->GetFrame( (unsigned short) frame, (unsigned char) Cycle );
if (pic == NULL) {
//stopping at end frame
if (control->Flags & IE_GUI_BUTTON_PLAYONCE) {
core->timer->RemoveAnimation( this );
return;
}
anim_phase = 0;
frame = 0;
pic = bam->GetFrame( 0, (unsigned char) Cycle );
}
if (pic == NULL) {
return;
}
if (has_palette) {
Palette* palette = pic->GetPalette();
palette->SetupPaperdollColours(colors, 0);
pic->SetPalette(palette);
palette->Release();
}
control->SetAnimPicture( pic );
core->timer->AddAnimation( this, time );
}
void ControlAnimation::SetPaletteGradients(ieDword *col)
{
memcpy(colors, col, 8*sizeof(ieDword));
has_palette = true;
}

View File

@@ -0,0 +1,51 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef CONTROLANIMATIONS_H
#define CONTROLANIMATIONS_H
#include "RGBAColor.h"
#include "exports.h"
#include "AnimationFactory.h"
#include "Sprite2D.h"
#include "GUI/Control.h"
#include <vector>
class GEM_EXPORT ControlAnimation {
private:
AnimationFactory* bam;
Control* control;
unsigned int cycle;
unsigned int frame;
unsigned int anim_phase;
bool has_palette;
ieDword colors[8];
public:
ControlAnimation(Control* ctl, const ieResRef ResRef, int Cycle = 0);
~ControlAnimation(void);
void UpdateAnimation();
//report if the current resource is the same as descripted by the params
bool SameResource(const ieResRef ResRef, int Cycle);
void SetPaletteGradients(ieDword *col);
};
#endif

View File

@@ -0,0 +1,323 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Core.cpp
* Some compatibility and utility functions
* @author The GemRB Project
*/
#include "globals.h"
#include "exports.h"
#include "Interface.h"
#include "Scriptable/Actor.h"
#include <cmath>
#include <ctype.h>
#ifdef WIN32
#include "win32def.h"
#ifdef _DEBUG
#include <stdlib.h>
#include <crtdbg.h>
#endif
BOOL WINAPI DllEntryPoint(HINSTANCE /*hinstDLL*/, DWORD /*fdwReason*/,
LPVOID /*lpvReserved*/)
{
return true;
}
#endif
//// Globally used functions
ieByte pl_uppercase[256];
ieByte pl_lowercase[256];
// these 3 functions will copy a string to a zero terminated string with a maximum length
void strnlwrcpy(char *dest, const char *source, int count)
{
while(count--) {
*dest++ = pl_lowercase[(ieByte) *source];
if(!*source++) {
while(count--) *dest++=0;
break;
}
}
*dest=0;
}
void strnuprcpy(char* dest, const char *source, int count)
{
while(count--) {
*dest++ = pl_uppercase[(ieByte) *source];
if(!*source++) {
while(count--) *dest++=0;
break;
}
}
*dest=0;
}
// this one also filters spaces
void strnspccpy(char* dest, const char *source, int count)
{
memset(dest,0,count);
while(count--) {
char c = pl_lowercase[(ieByte) *source];
if (c!=' ') {
*dest++=c;
}
if(!*source++) {
return;
}
}
}
#ifndef HAVE_STRNLEN
int strnlen(const char* string, int maxlen)
{
if (!string) {
return -1;
}
int i = 0;
while (maxlen-- > 0) {
if (!string[i])
break;
i++;
}
return i;
}
#endif // ! HAVE_STRNLEN
static const unsigned char orientations[25]={
6,7,8,9,10,
5,6,8,10,11,
4,4,0,12,12,
3,2,0,14,13,
2,1,0,15,14
};
/** Calculates the orientation of a character (or projectile) facing a point */
unsigned char GetOrient(const Point &s, const Point &d)
{
int deltaX = s.x - d.x;
int deltaY = s.y - d.y;
int div = Distance(s,d);
if(!div) return 0; //default
if(div>3) div/=2;
int aX=deltaX/div;
int aY=deltaY/div;
return orientations[(aY+2)*5+aX+2];
}
/** Calculates distance between 2 points */
unsigned int Distance(Point p, Point q)
{
long x = ( p.x - q.x );
long y = ( p.y - q.y );
return (unsigned int) sqrt( ( double ) ( x* x + y* y ) );
}
/** Calculates distance squared from a point to a scriptable */
unsigned int SquaredMapDistance(Point p, Scriptable *b)
{
long x = ( p.x/16 - b->Pos.x/16 );
long y = ( p.y/12 - b->Pos.y/12 );
return (unsigned int)(x*x + y*y);
}
/** Calculates distance between 2 points */
unsigned int Distance(Point p, Scriptable *b)
{
long x = ( p.x - b->Pos.x );
long y = ( p.y - b->Pos.y );
return (unsigned int) sqrt( ( double ) ( x* x + y* y ) );
}
unsigned int PersonalDistance(Point p, Scriptable *b)
{
long x = ( p.x - b->Pos.x );
long y = ( p.y - b->Pos.y );
int ret = (int) sqrt( ( double ) ( x* x + y* y ) );
if (b->Type==ST_ACTOR) {
ret-=((Actor *)b)->size*10;
}
if (ret<0) return (unsigned int) 0;
return (unsigned int) ret;
}
unsigned int SquaredPersonalDistance(Point p, Scriptable *b)
{
long x = ( p.x - b->Pos.x );
long y = ( p.y - b->Pos.y );
int ret = x*x + y*y;
if (b->Type==ST_ACTOR) {
ret-=((Actor *)b)->size*100;
}
if (ret<0) return (unsigned int) 0;
return (unsigned int) ret;
}
/** Calculates map distance between 2 scriptables */
unsigned int SquaredMapDistance(Scriptable *a, Scriptable *b)
{
long x = (a->Pos.x/16 - b->Pos.x/16 );
long y = (a->Pos.y/12 - b->Pos.y/12 );
return (unsigned int)(x*x + y*y);
}
/** Calculates distance between 2 scriptables */
unsigned int Distance(Scriptable *a, Scriptable *b)
{
long x = ( a->Pos.x - b->Pos.x );
long y = ( a->Pos.y - b->Pos.y );
return (unsigned int) sqrt( ( double ) ( x* x + y* y ) );
}
/** Calculates distance squared between 2 scriptables */
unsigned int SquaredDistance(Scriptable *a, Scriptable *b)
{
long x = ( a->Pos.x - b->Pos.x );
long y = ( a->Pos.y - b->Pos.y );
return (unsigned int) ( x* x + y* y );
}
/** Calculates distance between 2 scriptables, including feet circle if applicable */
unsigned int PersonalDistance(Scriptable *a, Scriptable *b)
{
long x = ( a->Pos.x - b->Pos.x );
long y = ( a->Pos.y - b->Pos.y );
int ret = (int) sqrt( ( double ) ( x* x + y* y ) );
if (a->Type==ST_ACTOR) {
ret-=((Actor *)a)->size*10;
}
if (b->Type==ST_ACTOR) {
ret-=((Actor *)b)->size*10;
}
if (ret<0) return (unsigned int) 0;
return (unsigned int) ret;
}
unsigned int SquaredPersonalDistance(Scriptable *a, Scriptable *b)
{
long x = ( a->Pos.x - b->Pos.x );
long y = ( a->Pos.y - b->Pos.y );
int ret = x*x + y*y;
if (a->Type==ST_ACTOR) {
ret-=((Actor *)a)->size*100;
}
if (b->Type==ST_ACTOR) {
ret-=((Actor *)b)->size*100;
}
if (ret<0) return (unsigned int) 0;
return (unsigned int) ret;
}
// returns EA relation between two scriptables (non actors are always enemies)
// it is used for protectile targeting/iwd ids targeting too!
int EARelation(Scriptable* Owner, Actor* target)
{
ieDword eao = EA_ENEMY;
if (Owner && Owner->Type==ST_ACTOR) {
eao = ((Actor *) Owner)->GetStat(IE_EA);
}
ieDword eat = target->GetStat(IE_EA);
if (eao<=EA_GOODCUTOFF) {
if (eat<=EA_GOODCUTOFF) {
return EAR_FRIEND;
}
if (eat>=EA_EVILCUTOFF) {
return EAR_HOSTILE;
}
return EAR_NEUTRAL;
}
if (eao>=EA_EVILCUTOFF) {
if (eat<=EA_GOODCUTOFF) {
return EAR_HOSTILE;
}
if (eat>=EA_EVILCUTOFF) {
return EAR_FRIEND;
}
return EAR_NEUTRAL;
}
return EAR_NEUTRAL;
}
/** Returns the length of string (up to a delimiter) */
GEM_EXPORT int strlench(const char* string, char ch)
{
int i;
for (i = 0; string[i] && string[i] != ch; i++)
;
return i;
}
//// Compatibility functions
#ifndef HAVE_STRNDUP
GEM_EXPORT char* strndup(const char* s, size_t l)
{
size_t len = strlen( s );
if (len < l) {
l = len;
}
char* string = ( char* ) malloc( l + 1 );
strncpy( string, s, l );
string[l] = 0;
return string;
}
#endif
#ifdef WIN32
#else
char* strupr(char* string)
{
char* s;
if (string) {
for (s = string; *s; ++s)
*s = toupper( *s );
}
return string;
}
char* strlwr(char* string)
{
char* s;
if (string) {
for (s = string; *s; ++s)
*s = tolower( *s );
}
return string;
}
#endif // ! WIN32

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "DataFileMgr.h"
DataFileMgr::DataFileMgr(void)
{
}
DataFileMgr::~DataFileMgr(void)
{
}

View File

@@ -0,0 +1,58 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file DataFileMgr.h
* Declares DataFileMgr class, abstract loader for .INI files
* @author The GemRB Project
*/
#ifndef DATAFILEMGR_H
#define DATAFILEMGR_H
#include "Plugin.h"
#include "System/DataStream.h"
/**
* @class DataFileMgr
* Abstract loader for .INI files
*/
class GEM_EXPORT DataFileMgr : public Plugin {
public:
DataFileMgr(void);
virtual ~DataFileMgr(void);
virtual bool Open(DataStream* stream, bool autoFree = false) = 0;
virtual int GetTagsCount() const = 0;
virtual const char* GetTagNameByIndex(int index) const = 0;
virtual int GetKeysCount(const char* Tag) const = 0;
virtual const char* GetKeyNameByIndex(const char* Tag, int index) const = 0;
virtual const char* GetKeyAsString(const char* Tag, const char* Key,
const char* Default) const = 0;
virtual int GetKeyAsInt(const char* Tag, const char* Key,
const int Default) const = 0;
virtual float GetKeyAsFloat(const char* Tag, const char* Key,
const float Default) const = 0;
virtual bool GetKeyAsBool(const char* Tag, const char* Key,
const bool Default) const = 0;
};
#endif

View File

@@ -0,0 +1,100 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Dialog.h"
#include "win32def.h"
#include "GameScript/GameScript.h"
Dialog::Dialog(void)
{
TopLevelCount = 0;
}
Dialog::~Dialog(void)
{
if (initialStates) {
for (unsigned int i = 0; i < TopLevelCount; i++) {
if (initialStates[i]) {
FreeDialogState( initialStates[i] );
}
}
free(initialStates);
}
if (Order) free(Order);
}
DialogState* Dialog::GetState(unsigned int index)
{
if (index >= TopLevelCount) {
return NULL;
}
return initialStates[index];
}
void Dialog::FreeDialogState(DialogState* ds)
{
for (unsigned int i = 0; i < ds->transitionsCount; i++) {
DialogTransition *trans = ds->transitions[i];
for (size_t j = 0; j < trans->actions.size(); ++j)
trans->actions[j]->Release();
if (trans->condition)
delete trans->condition;
delete( trans );
}
free( ds->transitions );
if (ds->condition) {
delete ds->condition;
}
delete( ds );
}
int Dialog::FindFirstState(Scriptable* target)
{
for (unsigned int i = 0; i < TopLevelCount; i++) {
Condition *cond = GetState( Order[i] )->condition;
if (cond && cond->Evaluate(target)) {
return Order[i];
}
}
return -1;
}
int Dialog::FindRandomState(Scriptable* target)
{
unsigned int i;
unsigned int max = TopLevelCount;
if (!max) return -1;
unsigned int pick = rand()%max;
for (i=pick; i < max; i++) {
Condition *cond = GetState(i)->condition;
if (cond && cond->Evaluate(target)) {
return i;
}
}
for (i=0; i < pick; i++) {
Condition *cond = GetState(i)->condition;
if (cond && cond->Evaluate(target)) {
return i;
}
}
return -1;
}

View File

@@ -0,0 +1,82 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef DIALOG_H
#define DIALOG_H
#include "exports.h"
#include "globals.h"
#include "GameScript/GameScript.h"
#include <vector>
#define IE_DLG_TR_TEXT 0x01
#define IE_DLG_TR_TRIGGER 0x02
#define IE_DLG_TR_ACTION 0x04
#define IE_DLG_TR_FINAL 0x08
#define IE_DLG_TR_JOURNAL 0x10
#define IE_DLG_UNSOLVED 0x40
#define IE_DLG_SOLVED 0x100
#define IE_DLG_QUEST_GROUP 0x4000 // this is a GemRB extension
struct DialogTransition {
ieDword Flags;
ieStrRef textStrRef;
ieStrRef journalStrRef;
Condition* condition;
std::vector<Action*> actions;
ieResRef Dialog;
ieDword stateIndex;
};
struct DialogState {
ieStrRef StrRef;
DialogTransition** transitions;
unsigned int transitionsCount;
Condition* condition;
unsigned int weight;
};
class GEM_EXPORT Dialog {
public:
Dialog(void);
~Dialog(void);
private:
void FreeDialogState(DialogState* ds);
public:
void AddState(DialogState* ds);
DialogState* GetState(unsigned int index);
int FindFirstState(Scriptable* target);
int FindRandomState(Scriptable* target);
void Release()
{
delete this;
}
public:
ieResRef ResRef;
ieDword Flags; //freeze flags (bg2)
unsigned int TopLevelCount;
ieDword* Order;
DialogState** initialStates;
};
#endif

View File

@@ -0,0 +1,473 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "DialogHandler.h"
#include "strrefs.h"
#include "DialogMgr.h"
#include "DisplayMessage.h"
#include "Game.h"
#include "GameData.h"
#include "Video.h"
#include "GUI/GameControl.h"
//translate section values (journal, solved, unsolved, user)
static int sectionMap[4]={4,1,2,0};
static const int bg2Sections[4]={4,1,2,0};
static const int noSections[4]={0,0,0,0};
DialogHandler::DialogHandler(void)
{
dlg = NULL;
targetID = 0;
originalTargetID = 0;
speakerID = 0;
if (core->HasFeature(GF_JOURNAL_HAS_SECTIONS) ) {
memcpy(sectionMap, bg2Sections, sizeof(sectionMap) );
} else {
memcpy(sectionMap, noSections, sizeof(sectionMap) );
}
}
DialogHandler::~DialogHandler(void)
{
if (dlg) {
delete dlg;
}
}
//Try to start dialogue between two actors (one of them could be inanimate)
int DialogHandler::InitDialog(Scriptable* spk, Scriptable* tgt, const char* dlgref)
{
if (dlg) {
delete dlg;
dlg = NULL;
}
PluginHolder<DialogMgr> dm(IE_DLG_CLASS_ID);
dm->Open( gamedata->GetResource( dlgref, IE_DLG_CLASS_ID ), true );
dlg = dm->GetDialog();
if (!dlg) {
printMessage("GameControl", " ", LIGHT_RED);
printf( "Cannot start dialog: %s\n", dlgref );
return -1;
}
strnlwrcpy(dlg->ResRef, dlgref, 8); //this isn't handled by GetDialog???
//target is here because it could be changed when a dialog runs onto
//and external link, we need to find the new target (whose dialog was
//linked to)
Actor *oldTarget = GetActorByGlobalID(targetID);
speakerID = spk->GetGlobalID();
targetID = tgt->GetGlobalID();
if (!originalTargetID) originalTargetID = tgt->GetGlobalID();
if (tgt->Type==ST_ACTOR) {
Actor *tar = (Actor *) tgt;
spk->LastTalkedTo=targetID;
tar->LastTalkedTo=speakerID;
tar->SetCircleSize();
}
if (oldTarget) oldTarget->SetCircleSize();
//check if we are already in dialog
if (core->GetGameControl()->GetDialogueFlags()&DF_IN_DIALOG) {
return 0;
}
int si = dlg->FindFirstState( tgt );
if (si < 0) {
return -1;
}
//we need GUI for dialogs
core->GetGameControl()->UnhideGUI();
//no exploring while in dialogue
core->GetGameControl()->SetScreenFlags(SF_GUIENABLED|SF_DISABLEMOUSE|SF_LOCKSCROLL, BM_OR);
core->GetGameControl()->SetDialogueFlags(DF_IN_DIALOG, BM_OR);
if (tgt->Type==ST_ACTOR) {
Actor *tar = (Actor *) tgt;
tar->DialogInterrupt();
}
//allow mouse selection from dialog (even though screen is locked)
Video *video = core->GetVideoDriver();
Region vp = video->GetViewport();
video->SetMouseEnabled(true);
core->timer->SetMoveViewPort( tgt->Pos.x, tgt->Pos.y, 0, true );
video->MoveViewportTo( tgt->Pos.x-vp.w/2, tgt->Pos.y-vp.h/2 );
//there are 3 bits, if they are all unset, the dialog freezes scripts
if (!(dlg->Flags&7) ) {
core->GetGameControl()->SetDialogueFlags(DF_FREEZE_SCRIPTS, BM_OR);
}
//opening control size to maximum, enabling dialog window
core->GetGame()->SetControlStatus(CS_HIDEGUI, BM_NAND);
core->GetGame()->SetControlStatus(CS_DIALOG, BM_OR);
core->SetEventFlag(EF_PORTRAIT);
return 0;
}
/*try to break will only try to break it, false means unconditional stop*/
void DialogHandler::EndDialog(bool try_to_break)
{
if (try_to_break && (core->GetGameControl()->GetDialogueFlags()&DF_UNBREAKABLE) ) {
return;
}
Actor *tmp = GetSpeaker();
if (tmp) {
tmp->LeaveDialog();
}
speakerID = 0;
Scriptable *tmp2 = GetTarget();
if (tmp2 && tmp2->Type == ST_ACTOR) {
tmp = (Actor *)tmp2;
} else {
tmp = NULL;
}
if (tmp) {
tmp->LeaveDialog();
}
targetID = 0;
if (tmp) tmp->SetCircleSize();
originalTargetID = 0;
ds = NULL;
if (dlg) {
delete dlg;
dlg = NULL;
}
//restoring original size
core->GetGame()->SetControlStatus(CS_DIALOG, BM_NAND);
core->GetGameControl()->SetScreenFlags(SF_DISABLEMOUSE|SF_LOCKSCROLL, BM_NAND);
core->GetGameControl()->SetDialogueFlags(0, BM_SET);
core->SetEventFlag(EF_PORTRAIT);
}
void DialogHandler::DialogChoose(unsigned int choose)
{
TextArea* ta = core->GetMessageTextArea();
if (!ta) {
printMessage("GameControl","Dialog aborted???",LIGHT_RED);
EndDialog();
return;
}
Actor *speaker = GetSpeaker();
if (!speaker) {
printMessage("GameControl","Speaker gone???",LIGHT_RED);
EndDialog();
return;
}
Scriptable *target = GetTarget();
if (!target) {
printMessage("GameControl","Target gone???",LIGHT_RED);
EndDialog();
return;
}
Actor *tgt = NULL;
if (target->Type == ST_ACTOR) {
tgt = (Actor *)target;
}
Video *video = core->GetVideoDriver();
Region vp = video->GetViewport();
video->SetMouseEnabled(true);
core->timer->SetMoveViewPort( target->Pos.x, target->Pos.y, 0, true );
video->MoveViewportTo( target->Pos.x-vp.w/2, target->Pos.y-vp.h/2 );
if (choose == (unsigned int) -1) {
//increasing talkcount after top level condition was determined
int si = dlg->FindFirstState( tgt );
if (si<0) {
EndDialog();
return;
}
if (tgt) {
if (core->GetGameControl()->GetDialogueFlags()&DF_TALKCOUNT) {
core->GetGameControl()->SetDialogueFlags(DF_TALKCOUNT, BM_NAND);
tgt->TalkCount++;
} else if (core->GetGameControl()->GetDialogueFlags()&DF_INTERACT) {
core->GetGameControl()->SetDialogueFlags(DF_INTERACT, BM_NAND);
tgt->InteractCount++;
}
}
ds = dlg->GetState( si );
} else {
if (ds->transitionsCount <= choose) {
return;
}
DialogTransition* tr = ds->transitions[choose];
ta->PopMinRow();
if (tr->Flags&IE_DLG_TR_JOURNAL) {
int Section = 0;
if (tr->Flags&IE_DLG_UNSOLVED) {
Section |= 1;
}
if (tr->Flags&IE_DLG_SOLVED) {
Section |= 2;
}
if (core->GetGame()->AddJournalEntry(tr->journalStrRef, sectionMap[Section], tr->Flags>>16) ) {
displaymsg->DisplayConstantString(STR_JOURNALCHANGE,0xffff00);
char *string = core->GetString( tr->journalStrRef );
//cutting off the strings at the first crlf
char *poi = strchr(string,'\n');
if (poi) {
*poi='\0';
}
displaymsg->DisplayString( string );
free( string );
}
}
if (tr->textStrRef != 0xffffffff) {
//allow_zero is for PST (deionarra's text)
displaymsg->DisplayStringName( (int) (tr->textStrRef), 0x8080FF, speaker, IE_STR_SOUND|IE_STR_SPEECH|IE_STR_ALLOW_ZERO);
if (core->HasFeature( GF_DIALOGUE_SCROLLS )) {
ta->AppendText( "", -1 );
}
}
if (tr->actions.size()) {
// does this belong here? we must clear actions somewhere before
// we start executing them (otherwise queued actions interfere)
// executing actions directly does not work, because dialog
// needs to end before final actions are executed due to
// actions making new dialogs!
if (target->Type == ST_ACTOR) ((Movable *)target)->ClearPath(); // fuzzie added this
target->ClearActions();
for (unsigned int i = 0; i < tr->actions.size(); i++) {
target->AddAction(tr->actions[i]);
//GameScript::ExecuteAction( target, action );
}
}
int final_dialog = tr->Flags & IE_DLG_TR_FINAL;
if (final_dialog) {
ta->SetMinRow( false );
EndDialog();
}
// *** the commented-out line here should no longer be required, with instant handling ***
// all dialog actions must be executed immediately
//target->ProcessActions(true);
// (do not clear actions - final actions can involve waiting/moving)
if (final_dialog) {
return;
}
// avoid problems when dhjollde.dlg tries starting a cutscene in the middle of a dialog
// (it seems harmless doing it in non-HoW too, since other versions would just break in such a situation)
core->SetCutSceneMode( false );
//displaying dialog for selected option
int si = tr->stateIndex;
//follow external linkage, if required
if (tr->Dialog[0] && strnicmp( tr->Dialog, dlg->ResRef, 8 )) {
//target should be recalculated!
tgt = NULL;
if (originalTargetID) {
// always try original target first (sometimes there are multiple
// actors with the same dialog in an area, we want to pick the one
// we were talking to)
tgt = GetActorByGlobalID(originalTargetID);
if (tgt && strnicmp( tgt->GetDialog(GD_NORMAL), tr->Dialog, 8 ) != 0) {
tgt = NULL;
}
}
if (!tgt) {
// then just search the current area for an actor with the dialog
tgt = target->GetCurrentArea()->GetActorByDialog(tr->Dialog);
}
if (!tgt) {
// try searching for banter dialogue: the original engine seems to
// happily let you randomly switch between normal and banter dialogs
// TODO: work out if this should go somewhere more central (such
// as GetActorByDialog), or if there's a less awful way to do this
// (we could cache the entries, for example)
// TODO: fix for ToB (see also the Interact action)
AutoTable pdtable("interdia");
if (pdtable) {
int row = pdtable->FindTableValue( pdtable->GetColumnIndex("FILE"), tr->Dialog );
tgt = target->GetCurrentArea()->GetActorByScriptName(pdtable->GetRowName(row));
}
}
target = tgt;
if (!target) {
printMessage("Dialog","Can't redirect dialog\n",YELLOW);
ta->SetMinRow( false );
EndDialog();
return;
}
Actor *oldTarget = GetActorByGlobalID(targetID);
targetID = tgt->GetGlobalID();
tgt->SetCircleSize();
if (oldTarget) oldTarget->SetCircleSize();
// we have to make a backup, tr->Dialog is freed
ieResRef tmpresref;
strnlwrcpy(tmpresref,tr->Dialog, 8);
if (target->GetInternalFlag()&IF_NOINT) {
// this whole check moved out of InitDialog by fuzzie, see comments
// for the IF_NOINT check in BeginDialog
displaymsg->DisplayConstantString(STR_TARGETBUSY,0xff0000);
ta->SetMinRow( false );
EndDialog();
return;
}
int ret = InitDialog( speaker, target, tmpresref);
if (ret<0) {
// error was displayed by InitDialog
ta->SetMinRow( false );
EndDialog();
return;
}
}
ds = dlg->GetState( si );
if (!ds) {
printMessage("Dialog","Can't find next dialog\n",YELLOW);
ta->SetMinRow( false );
EndDialog();
return;
}
}
//displaying npc text
displaymsg->DisplayStringName( ds->StrRef, 0x70FF70, target, IE_STR_SOUND|IE_STR_SPEECH);
//adding a gap between options and npc text
ta->AppendText("",-1);
int i;
int idx = 0;
ta->SetMinRow( true );
//first looking for a 'continue' opportunity, the order is descending (a la IE)
unsigned int x = ds->transitionsCount;
while(x--) {
if (ds->transitions[x]->Flags & IE_DLG_TR_FINAL) {
continue;
}
if (ds->transitions[x]->textStrRef != 0xffffffff) {
continue;
}
if (ds->transitions[x]->Flags & IE_DLG_TR_TRIGGER) {
if (ds->transitions[x]->condition &&
!ds->transitions[x]->condition->Evaluate(target)) {
continue;
}
}
core->GetDictionary()->SetAt("DialogOption",x);
core->GetGameControl()->SetDialogueFlags(DF_OPENCONTINUEWINDOW, BM_OR);
goto end_of_choose;
}
for (x = 0; x < ds->transitionsCount; x++) {
if (ds->transitions[x]->Flags & IE_DLG_TR_TRIGGER) {
if (ds->transitions[x]->condition &&
!ds->transitions[x]->condition->Evaluate(target)) {
continue;
}
}
idx++;
if (ds->transitions[x]->textStrRef == 0xffffffff) {
//dialogchoose should be set to x
//it isn't important which END option was chosen, as it ends
core->GetDictionary()->SetAt("DialogOption",x);
core->GetGameControl()->SetDialogueFlags(DF_OPENENDWINDOW, BM_OR);
} else {
char *string = ( char * ) malloc( 40 );
sprintf( string, "[s=%d,ffffff,ff0000]%d - [p]", x, idx );
i = ta->AppendText( string, -1 );
free( string );
string = core->GetString( ds->transitions[x]->textStrRef );
ta->AppendText( string, i );
free( string );
ta->AppendText( "[/p][/s]", i );
}
}
// this happens if a trigger isn't implemented or the dialog is wrong
if (!idx) {
printMessage("Dialog", "There were no valid dialog options!\n", YELLOW);
core->GetGameControl()->SetDialogueFlags(DF_OPENENDWINDOW, BM_OR);
}
end_of_choose:
//padding the rows so our text will be at the top
if (core->HasFeature( GF_DIALOGUE_SCROLLS )) {
ta->AppendText( "", -1 );
}
else {
ta->PadMinRow();
}
}
// TODO: duplicate of the one in GameControl
Actor *DialogHandler::GetActorByGlobalID(ieDword ID)
{
if (!ID)
return NULL;
Game* game = core->GetGame();
if (!game)
return NULL;
Map* area = game->GetCurrentArea( );
if (!area)
return NULL;
return area->GetActorByGlobalID(ID);
}
Scriptable *DialogHandler::GetTarget()
{
// TODO: area GetScriptableByGlobalID?
if (!targetID) return NULL;
Game *game = core->GetGame();
if (!game) return NULL;
Map *area = game->GetCurrentArea();
if (!area) return NULL;
Actor *actor = area->GetActorByGlobalID(targetID);
if (actor) return actor;
Door *door = area->GetDoorByGlobalID(targetID);
if (door) return door;
Container *container = area->GetContainerByGlobalID(targetID);
if (container) return container;
InfoPoint *ip = area->GetInfoPointByGlobalID(targetID);
if (ip) return ip;
return NULL;
}
Actor *DialogHandler::GetSpeaker()
{
return GetActorByGlobalID(speakerID);
}

View File

@@ -0,0 +1,51 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef DIALOGHANDLER_H
#define DIALOGHANDLER_H
#include "exports.h"
#include "Dialog.h"
class GEM_EXPORT DialogHandler {
public:
DialogHandler();
~DialogHandler();
private:
/** this function safely retrieves an Actor by ID */
Actor *GetActorByGlobalID(ieDword ID);
private:
DialogState* ds;
Dialog* dlg;
public:
ieDword speakerID;
ieDword targetID;
ieDword originalTargetID;
public:
Scriptable *GetTarget();
Actor *GetSpeaker();
int InitDialog(Scriptable* speaker, Scriptable* target, const char* dlgref);
void EndDialog(bool try_to_break=false);
void DialogChoose(unsigned int choose);
};
#endif

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "DialogMgr.h"
DialogMgr::DialogMgr(void)
{
}
DialogMgr::~DialogMgr(void)
{
}

View File

@@ -0,0 +1,36 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef DIALOGMGR_H
#define DIALOGMGR_H
#include "Dialog.h"
#include "Plugin.h"
#include "System/DataStream.h"
class GEM_EXPORT DialogMgr : public Plugin {
public:
DialogMgr(void);
virtual ~DialogMgr(void);
virtual bool Open(DataStream* stream, bool autoFree = true) = 0;
virtual Dialog* GetDialog() const = 0;
};
#endif

View File

@@ -0,0 +1,230 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003-2005 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "DisplayMessage.h"
#include "strrefs.h"
#include "Interface.h"
#include "TableMgr.h"
#include "GUI/Label.h"
#include "GUI/TextArea.h"
GEM_EXPORT DisplayMessage * displaymsg;
static int strref_table[STRREF_COUNT];
#define PALSIZE 8
static Color ActorColor[PALSIZE];
static const char* DisplayFormatName = "[color=%lX]%s - [/color][p][color=%lX]%s[/color][/p]";
static const char* DisplayFormatAction = "[color=%lX]%s - [/color][p][color=%lX]%s %s[/color][/p]";
static const char* DisplayFormat = "[/color][p][color=%lX]%s[/color][/p]";
static const char* DisplayFormatValue = "[/color][p][color=%lX]%s: %d[/color][/p]";
static const char* DisplayFormatNameString = "[color=%lX]%s - [/color][p][color=%lX]%s: %s[/color][/p]";
DisplayMessage::DisplayMessage(void) {
ReadStrrefs();
}
bool DisplayMessage::ReadStrrefs()
{
int i;
memset(strref_table,-1,sizeof(strref_table) );
AutoTable tab("strings");
if (!tab) {
return false;
}
for(i=0;i<STRREF_COUNT;i++) {
strref_table[i]=atoi(tab->QueryField(i,0));
}
return true;
}
void DisplayMessage::DisplayString(const char* Text, Scriptable *target) const
{
Label *l = core->GetMessageLabel();
if (l) {
l->SetText(Text, 0);
}
TextArea *ta = core->GetMessageTextArea();
if (ta) {
ta->AppendText( Text, -1 );
} else {
if(target) {
char *tmp = strdup(Text);
target->DisplayHeadText(tmp);
}
}
}
ieStrRef DisplayMessage::GetStringReference(int stridx) const
{
return strref_table[stridx];
}
bool DisplayMessage::HasStringReference(int stridx) const
{
return strref_table[stridx] != -1;
}
unsigned int DisplayMessage::GetSpeakerColor(const char *&name, const Scriptable *&speaker) const
{
unsigned int speaker_color;
if(!speaker) return 0;
switch (speaker->Type) {
case ST_ACTOR:
name = speaker->GetName(-1);
core->GetPalette( ((Actor *) speaker)->GetStat(IE_MAJOR_COLOR) & 0xFF, PALSIZE, ActorColor );
speaker_color = (ActorColor[4].r<<16) | (ActorColor[4].g<<8) | ActorColor[4].b;
break;
case ST_TRIGGER: case ST_PROXIMITY: case ST_TRAVEL:
name = core->GetString( ((InfoPoint *) speaker)->DialogName );
speaker_color = 0xc0c0c0;
break;
default:
name = "";
speaker_color = 0x800000;
break;
}
return speaker_color;
}
//simply displaying a constant string
void DisplayMessage::DisplayConstantString(int stridx, unsigned int color, Scriptable *target) const
{
if (stridx<0) return;
const char* text = core->GetString( strref_table[stridx], IE_STR_SOUND );
DisplayString(text, color, target);
}
void DisplayMessage::DisplayString(int stridx, unsigned int color, ieDword flags) const
{
if (stridx<0) return;
const char* text = core->GetString( stridx, flags);
DisplayString(text, color, NULL);
}
void DisplayMessage::DisplayString(const char *text, unsigned int color, Scriptable *target) const
{
if (!text) return;
int newlen = (int)(strlen( DisplayFormat) + strlen( text ) + 12);
char* newstr = ( char* ) malloc( newlen );
snprintf( newstr, newlen, DisplayFormat, color, text );
DisplayString( newstr, target );
free( newstr );
}
// String format is
// blah : whatever
void DisplayMessage::DisplayConstantStringValue(int stridx, unsigned int color, ieDword value) const
{
if (stridx<0) return;
char* text = core->GetString( strref_table[stridx], IE_STR_SOUND );
int newlen = (int)(strlen( DisplayFormat ) + strlen( text ) + 28);
char* newstr = ( char* ) malloc( newlen );
snprintf( newstr, newlen, DisplayFormatValue, color, text, (int) value );
core->FreeString( text );
DisplayString( newstr );
free( newstr );
}
// String format is
// <charname> - blah blah : whatever
void DisplayMessage::DisplayConstantStringNameString(int stridx, unsigned int color, int stridx2, const Scriptable *actor) const
{
unsigned int actor_color;
const char *name = 0;
if (stridx<0) return;
actor_color = GetSpeakerColor(name, actor);
char* text = core->GetString( strref_table[stridx], IE_STR_SOUND );
char* text2 = core->GetString( strref_table[stridx2], IE_STR_SOUND );
int newlen = (int)(strlen( DisplayFormat ) + strlen(name) + strlen( text ) + strlen(text2) + 18);
char* newstr = ( char* ) malloc( newlen );
if (strlen(text2)) {
snprintf( newstr, newlen, DisplayFormatNameString, actor_color, name, color, text, text2 );
} else {
snprintf( newstr, newlen, DisplayFormatName, color, name, color, text );
}
core->FreeString( text );
core->FreeString( text2 );
DisplayString( newstr );
free( newstr );
}
// String format is
// <charname> - blah blah
void DisplayMessage::DisplayConstantStringName(int stridx, unsigned int color, const Scriptable *speaker) const
{
if (stridx<0) return;
if(!speaker) return;
const char* text = core->GetString( strref_table[stridx], IE_STR_SOUND|IE_STR_SPEECH );
DisplayStringName(text, color, speaker);
}
void DisplayMessage::DisplayConstantStringAction(int stridx, unsigned int color, const Scriptable *attacker, const Scriptable *target) const
{
unsigned int attacker_color;
const char *name1 = 0;
const char *name2 = 0;
if (stridx<0) return;
GetSpeakerColor(name2, target);
attacker_color = GetSpeakerColor(name1, attacker);
char* text = core->GetString( strref_table[stridx], IE_STR_SOUND|IE_STR_SPEECH );
int newlen = (int)(strlen( DisplayFormatAction ) + strlen( name1 ) +
+ strlen( name2 ) + strlen( text ) + 18);
char* newstr = ( char* ) malloc( newlen );
snprintf( newstr, newlen, DisplayFormatAction, attacker_color, name1, color,
text, name2);
core->FreeString( text );
DisplayString( newstr );
free( newstr );
}
void DisplayMessage::DisplayStringName(int stridx, unsigned int color, const Scriptable *speaker, ieDword flags) const
{
if (stridx<0) return;
const char* text = core->GetString( stridx, flags);
DisplayStringName(text, color, speaker);
}
void DisplayMessage::DisplayStringName(const char *text, unsigned int color, const Scriptable *speaker) const
{
unsigned int speaker_color;
const char *name = 0;
if (!text) return;
speaker_color = GetSpeakerColor(name, speaker);
int newlen = (int)(strlen( DisplayFormatName ) + strlen( name ) +
+ strlen( text ) + 18);
char* newstr = ( char* ) malloc( newlen );
snprintf( newstr, newlen, DisplayFormatName, speaker_color, name, color, text );
DisplayString( newstr );
free( newstr );
}

View File

@@ -0,0 +1,70 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003-2005 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file DisplayMessage.h
* Declaration of the DisplayMessage class used for displaying messages in
* game message window
*/
#ifndef DISPLAYMESSAGE_H
#define DISPLAYMESSAGE_H
#include "exports.h"
#include "ActorMgr.h"
class GEM_EXPORT DisplayMessage
{
private:
bool ReadStrrefs();
public:
DisplayMessage(void);
/** returns a string reference from a string reference index constant */
ieStrRef GetStringReference(int stridx) const;
/** returns true if a string reference for a string reference index constant exists */
bool HasStringReference(int stridx) const;
/** returns the speaker's color and name */
unsigned int GetSpeakerColor(const char *&name, const Scriptable *&speaker) const;
/** displays any string in the textarea */
void DisplayString(const char *txt, Scriptable *speaker=NULL) const;
/** displays a string constant in the textarea */
void DisplayConstantString(int stridx, unsigned int color, Scriptable *speaker=NULL) const;
/** displays actor name - action : parameter */
void DisplayConstantStringNameString(int stridx, unsigned int color, int stridx2, const Scriptable *actor) const;
/** displays a string constant followed by a number in the textarea */
void DisplayConstantStringValue(int stridx, unsigned int color, ieDword value) const;
/** displays a string constant in the textarea, starting with speaker's name */
void DisplayConstantStringName(int stridx, unsigned int color, const Scriptable *speaker) const;
/** displays a string constant in the textarea, starting with actor, and ending with target */
void DisplayConstantStringAction(int stridx, unsigned int color, const Scriptable *actor, const Scriptable *target) const;
/** displays a string in the textarea */
void DisplayString(int stridx, unsigned int color, ieDword flags) const;
void DisplayString(const char *text, unsigned int color, Scriptable *target) const;
/** displays a string in the textarea, starting with speaker's name */
void DisplayStringName(int stridx, unsigned int color, const Scriptable *speaker, ieDword flags) const;
void DisplayStringName(const char *text, unsigned int color, const Scriptable *speaker) const;
};
extern GEM_EXPORT DisplayMessage * displaymsg;
#endif

View File

@@ -0,0 +1,139 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Effect.h
* Declares Effect class implementing spell and spell-like effects
* and related defines
*/
#ifndef EFFECT_H
#define EFFECT_H
#include "ie_types.h"
#include "Region.h"
class Actor;
//local variables in creatures are stored in fake opcodes
#define FAKE_VARIABLE_OPCODE 187
#define FAKE_VARIABLE_MARKER 1
// Effect target types
#define FX_TARGET_UNKNOWN 0
#define FX_TARGET_SELF 1
#define FX_TARGET_PRESET 2
#define FX_TARGET_PARTY 3
#define FX_TARGET_ALL 4
#define FX_TARGET_ALL_BUT_PARTY 5
#define FX_TARGET_OWN_SIDE 6
#define FX_TARGET_OTHER_SIDE 7
#define FX_TARGET_ALL_BUT_SELF 8
#define FX_TARGET_ORIGINAL 9
// Effect duration/timing types
#define FX_DURATION_INSTANT_LIMITED 0
#define FX_DURATION_INSTANT_PERMANENT 1
#define FX_DURATION_INSTANT_WHILE_EQUIPPED 2
#define FX_DURATION_DELAY_LIMITED 3 //this contains a relative onset time (delay) also used as duration, transforms to 6 when applied
#define FX_DURATION_DELAY_PERMANENT 4 //this transforms to 9 (i guess)
#define FX_DURATION_DELAY_UNSAVED 5 //this transforms to 8
#define FX_DURATION_DELAY_LIMITED_PENDING 6 //this contains an absolute onset time and a duration
#define FX_DURATION_AFTER_EXPIRES 7 //this is a delayed non permanent effect (resolves to JUST_EXPIRED)
#define FX_DURATION_PERMANENT_UNSAVED 8
#define FX_DURATION_INSTANT_PERMANENT_AFTER_BONUSES 9//this is a special permanent
#define FX_DURATION_JUST_EXPIRED 10
#define MAX_TIMING_MODE 11
#define FX_DURATION_ABSOLUTE 0x1000
// Effect resistance types
#define FX_NO_RESIST_NO_DISPEL 0
#define FX_CAN_RESIST_CAN_DISPEL 1
//#define FX_CAN_RESIST_NO_DISPEL 2 //same as 0 (not resistable, not dispellable)
#define FX_NO_RESIST_CAN_DISPEL 3
#define FX_CAN_DISPEL 1
#define FX_CAN_RESIST 3
/**
* @class Effect
* Structure holding information about single spell or spell-like effect.
*/
// the same as ITMFeature and SPLFeature
struct Effect {
ieDword Opcode;
ieDword Target;
ieDword Power;
ieDword Parameter1;
ieDword Parameter2;
ieWord TimingMode; //0x1000 -- no need of conversion
ieWord unknown2;
ieDword Resistance;
ieDword Duration;
ieWord Probability1;
ieWord Probability2;
//keep these four in one bunch, VariableName will
//spread across them
ieResRef Resource;
ieResRef Resource2; //vvc in a lot of effects
ieResRef Resource3;
ieResRef Resource4;
ieDword DiceThrown;
ieDword DiceSides;
ieDword SavingThrowType;
ieDword SavingThrowBonus;
ieWord IsVariable;
ieWord IsSaveForHalfDamage;
// EFF V2.0 fields:
ieDword PrimaryType; //school
ieDword MinAffectedLevel;
ieDword MaxAffectedLevel;
ieDword Parameter3;
ieDword Parameter4;
ieDword PosX, PosY;
ieDword SourceType; //1-item, 2-spell
ieResRef Source;
ieDword SourceFlags;
ieDword Projectile; //9c
ieDwordSigned InventorySlot; //a0
//Original engine had a VariableName here, but it is stored in the resource fields
ieDword CasterLevel; //c4 in both
ieDword FirstApply; //c8 in bg2, cc in iwd2
ieDword SecondaryType;
ieDword SecondaryDelay; //still not sure about this
ieDword CasterID; //10c in bg2 (not saved?)
// These are not in the IE files, but are our precomputed values
ieDword random_value;
public:
//don't modify position in case it was already set
void SetPosition(const Point &p) {
if(PosX==0xffffffff && PosY==0xffffffff) {
PosX=p.x;
PosY=p.y;
}
}
};
// FIXME: what about area spells? They can have map & coordinates as target
//void AddEffect(Effect* fx, Actor* self, Actor* pretarget);
#endif // ! EFFECT_H

View File

@@ -0,0 +1,29 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "EffectMgr.h"
EffectMgr::EffectMgr(void)
{
}
EffectMgr::~EffectMgr(void)
{
}

View File

@@ -0,0 +1,56 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file EffectMgr.h
* Declares EffectMgr class, loader for Effect objects
* @author The GemRB Project
*/
#ifndef EFFECTMGR_H
#define EFFECTMGR_H
#include "Effect.h"
#include "Plugin.h"
#include "System/DataStream.h"
/**
* @class EffectMgr
* Abstract loader for Effect objects
*/
class GEM_EXPORT EffectMgr : public Plugin {
public:
EffectMgr(void);
virtual ~EffectMgr(void);
virtual bool Open(DataStream* stream, bool autoFree = true) = 0;
/** Fills fx with Effect data loaded from the stream */
virtual Effect* GetEffect(Effect *fx) = 0;
/** Fills fx with Effect v1 data loaded from the stream*/
virtual Effect* GetEffectV1(Effect *fx) = 0;
/** Fills fx with Effect v2.0 data loaded from the stream*/
virtual Effect* GetEffectV20(Effect *fx) = 0;
/** Fills the stream with Effect v2 data loaded from the effect*/
virtual void PutEffectV2(DataStream *stream, const Effect *fx) = 0;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file EffectQueue.h
* Declares EffectQueue class holding and processing all spell effects
* on a single Actor
* @author The GemRB Project
*/
#ifndef EFFECTQUEUE_H
#define EFFECTQUEUE_H
#include "exports.h"
#include "Effect.h"
#include "Region.h"
#include <list>
class Actor;
class Map;
class Scriptable;
/** Maximum number of different Effect opcodes */
#define MAX_EFFECTS 512
///** if the effect returns this, stop adding any other effect */
#define FX_ABORT 0
/** these effects don't stick around if used as permanent,
* in that case they modify a base stat like charisma modifier */
#define FX_PERMANENT 2
/** these effects never stick around, use them for instant effects like damage */
#define FX_NOT_APPLIED 3
/** these effects always stick around when applied as permanent or duration */
#define FX_APPLIED 1
///** insert the effect instead of push back */
#define FX_INSERT 4
//remove level effects flags
#define RL_DISPELLABLE 1 //only dispellables
#define RL_MATCHSCHOOL 2 //match school
#define RL_MATCHSECTYPE 4 //match secondary type
#define RL_REMOVEFIRST 8 //remove only one spell (could be more effects)
//bouncing immunities
#define BNC_PROJECTILE 1
#define BNC_OPCODE 2
#define BNC_LEVEL 4
#define BNC_SCHOOL 8
#define BNC_SECTYPE 0x10
#define BNC_RESOURCE 0x20
#define BNC_PROJECTILE_DEC 0x100
#define BNC_OPCODE_DEC 0x200
#define BNC_LEVEL_DEC 0x400
#define BNC_SCHOOL_DEC 0x800
#define BNC_SECTYPE_DEC 0x1000
#define BNC_RESOURCE_DEC 0x2000
//normal immunities
#define IMM_PROJECTILE 1
#define IMM_OPCODE 2
#define IMM_LEVEL 4
#define IMM_SCHOOL 8
#define IMM_SECTYPE 16
#define IMM_RESOURCE 32
#define IMM_PROJECTILE_DEC 0x100
#define IMM_OPCODE_DEC 0x200
#define IMM_LEVEL_DEC 0x400
#define IMM_SCHOOL_DEC 0x800
#define IMM_SECTYPE_DEC 0x1000
#define IMM_RESOURCE_DEC 0x2000
// FIXME: Dice roll should be probably done just once, e.g. when equipping
// the item, not each time the fx are applied
// <avenger> the dice values are actually level limits, except in 3 hp modifier functions
// the damage function is an instant (the other 2 functions might be tricky with random values)
//#define DICE_ROLL(max_val) ((fx->DiceThrown && fx->DiceSides) ? ((max_val >=0) ? (MIN( core->Roll( fx->DiceThrown, fx->DiceSides, 0 ), max_val )) : (MAX( core->Roll( fx->DiceThrown, fx->DiceSides, 0 ), max_val ))) : max_val)
//sometimes damage doesn't comply with the calculated value
#define DICE_ROLL(adjustment) (core->Roll( fx->DiceThrown, fx->DiceSides, adjustment) )
// You will need to get GameTime somehow to use this macro
#define PrepareDuration(fx) fx->Duration = (fx->Duration*AI_UPDATE_TIME + GameTime)
// often used stat modifications, usually Parameter2 types 0, 1 and 2
//these macros should work differently in permanent mode (modify base too)
#define STAT_GET(stat) (target->Modified[ stat ])
#define STAT_ADD(stat, mod) target->SetStat( stat, STAT_GET( stat ) + ( mod ), 0 )
#define STAT_SUB(stat, mod) target->SetStat( stat, STAT_GET( stat ) - ( mod ), 0 )
#define STAT_BIT_OR(stat, mod) target->SetStat( stat, STAT_GET( stat ) | ( mod ), 0 )
#define STAT_SET(stat, mod) target->SetStat( stat, ( mod ), 0 )
#define STAT_SET_PCF(stat, mod) target->SetStat( stat, ( mod ), 1 )
#define STAT_BIT_OR_PCF(stat, mod) target->SetStat( stat, STAT_GET( stat ) | ( mod ), 1 )
#define STAT_MUL(stat, mod) target->SetStat( stat, STAT_GET(stat) * ( mod ) / 100, 0 )
//if an effect sticks around
#define STATE_CURE( mod ) target->Modified[ IE_STATE_ID ] &= ~(ieDword) ( mod )
#define STATE_SET( mod ) target->Modified[ IE_STATE_ID ] |= (ieDword) ( mod )
#define EXTSTATE_SET( mod ) target->Modified[ IE_EXTSTATE_ID ] |= (ieDword) ( mod )
#define STATE_GET( mod ) (target->Modified[ IE_STATE_ID ] & (ieDword) ( mod ) )
#define EXTSTATE_GET( mod ) (target->Modified[ IE_EXTSTATE_ID ] & (ieDword) ( mod ) )
#define STAT_MOD( stat ) target->NewStat(stat, fx->Parameter1, fx->Parameter2)
#define STAT_MOD_VAR( stat, mod ) target->NewStat(stat, ( mod ) , fx->Parameter2 )
#define BASE_GET(stat) (target->BaseStats[ stat ])
#define BASE_SET(stat, mod) target->SetBase( stat, ( mod ) )
#define BASE_ADD(stat, mod) target->SetBase( stat, BASE_GET(stat)+ ( mod ) )
#define BASE_SUB(stat, mod) target->SetBase( stat, BASE_GET(stat)- ( mod ) )
#define BASE_MUL(stat, mod) target->SetBase( stat, BASE_GET(stat)* ( mod ) / 100 )
#define BASE_MOD(stat) target->NewBase( stat, fx->Parameter1, fx->Parameter2)
#define BASE_MOD_VAR(stat, mod) target->NewBase( stat, (mod), fx->Parameter2 )
//if an effect doesn't stick (and has permanent until cured effect) then
//it has to modify the base stat (which is saved)
//also use this one if the effect starts a cure effect automatically
#define BASE_STATE_SET( mod ) target->SetBaseBit( IE_STATE_ID, ( mod ), true )
#define BASE_STATE_CURE( mod ) target->SetBaseBit( IE_STATE_ID, ( mod ), false )
/** Prototype of a function implementing a particular Effect opcode */
typedef int (* EffectFunction)(Scriptable*, Actor*, Effect*);
/** Links Effect name to a function implementing the effect */
struct EffectRef {
const char* Name;
EffectFunction Function;
int opcode;
};
/** Initializes table of available spell Effects used by all the queues. */
/** The available effects should already be registered by the effect plugins */
bool Init_EffectQueue();
/** Registers opcodes implemented by an effect plugin */
void EffectQueue_RegisterOpcodes(int count, const EffectRef *opcodes);
/** release effect list when Interface is destroyed */
void EffectQueue_ReleaseMemory();
/** Check if opcode is for an effect that takes a color slot as parameter. */
bool IsColorslotEffect(int opcode);
/**
* @class EffectQueue
* Class holding and processing spell Effects on a single Actor
*/
class GEM_EXPORT EffectQueue {
private:
/** List of Effects applied on the Actor */
std::list< Effect* > effects;
/** Actor which is target of the Effects */
Scriptable* Owner;
public:
EffectQueue();
virtual ~EffectQueue();
/** Sets Actor which is affected by these effects */
void SetOwner(Scriptable* act) { Owner = act; }
/** Returns Actor affected by these effects */
Scriptable* GetOwner() const { return Owner; }
/** adds an effect to the queue, it could also insert it if flagged so
* fx should be freed by the caller
*/
void AddEffect(Effect* fx, bool insert=false);
/** Adds an Effect to the queue, subject to level and other checks.
* Returns FX_ABORT is unsuccessful. fx is just a reference, AddEffect()
* will malloc its own copy */
int AddEffect(Effect* fx, Scriptable* self, Actor* pretarget, const Point &dest) const;
/** Removes first Effect matching fx from the queue.
* Effects are matched based on their contents */
bool RemoveEffect(Effect* fx);
int AddAllEffects(Actor* target, const Point &dest) const;
void ApplyAllEffects(Actor* target) const;
/** remove effects marked for removal */
void Cleanup();
/* directly removes effects with specified opcode, use effect_reference when you can */
void RemoveAllEffects(ieDword opcode) const;
void RemoveAllEffectsWithResource(ieDword opcode, const ieResRef resource) const;
/* removes any effects (delayed or not) which were using projectile */
void RemoveAllEffectsWithProjectile(ieDword projectile) const;
/* removes equipping effects with specified inventory slot code */
void RemoveEquippingEffects(ieDwordSigned slotcode) const;
/* removes all effects of a given spell */
void RemoveAllEffects(const ieResRef Removed) const;
void RemoveAllEffects(const ieResRef Removed, ieByte timing) const;
/* removes all effects of type */
void RemoveAllEffects(EffectRef &effect_reference) const;
/* removes expired or to be expired effects */
void RemoveExpiredEffects(ieDword futuretime) const;
/* removes all effects except timing mode 9 */
void RemoveAllNonPermanentEffects() const;
void RemoveAllDetrimentalEffects(EffectRef &effect_reference, ieDword current) const;
void RemoveAllEffectsWithParam(EffectRef &effect_reference, ieDword param2) const;
void RemoveAllEffectsWithResource(EffectRef &effect_reference, const ieResRef resource) const;
void RemoveLevelEffects(ieResRef &Removed, ieDword level, ieDword flags, ieDword match) const;
/* returns true if the timing method supports simplified duration */
static bool HasDuration(Effect *fx);
/* returns true if the effect should be saved */
static bool Persistent(Effect* fx);
/* returns next saved effect, increases index */
std::list< Effect* >::const_iterator GetFirstEffect() const
{
return effects.begin();
}
const Effect *GetNextSavedEffect(std::list< Effect* >::const_iterator &f) const;
Effect *GetNextEffect(std::list< Effect* >::const_iterator &f) const;
ieDword CountEffects(EffectRef &effect_reference, ieDword param1, ieDword param2, const char *ResRef) const;
void ModifyEffectPoint(EffectRef &effect_reference, ieDword x, ieDword y) const;
/* returns the number of saved effects */
ieDword GetSavedEffectsCount() const;
size_t GetEffectsCount() const { return effects.size(); }
/* this method hacks the offhand weapon color effects */
static void HackColorEffects(Actor *Owner, Effect *fx);
static Effect *CreateEffect(EffectRef &effect_reference, ieDword param1, ieDword param2, ieWord timing);
EffectQueue *CopySelf() const;
static Effect *CreateEffectCopy(Effect *oldfx, EffectRef &effect_reference, ieDword param1, ieDword param2);
static Effect *CreateUnsummonEffect(Effect *fx);
//locating opcodes
Effect *HasEffect(EffectRef &effect_reference) const;
Effect *HasEffectWithParam(EffectRef &effect_reference, ieDword param2) const;
Effect *HasEffectWithParamPair(EffectRef &effect_reference, ieDword param1, ieDword param2) const;
Effect *HasEffectWithResource(EffectRef &effect_reference, const ieResRef resource) const;
Effect *HasEffectWithSource(EffectRef &effect_reference, const ieResRef source) const;
void DecreaseParam1OfEffect(EffectRef &effect_reference, ieDword amount) const;
int SpecificDamageBonus(ieDword damage_type) const;
bool HasAnyDispellableEffect() const;
//transforming timing modes
static void TransformToDelay(ieByte &TimingMode);
//getting summarised effects
int BonusAgainstCreature(EffectRef &effect_reference, Actor *actor) const;
//getting weapon immunity flag
bool WeaponImmunity(int enchantment, ieDword weapontype) const;
//melee and ranged effects
void AddWeaponEffects(EffectQueue *fxqueue, EffectRef &fx_ref) const;
// checks if spells of type "types" are disabled (usually by armor)
// returns a bitfield of disabled spelltypes
// it is no longer used
//int DisabledSpellcasting(int types) const;
// returns -1 if bounced, 0 if resisted, 1 if accepted spell
int CheckImmunity(Actor *target) const;
// apply this effectqueue on all actors matching ids targeting
// from pos, in range (no cone size yet)
void AffectAllInRange(Map *map, const Point &pos, int idstype, int idsvalue, unsigned int range, Actor *except);
/** Lists contents of the queue on a terminal for debugging */
void dump() const;
//resolve effect
static int ResolveEffect(EffectRef &effect_reference);
static bool match_ids(Actor *target, int table, ieDword value);
/** returns true if the process should abort applying a stack of effects */
int ApplyEffect(Actor* target, Effect* fx, ieDword first_apply, ieDword resistance=1) const;
private:
/** counts effects of specific opcode, parameters and resource */
ieDword CountEffects(ieDword opcode, ieDword param1, ieDword param2, const char *ResRef) const;
void ModifyEffectPoint(ieDword opcode, ieDword x, ieDword y) const;
//use the effect reference style calls from outside
static Effect *CreateEffect(ieDword opcode, ieDword param1, ieDword param2, ieWord timing);
static Effect *CreateEffectCopy(Effect *oldfx, ieDword opcode, ieDword param1, ieDword param2);
void RemoveAllDetrimentalEffects(ieDword opcode, ieDword current) const;
void RemoveAllEffectsWithParam(ieDword opcode, ieDword param2) const;
Effect *HasOpcode(ieDword opcode) const;
Effect *HasOpcodeWithParam(ieDword opcode, ieDword param2) const;
Effect *HasOpcodeWithParamPair(ieDword opcode, ieDword param1, ieDword param2) const;
Effect *HasOpcodeWithResource(ieDword opcode, const ieResRef resource) const;
Effect *HasOpcodeWithSource(ieDword opcode, const ieResRef source) const;
void DecreaseParam1OfEffect(ieDword opcode, ieDword amount) const;
int SpecificDamageBonus(ieDword opcode, ieDword param2) const;
int BonusAgainstCreature(ieDword opcode, Actor *actor) const;
bool WeaponImmunity(ieDword opcode, int enchantment, ieDword weapontype) const;
};
#endif // ! EFFECTQUEUE_H

View File

@@ -0,0 +1,65 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "Factory.h"
#include "win32def.h"
#include <cstring>
Factory::Factory(void)
{
}
Factory::~Factory(void)
{
for (unsigned int i = 0; i < fobjects.size(); i++) {
delete( fobjects[i] );
}
}
void Factory::AddFactoryObject(FactoryObject* fobject)
{
fobjects.push_back( fobject );
}
int Factory::IsLoaded(const char* ResRef, SClass_ID type) const
{
for (unsigned int i = 0; i < fobjects.size(); i++) {
if (fobjects[i]->SuperClassID == type) {
if (strnicmp( fobjects[i]->ResRef, ResRef, 8 ) == 0) {
return i;
}
}
}
return -1;
}
FactoryObject* Factory::GetFactoryObject(int pos) const
{
return fobjects[pos];
}
void Factory::FreeObjects(void)
{
for (unsigned int i = 0; i < fobjects.size(); i++) {
delete( fobjects[i] );
}
}

View File

@@ -0,0 +1,42 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef FACTORY_H
#define FACTORY_H
#include "exports.h"
#include "globals.h"
#include "AnimationFactory.h"
#include "FactoryObject.h"
class GEM_EXPORT Factory {
private:
std::vector< FactoryObject*> fobjects;
public:
Factory(void);
~Factory(void);
void AddFactoryObject(FactoryObject* fobject);
int IsLoaded(const char* ResRef, SClass_ID type) const;
FactoryObject* GetFactoryObject(int pos) const;
void FreeObjects(void);
};
#endif

View File

@@ -0,0 +1,33 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "FactoryObject.h"
#include "win32def.h"
FactoryObject::FactoryObject(const char* name, SClass_ID SuperClassID)
{
strnlwrcpy( ResRef, name, 8 );
this->SuperClassID = SuperClassID;
}
FactoryObject::~FactoryObject(void)
{
}

View File

@@ -0,0 +1,35 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef FACTORYOBJECT_H
#define FACTORYOBJECT_H
#include "exports.h"
#include "globals.h"
class GEM_EXPORT FactoryObject {
public:
SClass_ID SuperClassID;
ieResRef ResRef;
FactoryObject(const char* ResRef, SClass_ID SuperClassID);
virtual ~FactoryObject(void);
};
#endif

View File

@@ -0,0 +1,560 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
//This class represents game fonts. Fonts are special .bam files.
//Each cycle stands for a letter.
#include "Font.h"
#include "win32def.h"
#include "GameData.h"
#include "Interface.h"
#include "Palette.h"
#include "Video.h"
#include <cassert>
unsigned int lastX = 0;
#define PARAGRAPH_START_X 5;
static const Color black = {0, 0, 0, 0};
inline size_t mystrlen(const char* string)
{
if (!string) {
return ( size_t ) 0;
}
const char* tmp = string;
size_t count = 0;
while (*tmp != 0) {
if (( ( unsigned char ) * tmp ) >= 0xf0) {
tmp += 3;
count += 3;
}
count++;
tmp++;
}
return count;
}
Font::Font(int w, int h, Palette* pal)
{
lastX = 0;
count = 0;
FirstChar = 0;
sprBuffer = 0;
width = w;
height = h;
tmpPixels = (unsigned char*)malloc(width*height);
memset( xPos, 0, sizeof( xPos) );
memset( yPos, 0, sizeof( yPos) );
pal->IncRef();
palette = pal;
maxHeight = h;
}
Font::~Font(void)
{
Video *video = core->GetVideoDriver();
gamedata->FreePalette( palette );
video->FreeSprite( sprBuffer );
}
void Font::FinalizeSprite(bool cK, int index)
{
sprBuffer = core->GetVideoDriver()->CreateSprite8( width, height, 8, tmpPixels, palette ? palette->col : 0, cK, index );
tmpPixels = 0;
}
void Font::AddChar(unsigned char* spr, int w, int h, short xPos, short yPos)
{
if (!spr) {
size[count].x = 0;
size[count].y = 0;
size[count].w = 0;
size[count].h = 0;
this->xPos[count] = 0;
this->yPos[count] = 0;
count++;
return;
}
unsigned char * currPtr = tmpPixels + lastX;
unsigned char * srcPtr = ( unsigned char * ) spr;
for (int y = 0; y < h; y++) {
memcpy( currPtr, srcPtr, w );
srcPtr += w;
currPtr += width;
}
size[count].x = lastX;
size[count].y = 0;
size[count].w = w;
size[count].h = h;
this->xPos[count] = xPos;
this->yPos[count] = yPos;
count++;
lastX += w;
}
void Font::PrintFromLine(int startrow, Region rgn, const unsigned char* string,
Palette* hicolor, unsigned char Alignment, Font* initials,
Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
bool enablecap=false;
int capital = 0;
if (initials)
{
capital=1;
enablecap=true;
}
int initials_rows = 0;
int initials_x = 0;
unsigned int psx = PARAGRAPH_START_X;
Palette *pal = hicolor;
if (!pal) {
pal = palette;
}
if (startrow) enablecap=false;
if (initials==this) {
enablecap=false;
}
sprBuffer->SetPalette( pal );
size_t len = strlen( ( char* ) string );
char* tmp = ( char* ) malloc( len + 1 );
memcpy( tmp, ( char * ) string, len + 1 );
SetupString( tmp, rgn.w, NoColor );
int ystep = 0;
if (Alignment & IE_FONT_SINGLE_LINE) {
for (size_t i = 0; i < len; i++) {
int height = yPos[( unsigned char ) tmp[i] - 1];
if (ystep < height)
ystep = height;
}
} else {
ystep = size[1].h;
}
if (!ystep) ystep = maxHeight;
int x = psx, y = ystep;
int w = CalcStringWidth( tmp, NoColor );
if (Alignment & IE_FONT_ALIGN_CENTER) {
x = ( rgn.w - w) / 2;
} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
x = ( rgn.w - w );
}
if (Alignment & IE_FONT_ALIGN_MIDDLE) {
int h = 0;
for (size_t i = 0; i <= len; i++) {
if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
h++;
}
h = h * ystep;
y += ( rgn.h - h ) / 2;
} else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
int h = 1;
for (size_t i = 0; i <= len; i++) {
if (( tmp[i] == 0 ) || ( tmp[i] == '\n' ))
h++;
}
h = h * ystep;
y += ( rgn.h - h );
} else if (Alignment & IE_FONT_ALIGN_TOP) {
y += 5;
}
Video* video = core->GetVideoDriver();
int row = 0;
for (size_t i = 0; i < len; i++) {
if (( ( unsigned char ) tmp[i] ) == '[' && !NoColor) {
i++;
char tag[256];
tag[0]=0;
for (int k = 0; k < 256 && i<len; k++) {
if (tmp[i] == ']') {
tag[k] = 0;
break;
}
tag[k] = tmp[i++];
}
if (strnicmp( tag, "capital=",8)==0) {
sscanf( tag, "capital=%d", &capital);
if (capital && (row>=startrow) ) {
enablecap=true;
}
continue;
}
if (strnicmp( tag, "color=", 6 ) == 0) {
unsigned int r,g,b;
if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
continue;
const Color c = {(unsigned char) r,(unsigned char)g, (unsigned char)b, 0};
Palette* newPal = core->CreatePalette( c, black );
sprBuffer->SetPalette( newPal );
gamedata->FreePalette( newPal );
continue;
}
if (stricmp( tag, "/color" ) == 0) {
sprBuffer->SetPalette( pal );
continue;
}
if (stricmp( "p", tag ) == 0) {
psx = x;
continue;
}
if (stricmp( "/p", tag ) == 0) {
psx = PARAGRAPH_START_X;
}
continue;
}
if (row < startrow) {
if (tmp[i] == 0) {
row++;
}
continue;
}
if (( tmp[i] == 0 ) || ( tmp[i] == '\n' )) {
y += ystep;
x = psx;
int w = CalcStringWidth( &tmp[i + 1], NoColor );
if (initials_rows > 0) {
initials_rows--;
x += initials_x;
w += initials_x;
}
if (Alignment & IE_FONT_ALIGN_CENTER) {
x = ( rgn.w - w ) / 2;
} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
x = ( rgn.w - w );
}
continue;
}
unsigned char currChar = ( unsigned char ) tmp[i] - 1;
if (initials && capital && enablecap) {
x = initials->PrintInitial( x, y, rgn, currChar );
initials_x = x;
//how many more lines to be indented (one was already indented)
initials_rows = (initials->maxHeight-1)/maxHeight;
enablecap = false;
continue;
}
video->BlitSpriteRegion( sprBuffer, size[currChar],
x + rgn.x, y + rgn.y - yPos[currChar], true, &rgn );
if (cursor && ( i == curpos )) {
video->BlitSprite( cursor, x + rgn.x,
y + rgn.y, true, &rgn );
}
x += size[currChar].w;
}
if (cursor && ( curpos == len )) {
video->BlitSprite( cursor, x + rgn.x,
y + rgn.y, true, &rgn );
}
free( tmp );
}
void Font::Print(Region rgn, const unsigned char* string, Palette* hicolor,
unsigned char Alignment, bool anchor, Font* initials,
Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
Print(rgn, rgn, string, hicolor, Alignment, anchor, initials, cursor, curpos, NoColor);
}
void Font::Print(Region cliprgn, Region rgn, const unsigned char* string,
Palette* hicolor, unsigned char Alignment, bool anchor, Font* initials,
Sprite2D* cursor, unsigned int curpos, bool NoColor) const
{
bool enablecap=false;
int capital = 0;
if (initials)
{
capital=1;
enablecap=true;
}
unsigned int psx = PARAGRAPH_START_X;
Palette* pal = hicolor;
if (!pal) {
pal = palette;
}
if (initials==this) {
initials = NULL;
}
sprBuffer->SetPalette( pal );
size_t len = strlen( ( char* ) string );
char* tmp = ( char* ) malloc( len + 1 );
memcpy( tmp, ( char * ) string, len + 1 );
while (len > 0 && (tmp[len - 1] == '\n' || tmp[len - 1] == '\r')) {
// ignore trailing newlines
tmp[len - 1] = 0;
len--;
}
SetupString( tmp, rgn.w, NoColor );
int ystep = 0;
if (Alignment & IE_FONT_SINGLE_LINE) {
for (size_t i = 0; i < len; i++) {
if (tmp[i] == 0) continue;
int height = yPos[( unsigned char ) tmp[i] - 1];
if (ystep < height)
ystep = height;
}
} else {
ystep = size[1].h;
}
if (!ystep) ystep = maxHeight;
int x = psx, y = ystep;
Video* video = core->GetVideoDriver();
if (Alignment & IE_FONT_ALIGN_CENTER) {
int w = CalcStringWidth( tmp, NoColor );
x = ( rgn.w - w ) / 2;
} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
int w = CalcStringWidth( tmp, NoColor );
x = ( rgn.w - w );
}
if (Alignment & IE_FONT_ALIGN_MIDDLE) {
int h = 0;
for (size_t i = 0; i <= len; i++) {
if (tmp[i] == 0)
h++;
}
h = h * ystep;
y += ( rgn.h - h ) / 2;
} else if (Alignment & IE_FONT_ALIGN_BOTTOM) {
int h = 1;
for (size_t i = 0; i <= len; i++) {
if (tmp[i] == 0)
h++;
}
h = h * ystep;
y += ( rgn.h - h );
} else if (Alignment & IE_FONT_ALIGN_TOP) {
y += 5;
}
for (size_t i = 0; i < len; i++) {
if (( ( unsigned char ) tmp[i] ) == '[' && !NoColor) {
i++;
char tag[256];
tag[0]=0;
for (int k = 0; k < 256 && i<len; k++) {
if (tmp[i] == ']') {
tag[k] = 0;
break;
}
tag[k] = tmp[i++];
}
if (strnicmp( tag, "capital=",8)==0) {
sscanf( tag, "capital=%d", &capital);
if (capital) {
enablecap=true;
}
continue;
}
if (strnicmp( tag, "color=", 6 ) == 0) {
unsigned int r,g,b;
if (sscanf( tag, "color=%02X%02X%02X", &r, &g, &b ) != 3)
continue;
const Color c = {(unsigned char) r,(unsigned char) g,(unsigned char) b, 0};
Palette* newPal = core->CreatePalette( c, black );
sprBuffer->SetPalette( newPal );
gamedata->FreePalette( newPal );
continue;
}
if (stricmp( tag, "/color" ) == 0) {
sprBuffer->SetPalette( pal );
continue;
}
if (stricmp( "p", tag ) == 0) {
psx = x;
continue;
}
if (stricmp( "/p", tag ) == 0) {
psx = PARAGRAPH_START_X;
continue;
}
continue;
}
if (tmp[i] == 0) {
y += ystep;
x = psx;
int w = CalcStringWidth( &tmp[i + 1], NoColor );
if (Alignment & IE_FONT_ALIGN_CENTER) {
x = ( rgn.w - w ) / 2;
} else if (Alignment & IE_FONT_ALIGN_RIGHT) {
x = ( rgn.w - w );
}
continue;
}
unsigned char currChar = ( unsigned char ) tmp[i] - 1;
if (initials && capital) {
x = initials->PrintInitial( x, y, rgn, currChar );
enablecap=false;
continue;
}
video->BlitSpriteRegion( sprBuffer, size[currChar],
x + rgn.x, y + rgn.y - yPos[currChar],
anchor, &cliprgn );
if (cursor && ( curpos == i ))
video->BlitSprite( cursor, x + rgn.x, y + rgn.y, anchor, &cliprgn );
x += size[currChar].w;
}
if (cursor && ( curpos == len )) {
video->BlitSprite( cursor, x + rgn.x, y + rgn.y, anchor, &cliprgn );
}
free( tmp );
}
int Font::PrintInitial(int x, int y, const Region &rgn, unsigned char currChar) const
{
Video *video = core->GetVideoDriver();
video->BlitSpriteRegion( sprBuffer, size[currChar],
x + rgn.x, y + rgn.y - yPos[currChar], true, &rgn );
x += size[currChar].w;
return x;
}
int Font::CalcStringWidth(const char* string, bool NoColor) const
{
size_t ret = 0, len = strlen( string );
for (size_t i = 0; i < len; i++) {
if (( ( unsigned char ) string[i] ) == '[' && !NoColor) {
i++;
if (i>=len)
break;
char tag[256];
int k = 0;
for (k = 0; k < 256; k++) {
if (string[i] == ']') {
tag[k] = 0;
break;
}
tag[k] = string[i++];
}
continue;
}
ret += size[( unsigned char ) string[i] - 1].w;
}
return ( int ) ret;
}
void Font::SetupString(char* string, unsigned int width, bool NoColor) const
{
size_t len = strlen( string );
unsigned int psx = PARAGRAPH_START_X;
int lastpos = 0;
unsigned int x = psx, wx = 0;
bool endword = false;
for (size_t pos = 0; pos < len; pos++) {
if (x + wx > width) {
if (!endword && ( x == psx ))
lastpos = ( int ) pos;
else
string[lastpos] = 0;
x = psx;
}
if (string[pos] == 0) {
continue;
}
endword = false;
if (string[pos] == '\r')
string[pos] = ' ';
if (string[pos] == '\n') {
string[pos] = 0;
x = psx;
wx = 0;
lastpos = ( int ) pos;
endword = true;
continue;
}
if (( ( unsigned char ) string[pos] ) == '[' && !NoColor) {
pos++;
if (pos>=len)
break;
char tag[256];
int k = 0;
for (k = 0; k < 256; k++) {
if (string[pos] == ']') {
tag[k] = 0;
break;
}
tag[k] = string[pos++];
}
if (stricmp( "p", tag ) == 0) {
psx = x;
continue;
}
if (stricmp( "/p", tag ) == 0) {
psx = PARAGRAPH_START_X;
continue;
}
continue;
}
if (string[pos] && string[pos] != ' ') {
string[pos] = ( unsigned char ) (string[pos] - FirstChar);
}
wx += size[( unsigned char ) string[pos] - 1].w;
if (( string[pos] == ' ' ) || ( string[pos] == '-' )) {
x += wx;
wx = 0;
lastpos = ( int ) pos;
endword = true;
}
}
}
Palette* Font::GetPalette() const
{
assert(palette);
palette->IncRef();
return palette;
}
void Font::SetPalette(Palette* pal)
{
if (palette) palette->Release();
pal->IncRef();
palette = pal;
}
void Font::SetFirstChar( unsigned char first)
{
FirstChar = first;
}

View File

@@ -0,0 +1,111 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Font.h
* Declares Font, class for manipulating images serving as fonts
* @author The GemRB Project
*/
#ifndef FONT_H
#define FONT_H
#include "globals.h"
#include "exports.h"
#include <vector>
class Palette;
struct StringList {
Sprite2D*** strings;
unsigned int* heights;
unsigned int* lengths;
int StringCount;
int starty;
int curx;
int cury;
};
#define IE_FONT_ALIGN_LEFT 0x00
#define IE_FONT_ALIGN_CENTER 0x01
#define IE_FONT_ALIGN_RIGHT 0x02
#define IE_FONT_ALIGN_BOTTOM 0x04
#define IE_FONT_ALIGN_TOP 0x10 //Single-Line and Multi-Line Text
#define IE_FONT_ALIGN_MIDDLE 0x20 //Only for single line Text
#define IE_FONT_SINGLE_LINE 0x40
/**
* @class Font
* Class for using and manipulating images serving as fonts
*/
class GEM_EXPORT Font {
private:
int count;
Palette* palette;
Sprite2D* sprBuffer;
unsigned char FirstChar;
short xPos[256];
short yPos[256];
// For the temporary bitmap
unsigned char* tmpPixels;
unsigned int width, height;
public:
/** ResRef of the Font image */
ieResRef ResRef;
int maxHeight;
Region size[256];
public:
Font(int w, int h, Palette* palette);
~Font(void);
void AddChar(unsigned char* spr, int w, int h, short xPos, short yPos);
/** Call this after adding all characters */
void FinalizeSprite(bool cK, int index);
void Print(Region cliprgn, Region rgn, const unsigned char* string,
Palette* color, unsigned char Alignment, bool anchor = false,
Font* initials = NULL, Sprite2D* cursor = NULL,
unsigned int curpos = 0, bool NoColor = false) const;
void Print(Region rgn, const unsigned char* string, Palette* color,
unsigned char Alignment, bool anchor = false,
Font* initials = NULL, Sprite2D* cursor = NULL,
unsigned int curpos = 0, bool NoColor = false) const;
void PrintFromLine(int startrow, Region rgn, const unsigned char* string,
Palette* color, unsigned char Alignment,
Font* initials = NULL, Sprite2D* cursor = NULL,
unsigned int curpos = 0, bool NoColor = false) const;
Palette* GetPalette() const;
void SetPalette(Palette* pal);
/** Returns width of the string rendered in this font in pixels */
int CalcStringWidth(const char* string, bool NoColor = false) const;
void SetupString(char* string, unsigned int width, bool NoColor = false) const;
/** Sets ASCII code of the first character in the font.
* (it allows remapping numeric fonts from \000 to '0') */
void SetFirstChar(unsigned char first);
private:
int PrintInitial(int x, int y, const Region &rgn, unsigned char currChar) const;
};
#endif

View File

@@ -0,0 +1,726 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Button.h"
#include "GUI/GameControl.h"
#include "defsounds.h"
#include "win32def.h"
#include "GameData.h"
#include "Interface.h"
#include "Palette.h"
#include "Variables.h"
#include "Video.h"
Button::Button()
{
Unpressed = Pressed = Selected = Disabled = NULL;
State = IE_GUI_BUTTON_UNPRESSED;
ResetEventHandler( ButtonOnPress );
ResetEventHandler( ButtonOnDoublePress );
ResetEventHandler( ButtonOnShiftPress );
ResetEventHandler( ButtonOnRightPress );
ResetEventHandler( ButtonOnDragDrop );
ResetEventHandler( ButtonOnDrag );
ResetEventHandler( MouseEnterButton );
ResetEventHandler( MouseLeaveButton );
ResetEventHandler( MouseOverButton );
//Text = ( char * ) calloc( 64, sizeof(char) );
Text = NULL;
hasText = false;
font = core->GetButtonFont();
normal_palette = NULL;
disabled_palette = font->GetPalette()->Copy();
for (int i = 0; i < 256; i++) {
disabled_palette->col[i].r = ( disabled_palette->col[i].r * 2 ) / 3;
disabled_palette->col[i].g = ( disabled_palette->col[i].g * 2 ) / 3;
disabled_palette->col[i].b = ( disabled_palette->col[i].b * 2 ) / 3;
}
Flags = IE_GUI_BUTTON_NORMAL;
ToggleState = false;
Picture = NULL;
Clipping = 1.0;
memset(&SourceRGB,0,sizeof(SourceRGB));
memset(&DestRGB,0,sizeof(DestRGB));
memset( borders, 0, sizeof( borders ));
starttime = 0;
Anchor.null();
}
Button::~Button()
{
Video* video = core->GetVideoDriver();
video->FreeSprite( Disabled );
video->FreeSprite( Selected );
video->FreeSprite( Pressed );
video->FreeSprite( Unpressed );
video->FreeSprite( Picture );
ClearPictureList();
if (Text) {
free( Text );
}
gamedata->FreePalette( normal_palette);
gamedata->FreePalette( disabled_palette);
}
/** Sets the 'type' Image of the Button to 'img'.
'type' may assume the following values:
- IE_GUI_BUTTON_UNPRESSED
- IE_GUI_BUTTON_PRESSED
- IE_GUI_BUTTON_SELECTED
- IE_GUI_BUTTON_DISABLED */
void Button::SetImage(unsigned char type, Sprite2D* img)
{
switch (type) {
case IE_GUI_BUTTON_UNPRESSED:
case IE_GUI_BUTTON_LOCKED:
case IE_GUI_BUTTON_LOCKED_PRESSED:
core->GetVideoDriver()->FreeSprite( Unpressed );
Unpressed = img;
break;
case IE_GUI_BUTTON_SECOND:
case IE_GUI_BUTTON_PRESSED:
core->GetVideoDriver()->FreeSprite( Pressed );
Pressed = img;
break;
case IE_GUI_BUTTON_SELECTED:
core->GetVideoDriver()->FreeSprite( Selected );
Selected = img;
break;
case IE_GUI_BUTTON_DISABLED:
case IE_GUI_BUTTON_THIRD:
core->GetVideoDriver()->FreeSprite( Disabled );
Disabled = img;
break;
}
Changed = true;
}
/** make SourceRGB go closer to DestRGB */
void Button::CloseUpColor()
{
if (!starttime) return;
//using the realtime timer, because i don't want to
//handle Game at this point
unsigned long newtime;
Changed = true;
GetTime( newtime );
if (newtime<starttime) {
return;
}
SourceRGB.r = (SourceRGB.r + DestRGB.r) / 2;
SourceRGB.g = (SourceRGB.g + DestRGB.g) / 2;
SourceRGB.b = (SourceRGB.b + DestRGB.b) / 2;
SourceRGB.a = (SourceRGB.a + DestRGB.a) / 2;
if (SourceRGB.r == DestRGB.r &&
SourceRGB.g == DestRGB.g &&
SourceRGB.b == DestRGB.b &&
SourceRGB.a == DestRGB.a) {
starttime = 0;
return;
}
starttime = newtime + 40;
}
/** Draws the Control on the Output Display */
void Button::Draw(unsigned short x, unsigned short y)
{
if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
return;
}
Changed = false;
if (XPos == 65535 || Width == 0) {
return;
}
Video * video = core->GetVideoDriver();
// Button image
if (!( Flags & IE_GUI_BUTTON_NO_IMAGE )) {
Sprite2D* Image = NULL;
switch (State) {
case IE_GUI_BUTTON_UNPRESSED:
case IE_GUI_BUTTON_LOCKED:
case IE_GUI_BUTTON_LOCKED_PRESSED:
Image = Unpressed;
break;
case IE_GUI_BUTTON_SECOND:
case IE_GUI_BUTTON_PRESSED:
Image = Pressed;
if (! Image)
Image = Unpressed;
break;
case IE_GUI_BUTTON_SELECTED:
Image = Selected;
if (! Image)
Image = Unpressed;
break;
case IE_GUI_BUTTON_DISABLED:
case IE_GUI_BUTTON_THIRD:
Image = Disabled;
if (! Image)
Image = Unpressed;
break;
}
if (Image) {
// FIXME: maybe it's useless...
int xOffs = ( Width / 2 ) - ( Image->Width / 2 );
int yOffs = ( Height / 2 ) - ( Image->Height / 2 );
video->BlitSprite( Image, x + XPos + xOffs, y + YPos + yOffs, true );
}
}
if (State == IE_GUI_BUTTON_PRESSED) {
//shift the writing/border a bit
x+= 2;
y+= 2;
}
// Button picture
if (Picture && (Flags & IE_GUI_BUTTON_PICTURE) ) {
// Picture is drawn centered
int xOffs = ( Width / 2 ) - ( Picture->Width / 2 );
int yOffs = ( Height / 2 ) - ( Picture->Height / 2 );
if (Flags & IE_GUI_BUTTON_HORIZONTAL) {
xOffs += x + XPos + Picture->XPos;
yOffs += y + YPos + Picture->YPos;
video->BlitSprite( Picture, xOffs, yOffs, true );
Region r = Region( xOffs, yOffs + (int) (Picture->Height * Clipping), Picture->Width, (int) (Picture->Height*(1.0 - Clipping)) );
video->DrawRect( r, SourceRGB, true );
// do NOT uncomment this, you can't change Changed or invalidate things from
// the middle of Window::DrawWindow() -- it needs moving to somewhere else
//CloseUpColor();
}
else {
Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(Picture->Width * Clipping), Picture->Height );
video->BlitSprite( Picture, x + XPos + xOffs + Picture->XPos, y + YPos + yOffs + Picture->YPos, true, &r );
}
}
// Composite pictures (paperdolls/description icons)
if (!PictureList.empty() && (Flags & IE_GUI_BUTTON_PICTURE) ) {
std::list<Sprite2D*>::iterator iter = PictureList.begin();
int xOffs = 0, yOffs = 0;
if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) {
// Center the hotspots of all pictures
xOffs = Width/2;
yOffs = Height/2;
} else if (Flags & IE_GUI_BUTTON_BG1_PAPERDOLL) {
// Display as-is
xOffs = 0;
yOffs = 0;
} else {
// Center the first picture, and align the rest to that
xOffs = Width/2 - (*iter)->Width/2 + (*iter)->XPos;
yOffs = Height/2 - (*iter)->Height/2 + (*iter)->YPos;
}
for (; iter != PictureList.end(); ++iter) {
video->BlitSprite( *iter, x + XPos + xOffs, y + YPos + yOffs, true );
}
}
// Button picture
if (AnimPicture) {
int xOffs = ( Width / 2 ) - ( AnimPicture->Width / 2 );
int yOffs = ( Height / 2 ) - ( AnimPicture->Height / 2 );
Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(AnimPicture->Width * Clipping), AnimPicture->Height );
if (Flags & IE_GUI_BUTTON_CENTER_PICTURES) {
video->BlitSprite( AnimPicture, x + XPos + xOffs + AnimPicture->XPos, y + YPos + yOffs + AnimPicture->YPos, true, &r );
} else {
video->BlitSprite( AnimPicture, x + XPos + xOffs, y + YPos + yOffs, true, &r );
}
}
// Button label
if (hasText && ! ( Flags & IE_GUI_BUTTON_NO_TEXT )) {
Palette* ppoi = normal_palette;
int align = 0;
if (State == IE_GUI_BUTTON_DISABLED)
ppoi = disabled_palette;
// FIXME: hopefully there's no button which sinks when selected
// AND has text label
//else if (State == IE_GUI_BUTTON_PRESSED || State == IE_GUI_BUTTON_SELECTED) {
if (Flags & IE_GUI_BUTTON_ALIGN_LEFT)
align |= IE_FONT_ALIGN_LEFT;
else if (Flags & IE_GUI_BUTTON_ALIGN_RIGHT)
align |= IE_FONT_ALIGN_RIGHT;
else
align |= IE_FONT_ALIGN_CENTER;
if (Flags & IE_GUI_BUTTON_ALIGN_TOP)
align |= IE_FONT_ALIGN_TOP;
else if (Flags & IE_GUI_BUTTON_ALIGN_BOTTOM)
align |= IE_FONT_ALIGN_BOTTOM;
else
align |= IE_FONT_ALIGN_MIDDLE;
if (! (Flags & IE_GUI_BUTTON_MULTILINE)) {
align |= IE_FONT_SINGLE_LINE;
}
font->Print( Region( x + XPos, y + YPos, Width - 2, Height - 2),
( unsigned char * ) Text, ppoi,
(ieByte) align, true );
}
if (! (Flags&IE_GUI_BUTTON_NO_IMAGE)) {
for (int i = 0; i < MAX_NUM_BORDERS; i++) {
ButtonBorder *fr = &borders[i];
if (! fr->enabled) continue;
Region r = Region( x + XPos + fr->dx1, y + YPos + fr->dy1, Width - (fr->dx1 + fr->dx2 + 1), Height - (fr->dy1 + fr->dy2 + 1) );
video->DrawRect( r, fr->color, fr->filled );
}
}
}
/** Sets the Button State */
void Button::SetState(unsigned char state)
{
if (state > IE_GUI_BUTTON_LOCKED_PRESSED) {// If wrong value inserted
return;
}
if (State != state) {
Changed = true;
State = state;
}
}
void Button::SetBorder(int index, int dx1, int dy1, int dx2, int dy2, const Color &color, bool enabled, bool filled)
{
if (index >= MAX_NUM_BORDERS)
return;
ButtonBorder *fr = &borders[index];
fr->dx1 = dx1;
fr->dy1 = dy1;
fr->dx2 = dx2;
fr->dy2 = dy2;
fr->color = color;
fr->enabled = enabled;
fr->filled = filled;
Changed = true;
}
void Button::EnableBorder(int index, bool enabled)
{
if (index >= MAX_NUM_BORDERS)
return;
if (borders[index].enabled != enabled) {
borders[index].enabled = enabled;
Changed = true;
}
}
void Button::SetFont(Font* newfont)
{
font = newfont;
}
/** Handling The default button (enter) */
void Button::OnSpecialKeyPress(unsigned char Key)
{
if (State != IE_GUI_BUTTON_DISABLED && State != IE_GUI_BUTTON_LOCKED) {
if (Key == GEM_RETURN) {
if (Flags & IE_GUI_BUTTON_DEFAULT ) {
RunEventHandler( ButtonOnPress );
return;
}
}
else if (Key == GEM_ESCAPE) {
if (Flags & IE_GUI_BUTTON_CANCEL ) {
RunEventHandler( ButtonOnPress );
return;
}
}
}
Control::OnSpecialKeyPress(Key);
}
/** Mouse Button Down */
void Button::OnMouseDown(unsigned short x, unsigned short y,
unsigned short Button, unsigned short Mod)
{
if (State == IE_GUI_BUTTON_DISABLED) {
Control::OnMouseDown(x,y,Button,Mod);
return;
}
if (core->GetDraggedItem () && !ButtonOnDragDrop) {
Control::OnMouseDown(x,y,Button,Mod);
return;
}
ScrollBar* scrlbr = (ScrollBar*) sb;
if (!scrlbr) {
Control *ctrl = Owner->GetScrollControl();
if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
scrlbr = (ScrollBar *) ctrl;
}
}
//Button == 1 means Left Mouse Button
switch(Button&GEM_MB_NORMAL) {
case GEM_MB_ACTION:
// We use absolute screen position here, so drag_start
// remains valid even after window/control is moved
drag_start.x = Owner->XPos + XPos + x;
drag_start.y = Owner->YPos + YPos + y;
if (State == IE_GUI_BUTTON_LOCKED) {
SetState( IE_GUI_BUTTON_LOCKED_PRESSED );
return;
}
SetState( IE_GUI_BUTTON_PRESSED );
if (Flags & IE_GUI_BUTTON_SOUND) {
core->PlaySound( DS_BUTTON_PRESSED );
}
if ((Button & GEM_MB_DOUBLECLICK) && ButtonOnDoublePress) {
RunEventHandler( ButtonOnDoublePress );
printMessage("Button","Doubleclick detected\n",GREEN);
}
break;
case GEM_MB_SCRLUP:
if (scrlbr) {
scrlbr->ScrollUp();
core->RedrawAll();
}
break;
case GEM_MB_SCRLDOWN:
if (scrlbr) {
scrlbr->ScrollDown();
core->RedrawAll();
}
break;
}
}
/** Mouse Button Up */
void Button::OnMouseUp(unsigned short x, unsigned short y,
unsigned short Button, unsigned short Mod)
{
if (State == IE_GUI_BUTTON_DISABLED) {
return;
}
//what was just dropped?
int dragtype = 0;
if (core->GetDraggedItem ()) dragtype=1;
if (core->GetDraggedPortrait ()) dragtype=2;
//if something was dropped, but it isn't handled here: it didn't happen
if (dragtype && !ButtonOnDragDrop)
return;
switch (State) {
case IE_GUI_BUTTON_PRESSED:
if (ToggleState) {
SetState( IE_GUI_BUTTON_SELECTED );
} else {
SetState( IE_GUI_BUTTON_UNPRESSED );
}
break;
case IE_GUI_BUTTON_LOCKED_PRESSED:
SetState( IE_GUI_BUTTON_LOCKED );
break;
}
//in case of dragged/dropped portraits, allow the event to happen even
//when we are out of bound
if (dragtype!=2) {
if (( x >= Width ) || ( y >= Height )) {
return;
}
}
if (Flags & IE_GUI_BUTTON_CHECKBOX) {
//checkbox
ToggleState = !ToggleState;
if (ToggleState)
SetState( IE_GUI_BUTTON_SELECTED );
else
SetState( IE_GUI_BUTTON_UNPRESSED );
if (VarName[0] != 0) {
ieDword tmp = 0;
core->GetDictionary()->Lookup( VarName, tmp );
tmp ^= Value;
core->GetDictionary()->SetAt( VarName, tmp );
Owner->RedrawControls( VarName, tmp );
}
} else {
if (Flags & IE_GUI_BUTTON_RADIOBUTTON) {
//radio button
ToggleState = true;
SetState( IE_GUI_BUTTON_SELECTED );
}
if (VarName[0] != 0) {
core->GetDictionary()->SetAt( VarName, Value );
Owner->RedrawControls( VarName, Value );
}
}
switch (dragtype) {
case 1:
RunEventHandler( ButtonOnDragDrop );
return;
case 2:
RunEventHandler( ButtonOnDragDropPortrait );
return;
}
if ((Button&GEM_MB_NORMAL) == GEM_MB_ACTION) {
if ((Mod & GEM_MOD_SHIFT) && ButtonOnShiftPress)
RunEventHandler( ButtonOnShiftPress );
else
RunEventHandler( ButtonOnPress );
} else {
if (Button == GEM_MB_MENU && ButtonOnRightPress)
RunEventHandler( ButtonOnRightPress );
}
}
void Button::OnMouseOver(unsigned short x, unsigned short y)
{
Owner->Cursor = IE_CURSOR_NORMAL;
if (State == IE_GUI_BUTTON_DISABLED) {
return;
}
if ( RunEventHandler( MouseOverButton )) {
//event handler destructed this object
return;
}
//well, no more flags for buttons, and the portraits we can perform action on
//are in fact 'draggable multiline pictures' (with image)
if ((Flags & IE_GUI_BUTTON_DISABLED_P) == IE_GUI_BUTTON_PORTRAIT) {
GameControl *gc = core->GetGameControl();
if (gc) {
Owner->Cursor = gc->GetDefaultCursor();
}
}
if (State == IE_GUI_BUTTON_LOCKED) {
return;
}
//portrait buttons are draggable and locked
if ((Flags & IE_GUI_BUTTON_DRAGGABLE) &&
(State == IE_GUI_BUTTON_PRESSED || State ==IE_GUI_BUTTON_LOCKED_PRESSED)) {
// We use absolute screen position here, so drag_start
// remains valid even after window/control is moved
int dx = Owner->XPos + XPos + x - drag_start.x;
int dy = Owner->YPos + YPos + y - drag_start.y;
core->GetDictionary()->SetAt( "DragX", dx );
core->GetDictionary()->SetAt( "DragY", dy );
drag_start.x = (ieWord) (drag_start.x + dx);
drag_start.y = (ieWord) (drag_start.y + dy);
RunEventHandler( ButtonOnDrag );
}
}
void Button::OnMouseEnter(unsigned short /*x*/, unsigned short /*y*/)
{
if (State == IE_GUI_BUTTON_DISABLED) {
return;
}
if (MouseEnterButton !=0 && VarName[0] != 0) {
core->GetDictionary()->SetAt( VarName, Value );
}
RunEventHandler( MouseEnterButton );
}
void Button::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
{
if (State == IE_GUI_BUTTON_DISABLED) {
return;
}
if (MouseLeaveButton !=0 && VarName[0] != 0) {
core->GetDictionary()->SetAt( VarName, Value );
}
RunEventHandler( MouseLeaveButton );
}
/** Sets the Text of the current control */
int Button::SetText(const char* string, int /*pos*/)
{
free(Text);
Text = NULL;
if (string == NULL) {
hasText = false;
} else if (string[0] == 0) {
hasText = false;
} else {
Text = strndup( string, 255 );
if (Flags&IE_GUI_BUTTON_LOWERCASE)
strlwr( Text );
else if (Flags&IE_GUI_BUTTON_CAPS)
strupr( Text );
hasText = true;
}
Changed = true;
return 0;
}
/** Set Event Handler */
bool Button::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_BUTTON_ON_PRESS:
ButtonOnPress = handler;
break;
case IE_GUI_MOUSE_OVER_BUTTON:
MouseOverButton = handler;
break;
case IE_GUI_MOUSE_ENTER_BUTTON:
MouseEnterButton = handler;
break;
case IE_GUI_MOUSE_LEAVE_BUTTON:
MouseLeaveButton = handler;
break;
case IE_GUI_BUTTON_ON_SHIFT_PRESS:
ButtonOnShiftPress = handler;
break;
case IE_GUI_BUTTON_ON_RIGHT_PRESS:
ButtonOnRightPress = handler;
break;
case IE_GUI_BUTTON_ON_DRAG_DROP:
ButtonOnDragDrop = handler;
break;
case IE_GUI_BUTTON_ON_DRAG_DROP_PORTRAIT:
ButtonOnDragDropPortrait = handler;
break;
case IE_GUI_BUTTON_ON_DRAG:
ButtonOnDrag = handler;
break;
case IE_GUI_BUTTON_ON_DOUBLE_PRESS:
ButtonOnDoublePress = handler;
break;
default:
return false;
}
return true;
}
/** Redraws a button from a given radio button group */
void Button::RedrawButton(const char* VariableName, unsigned int Sum)
{
if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
return;
}
if (State == IE_GUI_BUTTON_DISABLED) {
return;
}
if (Flags & IE_GUI_BUTTON_RADIOBUTTON) {
ToggleState = ( Sum == Value );
} //radio button, exact value
else if (Flags & IE_GUI_BUTTON_CHECKBOX) {
ToggleState = !!( Sum & Value );
} //checkbox, bitvalue
else {
return;
} //other buttons, nothing to redraw
if (ToggleState) {
SetState(IE_GUI_BUTTON_SELECTED);
} else {
SetState(IE_GUI_BUTTON_UNPRESSED);
}
}
/** Sets the Picture */
void Button::SetPicture(Sprite2D* newpic)
{
core->GetVideoDriver()->FreeSprite( Picture );
ClearPictureList();
Picture = newpic;
Changed = true;
Flags |= IE_GUI_BUTTON_PICTURE;
Owner->Invalidate();
}
/** Clears the list of Pictures */
void Button::ClearPictureList()
{
Video* video = core->GetVideoDriver();
for (std::list<Sprite2D*>::iterator iter = PictureList.begin();
iter != PictureList.end(); ++iter)
video->FreeSprite( *iter );
PictureList.clear();
Changed = true;
Owner->Invalidate();
}
/** Add picture to the end of the list of Pictures */
void Button::StackPicture(Sprite2D* Picture)
{
PictureList.push_back(Picture);
Changed = true;
Flags |= IE_GUI_BUTTON_PICTURE;
Owner->Invalidate();
}
bool Button::IsPixelTransparent(unsigned short x, unsigned short y)
{
// some buttons have hollow Image frame filled w/ Picture
// some buttons in BG2 are text only (if BAM == 'GUICTRL')
if (Picture || PictureList.size() || ! Unpressed) return false;
return Unpressed->IsPixelTransparent(x, y);
}
// Set palette used for drawing button label in normal state
void Button::SetTextColor(const Color &fore, const Color &back)
{
gamedata->FreePalette( normal_palette );
normal_palette = core->CreatePalette( fore, back );
Changed = true;
}
void Button::SetHorizontalOverlay(double clip, const Color &src, const Color &dest)
{
if ((Clipping>clip) || !(Flags&IE_GUI_BUTTON_HORIZONTAL) ) {
Flags |= IE_GUI_BUTTON_HORIZONTAL;
SourceRGB=src;
DestRGB=dest;
GetTime( starttime );
starttime += 40;
}
Clipping = clip;
Changed = true;
}
void Button::SetAnchor(ieWord x, ieWord y)
{
Anchor = Point(x,y);
}

View File

@@ -0,0 +1,219 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Button.h
* Declares Button widget, for displaying buttons in the GUI
* @author GemRB Development Team
*/
#ifndef BUTTON_H
#define BUTTON_H
#include "GUI/Control.h"
#include "exports.h"
#include "Font.h"
#include "Sprite2D.h"
#include <list>
class Palette;
// NOTE: keep these synchronized with GUIDefines.py!!!
#define IE_GUI_BUTTON_UNPRESSED 0
#define IE_GUI_BUTTON_PRESSED 1
#define IE_GUI_BUTTON_SELECTED 2
#define IE_GUI_BUTTON_DISABLED 3
// Like DISABLED, but processes MouseOver events and draws UNPRESSED bitmap
#define IE_GUI_BUTTON_LOCKED 4
// Draws the disabled bitmap, but otherwise works like unpressed
#define IE_GUI_BUTTON_THIRD 5
#define IE_GUI_BUTTON_SECOND 6
#define IE_GUI_BUTTON_LOCKED_PRESSED 7 //all the same as LOCKED
#define IE_GUI_BUTTON_NO_IMAGE 0x00000001 // don't draw image (BAM)
#define IE_GUI_BUTTON_PICTURE 0x00000002 // draw picture (BMP, MOS, ...)
#define IE_GUI_BUTTON_SOUND 0x00000004
#define IE_GUI_BUTTON_ALT_SOUND 0x00000008
#define IE_GUI_BUTTON_CHECKBOX 0x00000010 // or radio button
#define IE_GUI_BUTTON_RADIOBUTTON 0x00000020 // sticks in a state
#define IE_GUI_BUTTON_DEFAULT 0x00000040 // enter key triggers it
#define IE_GUI_BUTTON_ANIMATED 0x00000080
//these bits are hardcoded in the .chu structure
#define IE_GUI_BUTTON_ALIGN_LEFT 0x00000100
#define IE_GUI_BUTTON_ALIGN_RIGHT 0x00000200
#define IE_GUI_BUTTON_ALIGN_TOP 0x00000400
#define IE_GUI_BUTTON_ALIGN_BOTTOM 0x00000800
#define IE_GUI_BUTTON_ANCHOR 0x00001000 //not implemented yet
#define IE_GUI_BUTTON_LOWERCASE 0x00002000
#define IE_GUI_BUTTON_MULTILINE 0x00004000 // don't set the single line flag
//end of hardcoded part
#define IE_GUI_BUTTON_DRAGGABLE 0x00008000
#define IE_GUI_BUTTON_NO_TEXT 0x00010000 // don't draw button label
#define IE_GUI_BUTTON_PLAYRANDOM 0x00020000
#define IE_GUI_BUTTON_PLAYONCE 0x00040000
#define IE_GUI_BUTTON_CENTER_PICTURES 0x00080000 // center button's PictureList
#define IE_GUI_BUTTON_BG1_PAPERDOLL 0x00100000 // BG1-style paperdoll PictureList
#define IE_GUI_BUTTON_HORIZONTAL 0x00200000 // horizontal clipping of overlay
#define IE_GUI_BUTTON_CANCEL 0x00400000 // cancel key triggers it
#define IE_GUI_BUTTON_CAPS 0x00800000 // convert text to uppercase
//composite button flags
#define IE_GUI_BUTTON_NORMAL 0x00000004 // default button, doesn't stick
#define IE_GUI_BUTTON_PORTRAIT 0x0000c002 // portrait
#define IE_GUI_BUTTON_DISABLED_P 0x0000c003 // disabled portrait
// !!! Keep these synchronized with GUIDefines.py !!!
#define IE_GUI_BUTTON_ON_PRESS 0x00000000
#define IE_GUI_MOUSE_OVER_BUTTON 0x00000001
#define IE_GUI_MOUSE_ENTER_BUTTON 0x00000002
#define IE_GUI_MOUSE_LEAVE_BUTTON 0x00000003
#define IE_GUI_BUTTON_ON_SHIFT_PRESS 0x00000004
#define IE_GUI_BUTTON_ON_RIGHT_PRESS 0x00000005
#define IE_GUI_BUTTON_ON_DRAG_DROP 0x00000006
#define IE_GUI_BUTTON_ON_DRAG_DROP_PORTRAIT 0x00000007
#define IE_GUI_BUTTON_ON_DRAG 0x00000008
#define IE_GUI_BUTTON_ON_DOUBLE_PRESS 0x00000009
/** Border/frame settings for a button */
struct ButtonBorder {
int dx1;
int dy1;
int dx2;
int dy2;
Color color;
bool filled;
bool enabled;
};
#define MAX_NUM_BORDERS 3
/**
* @class Button
* Button widget, used mainly for buttons, but also for PixMaps (static images)
* or for Toggle Buttons.
*/
class GEM_EXPORT Button : public Control {
public:
Button();
~Button();
/** Sets the 'type' Image of the Button to 'img'.
'type' may assume the following values:
- IE_GUI_BUTTON_UNPRESSED
- IE_GUI_BUTTON_PRESSED
- IE_GUI_BUTTON_SELECTED
- IE_GUI_BUTTON_DISABLED */
void SetImage(unsigned char type, Sprite2D* img);
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Sets the Button State */
void SetState(unsigned char state);
/** Sets the Text of the current control */
int SetText(const char* string, int pos = 0);
/** Sets the Picture */
void SetPicture(Sprite2D* Picture);
/** Clears the list of Pictures */
void ClearPictureList();
/** Add picture to the end of the list of Pictures */
void StackPicture(Sprite2D* Picture);
/** Sets border/frame parameters */
void SetBorder(int index, int dx1, int dy1, int dx2, int dy2, const Color &color, bool enabled = false, bool filled = false);
/** Sets horizontal overlay, used in portrait hp overlay */
void SetHorizontalOverlay(double clip, const Color &src, const Color &dest);
/** Sets font used for drawing button label */
void SetFont(Font* newfont);
/** Enables or disables specified border/frame */
void EnableBorder(int index, bool enabled);
public: // Public Events
/** Mouse Enter */
void OnMouseEnter(unsigned short x, unsigned short y);
/** Mouse Leave */
void OnMouseLeave(unsigned short x, unsigned short y);
/** Mouse Over */
void OnMouseOver(unsigned short x, unsigned short y);
/** Mouse Button Down */
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** A special key has been pressed */
void OnSpecialKeyPress(unsigned char Key);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
/** Button Pressed Event Script Function Name */
EventHandler ButtonOnPress;
EventHandler ButtonOnShiftPress;
EventHandler ButtonOnRightPress;
EventHandler ButtonOnDoublePress;
EventHandler ButtonOnDragDrop;
EventHandler ButtonOnDragDropPortrait;
EventHandler ButtonOnDrag;
EventHandler MouseEnterButton;
EventHandler MouseLeaveButton;
EventHandler MouseOverButton;
/** Refreshes the button from a radio group */
void RedrawButton(const char* VariableName, unsigned int Sum);
/** Set palette used for drawing button label in normal state. */
void SetTextColor(const Color &fore, const Color &back);
/** Sets percent (0-1.0) of width for clipping picture */
void SetPictureClipping(double clip) { Clipping = clip; }
void SetAnchor(ieWord x, ieWord y);
private: // Private attributes
char* Text;
bool hasText;
Font* font;
bool ToggleState;
Palette* normal_palette;
Palette* disabled_palette;
/** Button Unpressed Image */
Sprite2D* Unpressed;
/** Button Pressed Image */
Sprite2D* Pressed;
/** Button Selected Image */
Sprite2D* Selected;
/** Button Disabled Image */
Sprite2D* Disabled;
/** Pictures to Apply when the hasPicture flag is set */
Sprite2D* Picture;
/** If non-empty, list of Pictures to draw when hasPicture is set */
std::list<Sprite2D*> PictureList;
/** The current state of the Button */
unsigned char State;
double Clipping;
Point drag_start;
/** HP Bar over portraits */
unsigned long starttime;
Color SourceRGB, DestRGB;
Point Anchor;
/** frame settings */
ButtonBorder borders[MAX_NUM_BORDERS];
bool IsPixelTransparent (unsigned short x, unsigned short y);
void CloseUpColor();
};
#endif

View File

@@ -0,0 +1,221 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Console.h"
#include "win32def.h"
#include "GameData.h"
#include "Interface.h"
#include "Palette.h"
#include "ScriptEngine.h"
#include "Video.h"
Console::Console(void)
{
Cursor = NULL;
Back = NULL;
max = 128;
Buffer = ( unsigned char * ) malloc( max );
Buffer[0] = 0;
for(size_t i=0;i<HISTORY_SIZE;i++) {
History[i] = ( unsigned char * ) malloc( max );
History[i][0] = 0;
}
CurPos = 0;
HistPos = 0;
HistMax = 0;
palette = NULL;
}
Console::~Console(void)
{
free( Buffer );
for (size_t i=0;i<HISTORY_SIZE;i++) {
free( History[i] );
}
Video *video = core->GetVideoDriver();
gamedata->FreePalette( palette );
video->FreeSprite( Cursor );
}
/** Draws the Console on the Output Display */
void Console::Draw(unsigned short x, unsigned short y)
{
if (Back) {
core->GetVideoDriver()->BlitSprite( Back, 0, y, true );
}
Color black = {
0x00, 0x00, 0x00, 0xff
};
Region r( x + XPos, y + YPos, Width, Height );
core->GetVideoDriver()->DrawRect( r, black );
font->Print( r, Buffer, palette,
IE_FONT_ALIGN_LEFT | IE_FONT_ALIGN_MIDDLE, true, NULL,
Cursor, CurPos, true );
}
/** Set Font */
void Console::SetFont(Font* f)
{
if (f != NULL) {
font = f;
}
}
/** Set Cursor */
void Console::SetCursor(Sprite2D* cur)
{
if (cur != NULL) {
Cursor = cur;
}
}
/** Set BackGround */
void Console::SetBackGround(Sprite2D* back)
{
//if 'back' is NULL then no BackGround will be drawn
Back = back;
}
/** Sets the Text of the current control */
int Console::SetText(const char* string, int /*pos*/)
{
strncpy( ( char * ) Buffer, string, max );
return 0;
}
/** Key Press Event */
void Console::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
{
if (Key >= 0x20) {
size_t len = strlen( ( char* ) Buffer );
if (len + 1 < max) {
for (size_t i = len; i > CurPos; i--) {
Buffer[i] = Buffer[i - 1];
}
Buffer[CurPos++] = Key;
Buffer[len + 1] = 0;
}
}
}
/** Special Key Press */
void Console::OnSpecialKeyPress(unsigned char Key)
{
size_t len;
switch (Key) {
case GEM_BACKSP:
if (CurPos != 0) {
size_t len = strlen( ( const char * ) Buffer );
for (size_t i = CurPos; i < len; i++) {
Buffer[i - 1] = Buffer[i];
}
Buffer[len - 1] = 0;
CurPos--;
}
break;
case GEM_HOME:
CurPos = 0;
break;
case GEM_END:
CurPos = (unsigned short) strlen( (const char * ) Buffer);
break;
case GEM_UP:
HistoryBack();
break;
case GEM_DOWN:
HistoryForward();
break;
case GEM_LEFT:
if (CurPos > 0)
CurPos--;
break;
case GEM_RIGHT:
len = strlen( ( const char * ) Buffer );
if (CurPos < len) {
CurPos++;
}
break;
case GEM_DELETE:
len = strlen( ( const char * ) Buffer );
if (CurPos < len) {
for (size_t i = CurPos; i < len; i++) {
Buffer[i] = Buffer[i + 1];
}
}
break;
case GEM_RETURN:
core->GetGUIScriptEngine()->ExecString( ( char* ) Buffer );
HistoryAdd(false);
Buffer[0] = 0;
CurPos = 0;
HistPos = 0;
Changed = true;
break;
}
}
//ctrl-up
void Console::HistoryBack()
{
HistoryAdd(false);
if (HistPos < HistMax-1 && Buffer[0]) {
HistPos++;
}
memcpy(Buffer, History[HistPos], max);
CurPos = (unsigned short) strlen ((const char *) Buffer);
}
//ctrl-down
void Console::HistoryForward()
{
HistoryAdd(false);
if (HistPos == 0) {
Buffer[0]=0;
CurPos=0;
return;
}
HistPos--;
memcpy(Buffer, History[HistPos], max);
CurPos = (unsigned short) strlen ((const char *) Buffer);
}
void Console::HistoryAdd(bool force)
{
int i;
if (!force && !Buffer[0])
return;
for (i=0;i<HistMax;i++) {
if (!strnicmp((const char *) History[i],(const char *) Buffer,max) )
return;
}
if (History[0][0]) {
for (i=HISTORY_SIZE-1; i>0; i--) {
memcpy(History[i], History[i-1], max);
}
}
memcpy(History[0], Buffer, max);
if (HistMax<HISTORY_SIZE) {
HistMax++;
}
}
bool Console::SetEvent(int /*eventType*/, EventHandler /*handler*/)
{
return false;
}

View File

@@ -0,0 +1,93 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Console.h
* Declares Console widget, input field for direct poking into GemRB innards.
* @author The GemRB Project
*/
#ifndef CONSOLE_H
#define CONSOLE_H
#include "GUI/Control.h"
#include "GUI/TextArea.h"
class Palette;
/**
* @class Console
* Widget displaying debugging console, input field for direct poking
* into GemRB innards.
* The console accepts and executes python statements and has already
* GemRB python module loaded, so almost any command
* from GUIScripts can be used.
*/
/** the number of remembered lines in the cheat console*/
#define HISTORY_SIZE 5
class Console : public Control {
public:
Console(void);
~Console(void);
/** Draws the Console on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Set Font */
void SetFont(Font* f);
/** Set Cursor */
void SetCursor(Sprite2D* cur);
/** Set BackGround */
void SetBackGround(Sprite2D* back);
/** Sets the Text of the current control */
int SetText(const char* string, int pos = 0);
private:
/** Text Editing Cursor Sprite */
Sprite2D* Cursor;
/** Text Font */
Font* font;
/** Background */
Sprite2D* Back;
/** Max Edit Text Length */
unsigned short max;
/** Text Buffer */
unsigned char* Buffer;
/** History Buffer */
unsigned char* History[HISTORY_SIZE];
/** Cursor Position */
unsigned short CurPos;
/** History Position and size */
unsigned short HistPos, HistMax;
/** Color Palette */
Palette* palette;
public: //Events
/** Key Press Event */
void OnKeyPress(unsigned char Key, unsigned short Mod);
/** Special Key Press */
void OnSpecialKeyPress(unsigned char Key);
bool SetEvent(int eventType, EventHandler handler);
private:
void HistoryBack();
void HistoryForward();
void HistoryAdd(bool force);
};
#endif

View File

@@ -0,0 +1,274 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Control.h"
#include "GUI/Window.h"
#include "win32def.h"
#include "ControlAnimation.h"
#include "Interface.h"
#include "ScriptEngine.h"
#include "Video.h"
#include <cstdio>
#include <cstring>
Control::Control()
{
hasFocus = false;
Changed = true;
InHandler = false;
VarName[0] = 0;
Value = 0;
Flags = 0;
Tooltip = NULL;
Owner = NULL;
XPos = 0;
YPos = 0;
sb = NULL;
animation = NULL;
AnimPicture = NULL;
ControlType = IE_GUI_INVALID;
}
Control::~Control()
{
if (InHandler) {
printMessage("Control","Destroying control inside event handler, crash may occur!\n", LIGHT_RED);
}
core->DisplayTooltip( 0, 0, NULL );
free (Tooltip);
delete animation;
core->GetVideoDriver()->FreeSprite(AnimPicture);
}
/** Sets the Tooltip text of the current control */
int Control::SetTooltip(const char* string)
{
free(Tooltip);
if ((string == NULL) || (string[0] == 0)) {
Tooltip = NULL;
} else {
Tooltip = strdup (string);
}
Changed = true;
return 0;
}
/** Sets the tooltip to be displayed on the screen now */
void Control::DisplayTooltip()
{
if (Tooltip)
core->DisplayTooltip( Owner->XPos + XPos + Width / 2, Owner->YPos + YPos + Height / 2, this );
else
core->DisplayTooltip( 0, 0, NULL );
}
void Control::ResetEventHandler(EventHandler handler)
{
handler = NULL;
}
int Control::RunEventHandler(EventHandler handler)
{
if (InHandler) {
printMessage("Control","Nested event handlers are not supported!\n", YELLOW);
return -1;
}
if (handler) {
Window *wnd = Owner;
if (!wnd) {
return -1;
}
unsigned short WID = wnd->WindowID;
unsigned short ID = (unsigned short) ControlID;
InHandler = true;
handler->call();
if (!core->IsValidWindow(WID,wnd) ) {
printMessage ("Control","Owner window destructed!\n", LIGHT_RED);
return -1;
}
if (!wnd->IsValidControl(ID,this) ) {
printMessage ("Control","Control destructed!\n", LIGHT_RED);
return -1;
}
InHandler = false;
}
return 0;
}
/** Key Press Event */
void Control::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
{
//printf("OnKeyPress: CtrlID = 0x%08X, Key = %c (0x%02hX)\n", (unsigned int) ControlID, Key, Key);
#ifdef ANDROID // mapping volume control to volume control keys on device, these keys must be set up in AndroidAppSettings.cfg
switch(Key)
{
case 'o': // volume down
case 'p': // volume up
int Ambients, Movie, Music, SFX, Voices;
core->GetDictionary()->Lookup( "Volume Ambients", (ieDword&)Ambients );
core->GetDictionary()->Lookup( "Volume Movie", (ieDword&)Movie );
core->GetDictionary()->Lookup( "Volume Music", (ieDword&)Music );
core->GetDictionary()->Lookup( "Volume SFX", (ieDword&)SFX );
core->GetDictionary()->Lookup( "Volume Voices", (ieDword&)Voices );
if(Key=='o')
{
if(Ambients>0) Ambients-=10; if(Ambients<0) Ambients=0;
if(Movie>0) Movie-=10; if(Movie<0) Movie=0;
if(Music>0) Music-=10; if(Music<0) Music=0;
if(SFX>0) SFX-=10; if(SFX<0) SFX=0;
if(Voices>0) Voices-=10; if(Voices<0) Voices=0;
}
else
{
if(Ambients<100) Ambients+=10; if(Ambients>100) Ambients=100;
if(Movie<100) Movie+=10; if(Movie>100) Movie=100;
if(Music<100) Music+=10; if(Music>100) Music=100;
if(SFX<100) SFX+=10; if(SFX>100) SFX=100;
if(Voices<100) Voices+=10; if(Voices>100) Voices=100;
}
core->GetDictionary()->SetAt( "Volume Ambients", (ieDword)Ambients );
core->GetDictionary()->SetAt( "Volume Movie", Movie );
core->GetDictionary()->SetAt( "Volume Music", Music );
core->GetDictionary()->SetAt( "Volume SFX", SFX );
core->GetDictionary()->SetAt( "Volume Voices", Voices );
core->GetAudioDrv()->UpdateVolume();
break;
}
#else
(void)Key; // unused, fool the compiler
#endif
}
/** Key Release Event */
void Control::OnKeyRelease(unsigned char /*Key*/, unsigned short /*Mod*/)
{
//printf( "OnKeyRelease: CtrlID = 0x%08X, Key = %c (0x%02hX)\n", (unsigned int) ControlID, Key, Key );
}
/** Mouse Enter Event */
void Control::OnMouseEnter(unsigned short /*x*/, unsigned short /*y*/)
{
// printf("OnMouseEnter: CtrlID = 0x%08X, x = %hd, y = %hd\n", (unsigned int) ControlID, x, y);
}
/** Mouse Leave Event */
void Control::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
{
// printf("OnMouseLeave: CtrlID = 0x%08X, x = %hd, y = %hd\n", (unsigned int) ControlID, x, y);
}
/** Mouse Over Event */
void Control::OnMouseOver(unsigned short /*x*/, unsigned short /*y*/)
{
//printf("OnMouseOver: CtrlID = 0x%08X, x = %hd, y = %hd\n", (unsigned int) ControlID, x, y);
}
/** Mouse Button Down */
void Control::OnMouseDown(unsigned short x, unsigned short y,
unsigned short Button, unsigned short Mod)
{
if (Button == GEM_MB_SCRLUP || Button == GEM_MB_SCRLDOWN) {
Control *ctrl = Owner->GetScrollControl();
if (ctrl && (ctrl!=this)) {
ctrl->OnMouseDown(x,y,Button,Mod);
}
}
}
/** Mouse Button Up */
void Control::OnMouseUp(unsigned short /*x*/, unsigned short /*y*/,
unsigned short /*Button*/, unsigned short /*Mod*/)
{
//printf("OnMouseUp: CtrlID = 0x%08X, x = %hd, y = %hd, Button = %d, Mos = %hd\n", (unsigned int) ControlID, x, y, Button, Mod);
}
/** Special Key Press */
void Control::OnSpecialKeyPress(unsigned char Key)
{
if (Key == GEM_UP || Key == GEM_DOWN) {
Control *ctrl = Owner->GetScrollControl();
if (ctrl && (ctrl!=this)) {
ctrl->OnSpecialKeyPress(Key);
}
}
}
/** Sets the Display Flags */
int Control::SetFlags(int arg_flags, int opcode)
{
if ((arg_flags >>24) != ControlType)
return -2;
switch (opcode) {
case BM_SET:
Flags = arg_flags; //set
break;
case BM_AND:
Flags &= arg_flags;
break;
case BM_OR:
Flags |= arg_flags; //turn on
break;
case BM_XOR:
Flags ^= arg_flags;
break;
case BM_NAND:
Flags &= ~arg_flags;//turn off
break;
default:
return -1;
}
Changed = true;
Owner->Invalidate();
return 0;
}
void Control::SetAnimPicture(Sprite2D* newpic)
{
core->GetVideoDriver()->FreeSprite(AnimPicture);
AnimPicture = newpic;
//apparently this is needed too, so the artifacts are not visible
if (Owner->Visible==WINDOW_VISIBLE) {
Changed = true;
Owner->InvalidateForControl(this);
}
}
/** Sets the Scroll Bar Pointer. If 'ptr' is NULL no Scroll Bar will be linked
to this Control. */
int Control::SetScrollBar(Control* ptr)
{
if (ptr && (ptr->ControlType!=IE_GUI_SCROLLBAR)) {
ptr = NULL;
printMessage("Control","Attached control is not a ScrollBar!\n",YELLOW);
return -1;
}
sb = ptr;
Changed = true;
if (ptr) return 1;
return 0;
}

View File

@@ -0,0 +1,149 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Control.h
* Declares Control, root class for all widgets except of windows
*/
#ifndef CONTROL_H
#define CONTROL_H
#define IE_GUI_BUTTON 0
#define IE_GUI_PROGRESSBAR 1 //gemrb extension
#define IE_GUI_SLIDER 2
#define IE_GUI_EDIT 3
#define IE_GUI_TEXTAREA 5
#define IE_GUI_LABEL 6
#define IE_GUI_SCROLLBAR 7
#define IE_GUI_WORLDMAP 8 // gemrb extension
#define IE_GUI_MAP 9 // gemrb extension
#define IE_GUI_GAMECONTROL 128
#define IE_GUI_INVALID 255
#define IE_GUI_CONTROL_FOCUSED 0x80
//this is in the control ID
#define IGNORE_CONTROL 0x10000000
#include "RGBAColor.h"
#include "exports.h"
#include "ie_types.h"
#include "win32def.h"
#include "Callback.h"
class ControlAnimation;
class Sprite2D;
class Window;
/**
* @class Control
* Basic Control Object, also called widget or GUI element. Parent class for Labels, Buttons, etc.
* Every GUI element except of a Window is a descendant of this class.
*/
class GEM_EXPORT Control {
public:
Control();
virtual ~Control();
/** Draws the Control on the Output Display */
virtual void Draw(unsigned short x, unsigned short y) = 0;
/** Sets the Text of the current control */
virtual int SetText(const char* string, int pos = 0) = 0;
/** Sets the Tooltip text of the current control */
int SetTooltip(const char* string);
/** Displays the tooltip text, Worldmap handles this differently */
virtual void DisplayTooltip();
/** Variable length is 40-1 (zero terminator) */
char VarName[MAX_VARIABLE_LENGTH];
/** the value of the control to add to the variable */
ieDword Value;
/** various flags based on the control type */
ieDword Flags;
ControlAnimation* animation;
Sprite2D* AnimPicture;
public: // Public attributes
/** Defines the Control ID Number used for GUI Scripting */
ieDword ControlID;
/** X position of control relative to containing window */
ieWord XPos;
/** Y position of control relative to containing window */
ieWord YPos;
/** Width of control */
ieWord Width;
/** Height of control */
ieWord Height;
/** Type of control */
ieByte ControlType;
/** Text to display as a tooltip when the mouse cursor hovers
* for some time over the control */
char* Tooltip;
/** Focused Control */
bool hasFocus;
/** If true, control is redrawn during next call to gc->DrawWindows.
* Then it's set back to false. */
bool Changed;
/** True if we are currently in an event handler */
bool InHandler;
/** Owner Window */
Window* Owner;
/** Attached Scroll Bar Pointer*/
Control* sb;
public: //Events
/** Reset/init event handler */
void ResetEventHandler(EventHandler handler);
/** Returns the Owner */
Window *GetOwner() const { return Owner; }
/** Set the Flags */
int SetFlags(int arg_flags, int opcode);
/** Set handler for specified event. Override in child classes */
virtual bool SetEvent(int eventType, EventHandler handler) = 0;
/** Run specified handler, it may return error code */
int RunEventHandler(EventHandler handler);
/** Key Press Event */
virtual void OnKeyPress(unsigned char Key, unsigned short Mod);
/** Key Release Event */
virtual void OnKeyRelease(unsigned char Key, unsigned short Mod);
/** Mouse Enter Event */
virtual void OnMouseEnter(unsigned short x, unsigned short y);
/** Mouse Leave Event */
virtual void OnMouseLeave(unsigned short x, unsigned short y);
/** Mouse Over Event */
virtual void OnMouseOver(unsigned short x, unsigned short y);
/** Mouse Button Down */
virtual void OnMouseDown(unsigned short x, unsigned short y,
unsigned short Button, unsigned short Mod);
/** Mouse Button Up */
virtual void OnMouseUp(unsigned short x, unsigned short y,
unsigned short Button, unsigned short Mod);
/** Special Key Press */
virtual void OnSpecialKeyPress(unsigned char Key);
virtual bool IsPixelTransparent(unsigned short /*x*/, unsigned short /*y*/) {
return false;
}
/** Sets the animation picture ref */
void SetAnimPicture(Sprite2D* Picture);
/** Sets the Scroll Bar Pointer */
int SetScrollBar(Control* ptr);
};
#endif

View File

@@ -0,0 +1,439 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/EventMgr.h"
#include "GUI/GameControl.h"
#include "win32def.h"
#include "Interface.h"
#include "Video.h"
EventMgr::EventMgr(void)
{
last_win_focused = NULL;
// Last window focused for mouse events (eg, with a click). Used to determine MouseUp events
last_win_mousefocused = NULL;
// Last window we were over. Used to determine MouseEnter and MouseLeave events
last_win_over = NULL;
MButtons = 0;
dc_x = 0;
dc_y = 0;
dc_time = 0;
dc_delay = 250;
rk_delay = 250;
rk_flags = GEM_RK_DISABLE;
}
EventMgr::~EventMgr(void)
{
}
void EventMgr::SetOnTop(int Index)
{
std::vector< int>::iterator t;
for (t = topwin.begin(); t != topwin.end(); ++t) {
if (( *t ) == Index) {
topwin.erase( t );
break;
}
}
if (topwin.size() != 0) {
topwin.insert( topwin.begin(), Index );
} else {
topwin.push_back( Index );
}
}
void EventMgr::SetDefaultFocus(Window *win)
{
if (!last_win_focused) {
last_win_focused = win;
last_win_focused->SetFocused(last_win_focused->GetControl(0));
}
last_win_over = NULL;
}
/** Adds a Window to the Event Manager */
void EventMgr::AddWindow(Window* win)
{
unsigned int i;
if (win == NULL) {
return;
}
bool found = false;
for (i = 0; i < windows.size(); i++) {
if (windows[i] == win) {
goto ok;
}
if(windows[i]==NULL) {
windows[i] = win;
ok:
SetOnTop( i );
found = true;
break;
}
}
if (!found) {
windows.push_back( win );
if (windows.size() == 1)
topwin.push_back( 0 );
else
SetOnTop( ( int ) windows.size() - 1 );
}
SetDefaultFocus(win);
}
/** Frees and Removes all the Windows in the Array */
void EventMgr::Clear()
{
topwin.clear();
windows.clear();
last_win_focused = NULL;
last_win_mousefocused = NULL;
last_win_over = NULL;
}
/** Remove a Window from the array */
void EventMgr::DelWindow(Window *win)
//unsigned short WindowID, const char *WindowPack)
{
if (last_win_focused == win) {
last_win_focused = NULL;
}
if (last_win_mousefocused == win) {
last_win_mousefocused = NULL;
}
if (last_win_over == win) {
last_win_over = NULL;
}
if (windows.size() == 0) {
return;
}
int pos = -1;
std::vector< Window*>::iterator m;
for (m = windows.begin(); m != windows.end(); ++m) {
pos++;
if ( (*m) == win) {
(*m) = NULL;
std::vector< int>::iterator t;
for (t = topwin.begin(); t != topwin.end(); ++t) {
if ( (*t) == pos) {
topwin.erase( t );
return;
}
}
printMessage("EventManager","Couldn't find window",YELLOW);
}
}
}
/** BroadCast Mouse Move Event */
void EventMgr::MouseMove(unsigned short x, unsigned short y)
{
if (windows.size() == 0) {
return;
}
if (!last_win_focused) {
return;
}
GameControl *gc = core->GetGameControl();
if (gc) {
// for scrolling
gc->OnGlobalMouseMove(x, y);
}
std::vector< int>::iterator t;
std::vector< Window*>::iterator m;
for (t = topwin.begin(); t != topwin.end(); ++t) {
m = windows.begin();
m += ( *t );
Window *win = *m;
if (win == NULL)
continue;
if (!win->Visible)
continue;
if (( win->XPos <= x ) && ( win->YPos <= y )) {
//Maybe we are on the window, let's check
if (( win->XPos + win->Width >= x ) &&
( win->YPos + win->Height >= y )) {
//Yes, we are on the Window
//Let's check if we have a Control under the Mouse Pointer
Control* ctrl = win->GetControl( x, y, true );
//look for the low priority flagged controls (mostly static labels)
if (ctrl == NULL) {
ctrl = win->GetControl( x, y, false );
}
if (win != last_win_over || ctrl != win->GetOver()) {
// Remove tooltip if mouse moved to different control
core->DisplayTooltip( 0, 0, NULL );
if (last_win_over) {
last_win_over->OnMouseLeave( x, y );
}
last_win_over = win;
win->OnMouseEnter( x, y, ctrl );
}
if (ctrl != NULL) {
win->OnMouseOver( x, y );
}
RefreshCursor(win->Cursor);
return;
}
}
//stop going further
if (( *m )->Visible == WINDOW_FRONT)
break;
}
core->DisplayTooltip( 0, 0, NULL );
}
void EventMgr::RefreshCursor(int idx)
{
Video *video = core->GetVideoDriver();
if (idx&IE_CURSOR_GRAY) {
video->SetMouseGrayed(true);
} else {
video->SetMouseGrayed(false);
}
idx &= IE_CURSOR_MASK;
video->SetCursor( core->Cursors[idx], core->Cursors[idx ^ 1] );
}
bool EventMgr::ClickMatch(unsigned short x, unsigned short y, unsigned long thisTime)
{
if (dc_x+10<x) return false;
if (dc_x>x+10) return false;
if (dc_y+10<y) return false;
if (dc_y>y+10) return false;
if (dc_time<thisTime) return false;
return true;
}
/** BroadCast Mouse Move Event */
void EventMgr::MouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod)
{
std::vector< int>::iterator t;
std::vector< Window*>::iterator m;
Control *ctrl;
unsigned long thisTime;
GetTime( thisTime );
if (ClickMatch(x, y, thisTime)) {
Button |= GEM_MB_DOUBLECLICK;
dc_x = 0;
dc_y = 0;
dc_time = 0;
} else {
dc_x = x;
dc_y = y;
dc_time = thisTime+dc_delay;
}
MButtons |= Button;
for (t = topwin.begin(); t != topwin.end(); ++t) {
m = windows.begin();
m += ( *t );
if (( *m ) == NULL)
continue;
if (!( *m )->Visible)
continue;
if (( ( *m )->XPos <= x ) && ( ( *m )->YPos <= y )) {
//Maybe we are on the window, let's check
if (( ( *m )->XPos + ( *m )->Width >= x ) &&
( ( *m )->YPos + ( *m )->Height >= y )) {
//Yes, we are on the Window
//Let's check if we have a Control under the Mouse Pointer
ctrl = ( *m )->GetControl( x, y, true );
if (!ctrl) {
ctrl = ( *m )->GetControl( x, y, false);
}
last_win_mousefocused = *m;
if (ctrl != NULL) {
last_win_mousefocused->SetMouseFocused( ctrl );
ctrl->OnMouseDown( x - last_win_mousefocused->XPos - ctrl->XPos, y - last_win_mousefocused->YPos - ctrl->YPos, Button, Mod );
return;
}
}
}
if (( *m )->Visible == WINDOW_FRONT) //stop looking further
break;
}
if ((Button == GEM_MB_SCRLUP || Button == GEM_MB_SCRLDOWN) && last_win_mousefocused) {
ctrl = last_win_mousefocused->GetScrollControl();
if (ctrl) {
ctrl->OnMouseDown( x - last_win_mousefocused->XPos - ctrl->XPos, y - last_win_mousefocused->YPos - ctrl->YPos, Button, Mod );
}
}
if (last_win_mousefocused) {
last_win_mousefocused->SetMouseFocused(NULL);
}
}
/** BroadCast Mouse Up Event */
void EventMgr::MouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod)
{
MButtons &= ~Button;
if (last_win_mousefocused == NULL) return;
Control *last_ctrl_mousefocused = last_win_mousefocused->GetMouseFocus();
if (last_ctrl_mousefocused == NULL) return;
last_ctrl_mousefocused->OnMouseUp( x - last_win_mousefocused->XPos - last_ctrl_mousefocused->XPos,
y - last_win_mousefocused->YPos - last_ctrl_mousefocused->YPos, Button, Mod );
}
/** BroadCast Mouse Idle Event */
void EventMgr::MouseIdle(unsigned long /*time*/)
{
if (last_win_over == NULL) return;
Control *ctrl = last_win_over->GetOver();
if (ctrl == NULL) return;
ctrl->DisplayTooltip();
}
/** BroadCast Key Press Event */
void EventMgr::KeyPress(unsigned char Key, unsigned short Mod)
{
if (last_win_focused == NULL) return;
Control *ctrl = last_win_focused->GetFocus();
if (ctrl == NULL) return;
ctrl->OnKeyPress( Key, Mod );
}
/** BroadCast Key Release Event */
void EventMgr::KeyRelease(unsigned char Key, unsigned short Mod)
{
if (last_win_focused == NULL) return;
Control *ctrl = last_win_focused->GetFocus();
if (Key == GEM_GRAB) {
core->GetVideoDriver()->ToggleGrabInput();
return;
}
if (ctrl == NULL) return;
ctrl->OnKeyRelease( Key, Mod );
}
/** Special Key Press Event */
void EventMgr::OnSpecialKeyPress(unsigned char Key)
{
if (!last_win_focused) {
return;
}
Control *ctrl = NULL;
// tab shows tooltips
if (Key == GEM_TAB) {
if (last_win_over != NULL) {
Control *ctrl = last_win_over->GetOver();
if (ctrl != NULL) {
ctrl->DisplayTooltip();
}
}
}
//the default control will get only GEM_RETURN
else if (Key == GEM_RETURN) {
ctrl = last_win_focused->GetDefaultControl(0);
}
//the default cancel control will get only GEM_ESCAPE
else if (Key == GEM_ESCAPE) {
ctrl = last_win_focused->GetDefaultControl(1);
}
//if there was no default button set, then the current focus will get it
if (!ctrl) {
ctrl = last_win_focused->GetFocus();
}
//if one is under focus, use the default scroll focus
if (!ctrl) {
if (Key == GEM_UP || Key == GEM_DOWN) {
ctrl = last_win_focused->GetScrollControl();
}
}
if (ctrl) {
switch (ctrl->ControlType) {
//scrollbars will receive only mousewheel events
case IE_GUI_SCROLLBAR:
if (Key != GEM_UP && Key != GEM_DOWN) {
return;
}
break;
//buttons will receive only GEM_RETURN
case IE_GUI_BUTTON:
if (Key != GEM_RETURN && Key!=GEM_ESCAPE) {
return;
}
break;
case IE_GUI_GAMECONTROL:
//gamecontrols will receive all special keys
break;
case IE_GUI_EDIT:
case IE_GUI_TEXTAREA:
//editboxes and textareas will receive all special keys
break;
default:
//other controls don't receive any
return;
}
ctrl->OnSpecialKeyPress( Key );
}
}
void EventMgr::SetFocused(Window *win, Control *ctrl)
{
last_win_focused = win;
last_win_focused->SetFocused(ctrl);
//this is to refresh changing mouse cursors should the focus change)
int x,y;
core->GetVideoDriver()->GetMousePos(x,y);
MouseMove((unsigned short) x, (unsigned short) y);
}
void EventMgr::SetDCDelay(unsigned long t)
{
dc_delay = t;
}
void EventMgr::SetRKDelay(unsigned long t)
{
rk_delay = t;
}
unsigned long EventMgr::GetRKDelay()
{
if (rk_flags&GEM_RK_DISABLE) return (unsigned long) ~0;
if (rk_flags&GEM_RK_DOUBLESPEED) return rk_delay/2;
if (rk_flags&GEM_RK_QUADRUPLESPEED) return rk_delay/4;
return rk_delay;
}
unsigned long EventMgr::SetRKFlags(unsigned long arg, unsigned int op)
{
unsigned long tmp = rk_flags;
switch (op) {
case BM_SET: tmp = arg; break;
case BM_OR: tmp |= arg; break;
case BM_NAND: tmp &= ~arg; break;
case BM_XOR: tmp ^= arg; break;
case BM_AND: tmp &= arg; break;
default: tmp = 0; break;
}
rk_flags=tmp;
return rk_flags;
}

View File

@@ -0,0 +1,142 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file EventMgr.h
* Declares EventMgr, class distributing events from input devices to GUI windows
* @author The GemRB Project
*/
#ifndef EVENTMGR_H
#define EVENTMGR_H
#include "GUI/Control.h"
#include "exports.h"
#include "WindowMgr.h"
#include <vector>
#define GEM_LEFT 0x81
#define GEM_RIGHT 0x82
#define GEM_UP 0x83
#define GEM_DOWN 0x84
#define GEM_DELETE 0x85
#define GEM_RETURN 0x86
#define GEM_BACKSP 0x87
#define GEM_TAB 0x88
#define GEM_ALT 0x89
#define GEM_HOME 0x8a
#define GEM_END 0x8b
#define GEM_ESCAPE 0x8c
#define GEM_PGUP 0x8d
#define GEM_PGDOWN 0x8e
#define GEM_GRAB 0x8f
#define GEM_MOD_SHIFT 1
#define GEM_MOD_CTRL 2
#define GEM_MOD_ALT 4
#define GEM_MOUSEOUT 128
// Mouse buttons
#define GEM_MB_ACTION 1
#define GEM_MB_MENU 4
#define GEM_MB_SCRLUP 8
#define GEM_MB_SCRLDOWN 16
#define GEM_MB_NORMAL 255
#define GEM_MB_DOUBLECLICK 256
#define GEM_RK_DOUBLESPEED 1
#define GEM_RK_DISABLE 2
#define GEM_RK_QUADRUPLESPEED 4
/**
* @class EventMgr
* Class distributing events from input devices to GUI windows.
* The events are pumped into instance of this class from a Video driver plugin
*/
class GEM_EXPORT EventMgr {
private:
std::vector< Window*> windows;
std::vector< int> topwin;
unsigned short dc_x, dc_y;
unsigned long dc_time, dc_delay;
unsigned long rk_delay, rk_flags;
public:
EventMgr(void);
~EventMgr(void);
/** Adds a Window to the Event Manager */
void AddWindow(Window* win);
/** Removes a Window from the Event chain */
//void DelWindow(unsigned short WindowID, const char *WindowPack);
void DelWindow(Window* win);
/** Frees and Removes all the Windows in the Array */
void Clear();
/** Call this to change the cursor (moving over windows will change it back) */
void RefreshCursor(int idx);
/** BroadCast Mouse Move Event */
void MouseMove(unsigned short x, unsigned short y);
/** BroadCast Mouse Move Event */
void MouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** BroadCast Mouse Move Event */
void MouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** BroadCast Mouse Idle Event */
void MouseIdle(unsigned long time);
/** BroadCast Key Press Event */
void KeyPress(unsigned char Key, unsigned short Mod);
/** BroadCast Key Release Event */
void KeyRelease(unsigned char Key, unsigned short Mod);
/** Special Ket Press Event */
void OnSpecialKeyPress(unsigned char Key);
/** Sets focus to the control of the window */
void SetFocused(Window *win, Control *ctrl);
/** Sets mouse event focus to the control of the window */
void SetMouseFocused(Window *win, Control *ctrl);
/** Sets the maximum accepted doubleclick delay */
void SetDCDelay(unsigned long t);
void SetRKDelay(unsigned long t);
unsigned long GetRKDelay();
unsigned long SetRKFlags(unsigned long arg, unsigned int op);
/** Mask of which Mouse Buttons are pressed */
unsigned char MButtons;
private:
/** Last Window focused */
Window* last_win_focused;
/** Last Window mouse event focused */
Window* last_win_mousefocused;
/** Last Window under Mouse Pointer*/
Window* last_win_over;
/** Sets a Window on the Top of the Window Queue */
void SetDefaultFocus(Window *win);
void SetOnTop(int Index);
bool ClickMatch(unsigned short x, unsigned short y, unsigned long thisTime);
};
#endif // ! EVENTMGR_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,252 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
/**
* @file GameControl.h
* Declares GameControl widget which is responsible for displaying areas,
* interacting with PCs, NPCs and the rest of the game world.
* @author The GemRB Project
*/
#ifndef GAMECONTROL_H
#define GAMECONTROL_H
#include "GUI/Control.h"
#include "exports.h"
#include "Dialog.h"
#include "Interface.h"
#include "Map.h"
class GameControl;
class Window;
class DialogHandler;
//dialog flags
#define DF_IN_DIALOG 1
#define DF_TALKCOUNT 2
#define DF_UNBREAKABLE 4
#define DF_FREEZE_SCRIPTS 8
#define DF_INTERACT 16
#define DF_IN_CONTAINER 32
#define DF_OPENCONTINUEWINDOW 64
#define DF_OPENENDWINDOW 128
//screen flags
// !!! Keep these synchronized with GUIDefines.py !!!
#define SF_DISABLEMOUSE 1 //no mouse cursor
#define SF_CENTERONACTOR 2 //
#define SF_ALWAYSCENTER 4
#define SF_GUIENABLED 8 //
#define SF_LOCKSCROLL 16 //don't scroll
#define SF_CUTSCENE 32 //don't push new actions onto the action queue
#define SF_TRACKING 64 //draw blue arrows on the edge for creatures
// target modes and types
// !!! Keep these synchronized with GUIDefines.py !!!
#define TARGET_MODE_NONE 0
#define TARGET_MODE_TALK 1
#define TARGET_MODE_ATTACK 2
#define TARGET_MODE_CAST 3
#define TARGET_MODE_DEFEND 4
#define TARGET_MODE_PICK 5
/*
#define TARGET_SELECT 16
#define TARGET_NO_DEAD 32
#define TARGET_POINT 64
#define TARGET_NO_HIDDEN 128
#define TARGET_TYPE_NONE 0x000
#define TARGET_NO_ALLY 0x100 //0x100
#define TARGET_NO_ENEMY 0x200 //0x200
#define TARGET_NO_NEUTRAL 0x400
#define TARGET_NO_SELF 0x800
#define TARGET_TYPE_ALL 0 //(TARGET_TYPE_ALLY | TARGET_TYPE_ENEMY | TARGET_TYPE_NEUTRAL)
*/
/**
* @class GameControl
* Widget displaying areas, where most of the game 'happens'.
* It allows for interacting with PCs, NPCs and the rest of the world.
* It's also a very core part of GemRB, as some processes are driven from it.
* It's always assigned Control index 0.
*/
class GEM_EXPORT GameControl : public Control {
public:
GameControl(void);
~GameControl(void);
public:
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Sets the Text of the current control */
int SetText(const char* string, int pos = 0);
/** Sets multiple quicksaves flag*/
static void MultipleQuickSaves(int arg);
void SetTracker(Actor *actor, ieDword dist);
private:
ieDword lastActorID;
ieDword trackerID;
ieDword distance; //tracking distance
std::vector< Actor*> highlighted;
bool DrawSelectionRect;
bool MouseIsDown;
bool DoubleClick;
Region SelectionRect;
short StartX, StartY;
//int action;
public:
Door* overDoor;
Container* overContainer;
InfoPoint* overInfoPoint;
// allow targetting allies, enemies and/or neutrals (bitmask)
int target_types;
private:
// currently selected targetting type, such as talk, attack, cast, ...
// private to enforce proper cursor changes
int target_mode;
unsigned char lastCursor;
short moveX, moveY;
int numScrollCursor;
bool scrolling;
unsigned short lastMouseX, lastMouseY;
int DebugFlags;
Point pfs;
PathNode* drawPath;
unsigned long AIUpdateCounter;
int ScreenFlags;
int DialogueFlags;
char *DisplayText;
unsigned int DisplayTextTime;
bool EnableRunning;
public: //Events
/** Key Press Event */
void OnKeyPress(unsigned char Key, unsigned short Mod);
/** Key Release Event */
void OnKeyRelease(unsigned char Key, unsigned short Mod);
/** Mouse Over Event */
void OnMouseOver(unsigned short x, unsigned short y);
/** Global Mouse Move Event */
void OnGlobalMouseMove(unsigned short x, unsigned short y);
/** Mouse Button Down */
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Special Key Press */
void OnSpecialKeyPress(unsigned char Key);
void DisplayTooltip();
void UpdateScrolling();
void SetTargetMode(int mode);
int GetTargetMode() { return target_mode; }
void SetScreenFlags(int value, int mode);
void SetDialogueFlags(int value, int mode);
int GetScreenFlags() { return ScreenFlags; }
int GetDialogueFlags() { return DialogueFlags; }
/** this function is called from the area when autosave is needed */
void AutoSave();
void SetDisplayText(char *text, unsigned int time);
void SetDisplayText(ieStrRef text, unsigned int time);
/* centers viewport to the points specified */
void Center(unsigned short x, unsigned short y);
private:
/** this function is called when the user presses 'q' (or equivalent) */
void QuickSave();
/** this function safely retrieves an Actor by ID */
Actor *GetActorByGlobalID(ieDword ID);
void CalculateSelection(const Point &p);
void ResizeDel(Window* win, int type);
void ResizeAdd(Window* win, int type);
void HandleWindowHide(const char *WindowName, const char *WindowPosition);
void HandleWindowReveal(const char *WindowName, const char *WindowPosition);
void ReadFormations();
/** Draws an arrow on the edge of the screen based on the point (points at offscreen actors) */
void DrawArrowMarker(const Region &screen, Point p, const Region &viewport);
private:
unsigned char LeftCount, BottomCount, RightCount, TopCount;
Actor *user; //the user of item or spell
public:
DialogHandler *dialoghandler;
//using spell or item
int spellOrItem; // -1 = item, otherwise the spell type
//the user of spell or item
Actor *spellUser;
int spellSlot, spellIndex; //or inventorySlot/itemHeader
int spellCount; //multiple targeting
public:
/** Selects one or all PC */
void SelectActor(int whom, int type = -1);
void SetLastActor(Actor *actor, Actor *prevActor);
void SetCutSceneMode(bool active);
int HideGUI();
int UnhideGUI();
void TryToAttack(Actor *source, Actor *target);
void TryToBash(Actor *source, Scriptable *tgt);
void TryToCast(Actor *source, const Point &p);
void TryToCast(Actor *source, Actor *target);
void TryToDefend(Actor *source, Actor *target);
void TryToTalk(Actor *source, Actor *target);
void TryToPick(Actor *source, Actor *tgt);
void TryToPick(Actor *source, Door *tgt);
void TryToPick(Actor *source, Container *tgt);
void TryToDisarm(Actor *source, InfoPoint *tgt);
void PerformActionOn(Actor *actor);
void ResetTargetMode();
// returns the default cursor fitting the targeting mode
int GetDefaultCursor() const;
//containers
int GetCursorOverContainer(Container *overContainer) const;
void HandleContainer(Container *container, Actor *actor);
//doors
int GetCursorOverDoor(Door *overDoor) const;
void HandleDoor(Door *door, Actor *actor);
//infopoints
int GetCursorOverInfoPoint(InfoPoint *overInfoPoint) const;
bool HandleActiveRegion(InfoPoint *trap, Actor *actor, Point &p);
Point GetFormationOffset(ieDword formation, ieDword pos);
void MoveToPointFormation(Actor *actor, unsigned int pos, Point src, Point p);
/** calls MoveToPoint or RunToPoint */
void CreateMovement(Actor *actor, const Point &p);
/** Displays a string over an object */
void DisplayString(Scriptable* target);
/** Displays a string on screen */
void DisplayString(const Point &p, const char *Text);
Actor *GetLastActor();
/** changes map to the current PC */
void ChangeMap(Actor *pc, bool forced);
/** Returns game screenshot, with or without GUI controls */
Sprite2D* GetScreenshot( bool show_gui = 0 );
/** Returns current area preview for saving a game */
Sprite2D* GetPreview();
/** Returns PC portrait for a currently running game */
Sprite2D* GetPortraitPreview(int pcslot);
/** Sets up targeting with spells or items */
void SetupItemUse(int slot, int header, Actor *actor, int targettype, int cnt);
/** Page is the spell type + spell level info */
void SetupCasting(int type, int level, int slot, Actor *actor, int targettype, int cnt);
bool SetEvent(int eventType, EventHandler handler);
};
#endif

View File

@@ -0,0 +1,152 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Label.h"
#include "win32def.h"
#include "GameData.h"
#include "Interface.h"
#include "Palette.h"
#include "Variables.h"
#include "Video.h"
Label::Label(Font* font)
{
this->font = font;
Buffer = NULL;
useRGB = false;
ResetEventHandler( LabelOnPress );
Alignment = IE_FONT_ALIGN_CENTER|IE_FONT_ALIGN_MIDDLE;
palette = NULL;
}
Label::~Label()
{
gamedata->FreePalette( palette );
if (Buffer) {
free( Buffer );
}
}
/** Draws the Control on the Output Display */
void Label::Draw(unsigned short x, unsigned short y)
{
if (!Changed && !(Owner->Flags&WF_FLOAT)) {
return;
}
Changed = false;
if (XPos == 65535) {
return;
}
if (font && Buffer) {
font->Print( Region( this->XPos + x, this->YPos + y,
this->Width, this->Height ), ( unsigned char * ) Buffer,
useRGB?palette:NULL,
Alignment | IE_FONT_SINGLE_LINE, true );
}
if (AnimPicture) {
int xOffs = ( Width / 2 ) - ( AnimPicture->Width / 2 );
int yOffs = ( Height / 2 ) - ( AnimPicture->Height / 2 );
Region r( x + XPos + xOffs, y + YPos + yOffs, (int)(AnimPicture->Width), AnimPicture->Height );
core->GetVideoDriver()->BlitSprite( AnimPicture, x + XPos + xOffs, y + YPos + yOffs, true, &r );
}
}
/** This function sets the actual Label Text */
int Label::SetText(const char* string, int /*pos*/)
{
if (Buffer )
free( Buffer );
if (Alignment == IE_FONT_ALIGN_CENTER) {
if (core->HasFeature( GF_LOWER_LABEL_TEXT )) {
int len = strlen(string);
Buffer = (char *) malloc( len+1 );
strnlwrcpy( Buffer, string, len );
}
else {
Buffer = strdup( string );
}
}
else {
Buffer = strdup( string );
}
if (!palette) {
Color white = {0xff, 0xff, 0xff, 0x00}, black = {0x00, 0x00, 0x00, 0x00};
SetColor(white, black);
}
if (Owner) {
Owner->Invalidate();
}
return 0;
}
/** Sets the Foreground Font Color */
void Label::SetColor(Color col, Color bac)
{
gamedata->FreePalette( palette );
palette = core->CreatePalette( col, bac );
Changed = true;
}
void Label::SetAlignment(unsigned char Alignment)
{
this->Alignment = Alignment;
if (Alignment == IE_FONT_ALIGN_CENTER) {
if (core->HasFeature( GF_LOWER_LABEL_TEXT )) {
strlwr( Buffer );
}
}
Changed = true;
}
void Label::OnMouseUp(unsigned short x, unsigned short y,
unsigned short /*Button*/, unsigned short /*Mod*/)
{
//printf( "Label::OnMouseUp\n" );
if (( x <= Width ) && ( y <= Height )) {
if (VarName[0] != 0) {
core->GetDictionary()->SetAt( VarName, Value );
}
if (LabelOnPress) {
RunEventHandler( LabelOnPress );
}
}
}
bool Label::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_LABEL_ON_PRESS:
LabelOnPress = handler;
break;
default:
return false;
}
return true;
}
/** Simply returns the pointer to the text, don't modify it! */
const char* Label::QueryText() const
{
return ( const char * ) Buffer;
}

View File

@@ -0,0 +1,83 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Label.h
* Declares Label widget for displaying static texts
* @author GemRB Developement Team
*/
#ifndef LABEL_H
#define LABEL_H
#include "GUI/Control.h"
#include "RGBAColor.h"
#include "exports.h"
#include "Font.h"
class Palette;
// !!! Keep these synchronized with GUIDefines.py !!!
#define IE_GUI_LABEL_ON_PRESS 0x06000000
/**
* @class Label
* Label widget for displaying static texts in the GUI
*/
class GEM_EXPORT Label : public Control {
public:
Label(Font* font);
~Label();
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** This function sets the actual Label Text */
int SetText(const char* string, int pos = 0);
/** Sets the Foreground Font Color */
void SetColor(Color col, Color bac);
/** Sets the Alignment of Text */
void SetAlignment(unsigned char Alignment);
/** Simply returns the pointer to the text, don't modify it! */
const char* QueryText() const;
/** Mouse Button Down */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
/** Use the RGB Color for the Font */
bool useRGB;
/** OnPress Scripted Event Function Name */
EventHandler LabelOnPress;
private: // Private attributes
/** Text String Buffer */
char* Buffer;
/** Font for Text Writing */
Font* font;
/** Foreground & Background Colors */
Palette* palette;
/** Alignment Variable */
unsigned char Alignment;
};
#endif

View File

@@ -0,0 +1,540 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "GUI/MapControl.h"
#include "win32def.h"
#include "Game.h"
#include "Interface.h"
#include "Map.h"
#include "Video.h"
#define MAP_NO_NOTES 0
#define MAP_VIEW_NOTES 1
#define MAP_SET_NOTE 2
#define MAP_REVEAL 3
// Ratio between pixel sizes of an Area (Big map) and a Small map
static int MAP_DIV = 3;
static int MAP_MULT = 32;
typedef enum {black=0, gray, violet, green, orange, red, blue, darkblue, darkgreen} colorcode;
Color colors[]={
{ 0x00, 0x00, 0x00, 0xff }, //black
{ 0x60, 0x60, 0x60, 0xff }, //gray
{ 0xa0, 0x00, 0xa0, 0xff }, //violet
{ 0x00, 0xff, 0x00, 0xff }, //green
{ 0xff, 0xff, 0x00, 0xff }, //orange
{ 0xff, 0x00, 0x00, 0xff }, //red
{ 0x00, 0x00, 0xff, 0xff }, //blue
{ 0x00, 0x00, 0x80, 0xff }, //darkblue
{ 0x00, 0x80, 0x00, 0xff } //darkgreen
};
#define MAP_TO_SCREENX(x) (XWin + XPos + XCenter - ScrollX + (x))
#define MAP_TO_SCREENY(y) (YWin + YPos + YCenter - ScrollY + (y))
// Omit [XY]Pos, since these macros are used in OnMouseDown(x, y), and x, y is
// already relative to control [XY]Pos there
#define SCREEN_TO_MAPX(x) ((x) - XCenter + ScrollX)
#define SCREEN_TO_MAPY(y) ((y) - YCenter + ScrollY)
#define GAME_TO_SCREENX(x) MAP_TO_SCREENX((int)((x) * MAP_DIV / MAP_MULT))
#define GAME_TO_SCREENY(y) MAP_TO_SCREENY((int)((y) * MAP_DIV / MAP_MULT))
#define SCREEN_TO_GAMEX(x) (SCREEN_TO_MAPX(x) * MAP_MULT / MAP_DIV)
#define SCREEN_TO_GAMEY(y) (SCREEN_TO_MAPY(y) * MAP_MULT / MAP_DIV)
MapControl::MapControl(void)
{
if (core->HasFeature(GF_IWD_MAP_DIMENSIONS) ) {
MAP_DIV=4;
MAP_MULT=32;
} else {
MAP_DIV=3;
MAP_MULT=32;
}
LinkedLabel = NULL;
ScrollX = 0;
ScrollY = 0;
NotePosX = 0;
NotePosY = 0;
mouseIsDown = false;
mouseIsDragging = false;
Changed = true;
convertToGame = true;
memset(Flag,0,sizeof(Flag) );
// initialize var and event callback to no-ops
VarName[0] = 0;
ResetEventHandler( MapControlOnPress );
ResetEventHandler( MapControlOnRightPress );
ResetEventHandler( MapControlOnDoublePress );
MyMap = core->GetGame()->GetCurrentArea();
if (MyMap->SmallMap) {
MapMOS = MyMap->SmallMap;
MapMOS->acquire();
} else
MapMOS = NULL;
}
MapControl::~MapControl(void)
{
Video *video = core->GetVideoDriver();
if (MapMOS) {
video->FreeSprite(MapMOS);
}
for(int i=0;i<8;i++) {
if (Flag[i]) {
video->FreeSprite(Flag[i]);
}
}
}
// Draw fog on the small bitmap
void MapControl::DrawFog(unsigned short XWin, unsigned short YWin)
{
Video *video = core->GetVideoDriver();
Region old_clip;
video->GetClipRect(old_clip);
Region r( XWin + XPos, YWin + YPos, Width, Height );
video->SetClipRect(&r);
// FIXME: this is ugly, the knowledge of Map and ExploredMask
// sizes should be in Map.cpp
int w = MyMap->GetWidth() / 2;
int h = MyMap->GetHeight() / 2;
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Point p( (short) (MAP_MULT * x), (short) (MAP_MULT * y) );
bool visible = MyMap->IsVisible( p, true );
if (! visible) {
Region rgn = Region ( MAP_TO_SCREENX(MAP_DIV * x), MAP_TO_SCREENY(MAP_DIV * y), MAP_DIV, MAP_DIV );
video->DrawRect( rgn, colors[black] );
}
}
}
video->SetClipRect(&old_clip);
}
// To be called after changes in control's or screen geometry
void MapControl::Realize()
{
// FIXME: ugly!! How to get area size in pixels?
//Map *map = core->GetGame()->GetCurrentMap();
//MapWidth = map->GetWidth();
//MapHeight = map->GetHeight();
if (MapMOS) {
MapWidth = (short) MapMOS->Width;
MapHeight = (short) MapMOS->Height;
} else {
MapWidth = 0;
MapHeight = 0;
}
// FIXME: ugly hack! What is the actual viewport size?
ViewWidth = (short) (core->Width * MAP_DIV / MAP_MULT);
ViewHeight = (short) (core->Height * MAP_DIV / MAP_MULT);
XCenter = (short) (Width - MapWidth ) / 2;
YCenter = (short) (Height - MapHeight ) / 2;
if (XCenter < 0) XCenter = 0;
if (YCenter < 0) YCenter = 0;
}
void MapControl::RedrawMapControl(const char *VariableName, unsigned int Sum)
{
if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
return;
}
Value = Sum;
Changed = true;
}
/** Draws the Control on the Output Display */
void MapControl::Draw(unsigned short XWin, unsigned short YWin)
{
if (!Width || !Height) {
return;
}
if (Owner->Visible!=WINDOW_VISIBLE) {
return;
}
if (Changed) {
Realize();
Changed = false;
}
// we're going to paint over labels/etc, so they need to repaint!
bool seen_this = false;
unsigned int i;
for (i = 0; i < Owner->GetControlCount(); i++) {
Control *ctrl = Owner->GetControl(i);
if (!ctrl) continue;
// we could try working out which controls overlap,
// but the later controls are cheap to paint..
if (ctrl == this) { seen_this = true; continue; }
if (!seen_this) continue;
ctrl->Changed = true;
}
Video* video = core->GetVideoDriver();
Region r( XWin + XPos, YWin + YPos, Width, Height );
if (MapMOS) {
video->BlitSprite( MapMOS, MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r );
}
if (core->FogOfWar&FOG_DRAWFOG)
DrawFog(XWin, YWin);
Region vp = video->GetViewport();
vp.x = GAME_TO_SCREENX(vp.x);
vp.y = GAME_TO_SCREENY(vp.y);
vp.w = ViewWidth;
vp.h = ViewHeight;
video->DrawRect( vp, colors[green], false, false );
// Draw PCs' ellipses
Game *game = core->GetGame();
i = game->GetPartySize(true);
while (i--) {
Actor* actor = game->GetPC( i, true );
if (MyMap->HasActor(actor) ) {
video->DrawEllipse( (short) GAME_TO_SCREENX(actor->Pos.x), (short) GAME_TO_SCREENY(actor->Pos.y), 3, 2, actor->Selected ? colors[green] : colors[darkgreen], false );
}
}
// Draw Map notes, could be turned off in bg2
// we use the common control value to handle it, because then we
// don't need another interface
if (Value!=MAP_NO_NOTES) {
i = MyMap -> GetMapNoteCount();
while (i--) {
MapNote * mn = MyMap -> GetMapNote(i);
Sprite2D *anim = Flag[mn->color&7];
Point pos = mn->Pos;
if (convertToGame) {
vp.x = GAME_TO_SCREENX(mn->Pos.x);
vp.y = GAME_TO_SCREENY(mn->Pos.y);
} else { //pst style
vp.x = MAP_TO_SCREENX(mn->Pos.x);
vp.y = MAP_TO_SCREENY(mn->Pos.y);
pos.x = pos.x * MAP_MULT / MAP_DIV;
pos.y = pos.y * MAP_MULT / MAP_DIV;
}
//Skip unexplored map notes
bool visible = MyMap->IsVisible( pos, true );
if (!visible)
continue;
if (anim) {
video->BlitSprite( anim, vp.x - anim->Width/2, vp.y - anim->Height/2, true, &r );
} else {
video->DrawEllipse( (short) vp.x, (short) vp.y, 6, 5, colors[mn->color&7], false );
}
}
}
}
/** Key Press Event */
void MapControl::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
{
#ifdef ANDROID
switch(Key) {
case 'o':
case 'p':
Control::OnKeyPress(Key, 0);
break;
}
#else
(void)Key; // unused, fool the compiler
#endif
}
/** Key Release Event */
void MapControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
{
switch (Key) {
case '\t':
//not GEM_TAB
printf( "TAB released\n" );
return;
case 'f':
if (Mod & GEM_MOD_CTRL)
core->GetVideoDriver()->ToggleFullscreenMode();
break;
default:
break;
}
if (!core->CheatEnabled()) {
return;
}
}
/** Mouse Over Event */
void MapControl::OnMouseOver(unsigned short x, unsigned short y)
{
if (mouseIsDown) {
ScrollX -= x - lastMouseX;
ScrollY -= y - lastMouseY;
if (ScrollX > MapWidth - Width)
ScrollX = MapWidth - Width;
if (ScrollY > MapHeight - Height)
ScrollY = MapHeight - Height;
if (ScrollX < 0)
ScrollX = 0;
if (ScrollY < 0)
ScrollY = 0;
}
if (mouseIsDragging) {
ViewHandle(x,y);
}
lastMouseX = x;
lastMouseY = y;
switch (Value) {
case MAP_REVEAL: //for farsee effect
Owner->Cursor = IE_CURSOR_CAST;
break;
case MAP_SET_NOTE:
Owner->Cursor = IE_CURSOR_GRAB;
break;
default:
Owner->Cursor = IE_CURSOR_NORMAL;
break;
}
if (Value == MAP_VIEW_NOTES || Value == MAP_SET_NOTE || Value == MAP_REVEAL) {
Point mp;
unsigned int dist;
if (convertToGame) {
mp.x = (short) SCREEN_TO_GAMEX(x);
mp.y = (short) SCREEN_TO_GAMEY(y);
dist = 100;
} else {
mp.x = (short) SCREEN_TO_MAPX(x);
mp.y = (short) SCREEN_TO_MAPY(y);
dist = 16;
}
int i = MyMap -> GetMapNoteCount();
while (i--) {
MapNote * mn = MyMap -> GetMapNote(i);
if (Distance(mp, mn->Pos)<dist) {
if (LinkedLabel) {
LinkedLabel->SetText( mn->text );
}
NotePosX = mn->Pos.x;
NotePosY = mn->Pos.y;
return;
}
}
NotePosX = mp.x;
NotePosY = mp.y;
}
if (LinkedLabel) {
LinkedLabel->SetText( "" );
}
}
/** Mouse Leave Event */
void MapControl::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
{
Owner->Cursor = IE_CURSOR_NORMAL;
}
void MapControl::ClickHandle(unsigned short Button)
{
core->GetDictionary()->SetAt( "MapControlX", NotePosX );
core->GetDictionary()->SetAt( "MapControlY", NotePosY );
switch(Button&GEM_MB_NORMAL) {
case GEM_MB_ACTION:
if (Button&GEM_MB_DOUBLECLICK) {
RunEventHandler( MapControlOnDoublePress );
} else {
RunEventHandler( MapControlOnPress );
}
break;
case GEM_MB_MENU:
RunEventHandler( MapControlOnRightPress );
break;
default:
break;
}
}
void MapControl::ViewHandle(unsigned short x, unsigned short y)
{
short xp = (short) (SCREEN_TO_MAPX(x) - ViewWidth / 2);
short yp = (short) (SCREEN_TO_MAPY(y) - ViewHeight / 2);
if (xp + ViewWidth > MapWidth) xp = MapWidth - ViewWidth;
if (yp + ViewHeight > MapHeight) yp = MapHeight - ViewHeight;
if (xp < 0) xp = 0;
if (yp < 0) yp = 0;
// clear any previously scheduled moves and then do it asap, so it works while paused
unsigned int vpx = xp * MAP_MULT / MAP_DIV;
unsigned int vpy = yp * MAP_MULT / MAP_DIV;
core->timer->SetMoveViewPort( vpx, vpy, 0, false );
core->GetVideoDriver()->MoveViewportTo( vpx, vpy );
}
/** Mouse Button Down */
void MapControl::OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short /*Mod*/)
{
switch((unsigned char) Button) {
case GEM_MB_SCRLUP:
OnSpecialKeyPress(GEM_UP);
return;
case GEM_MB_SCRLDOWN:
OnSpecialKeyPress(GEM_DOWN);
return;
case GEM_MB_ACTION:
if (Button & GEM_MB_DOUBLECLICK) {
ClickHandle(Button);
}
break;
default:
break;
}
mouseIsDown = true;
short xp = (short) (SCREEN_TO_GAMEX(x));
short yp = (short) (SCREEN_TO_GAMEY(y));
Region vp = core->GetVideoDriver()->GetViewport();
vp.w = vp.x+ViewWidth*MAP_MULT/MAP_DIV;
vp.h = vp.y+ViewHeight*MAP_MULT/MAP_DIV;
if ((xp>vp.x) && (xp<vp.w) && (yp>vp.y) && (yp<vp.h)) {
mouseIsDragging = true;
} else {
mouseIsDragging = false;
}
lastMouseX = x;
lastMouseY = y;
}
/** Mouse Button Up */
void MapControl::OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short /*Mod*/)
{
if (!mouseIsDown) {
return;
}
mouseIsDown = false;
mouseIsDragging = false;
switch(Value) {
case MAP_REVEAL:
ViewHandle(x,y);
NotePosX = (short) SCREEN_TO_MAPX(x) * MAP_MULT / MAP_DIV;
NotePosY = (short) SCREEN_TO_MAPY(y) * MAP_MULT / MAP_DIV;
ClickHandle(Button);
return;
case MAP_NO_NOTES:
ViewHandle(x,y);
return;
case MAP_VIEW_NOTES:
//left click allows setting only when in MAP_SET_NOTE mode
if ((Button == GEM_MB_ACTION) ) {
ViewHandle(x,y);
}
ClickHandle(Button);
return;
default:
ClickHandle(Button);
return;
}
}
/** Special Key Press */
void MapControl::OnSpecialKeyPress(unsigned char Key)
{
switch (Key) {
case GEM_LEFT:
ScrollX -= 64;
break;
case GEM_UP:
ScrollY -= 64;
break;
case GEM_RIGHT:
ScrollX += 64;
break;
case GEM_DOWN:
ScrollY += 64;
break;
case GEM_ALT:
printf( "ALT pressed\n" );
break;
case GEM_TAB:
printf( "TAB pressed\n" );
break;
default:
break;
}
if (ScrollX > MapWidth - Width)
ScrollX = MapWidth - Width;
if (ScrollY > MapHeight - Height)
ScrollY = MapHeight - Height;
if (ScrollX < 0)
ScrollX = 0;
if (ScrollY < 0)
ScrollY = 0;
}
bool MapControl::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_MAP_ON_PRESS:
MapControlOnPress = handler;
break;
case IE_GUI_MAP_ON_RIGHT_PRESS:
MapControlOnRightPress = handler;
break;
case IE_GUI_MAP_ON_DOUBLE_PRESS:
MapControlOnDoublePress = handler;
break;
default:
return false;
}
return true;
}

View File

@@ -0,0 +1,110 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file MapControl.h
* Declares MapControl, widget for displaying current area map
*/
class MapControl;
#ifndef MAPCONTROL_H
#define MAPCONTROL_H
#include "GUI/Control.h"
#include "exports.h"
#include "Interface.h"
// !!! Keep these synchronized with GUIDefines.py !!!
#define IE_GUI_MAP_ON_PRESS 0x09000000
#define IE_GUI_MAP_ON_RIGHT_PRESS 0x09000005
#define IE_GUI_MAP_ON_DOUBLE_PRESS 0x09000008
/**
* @class MapControl
* Widget displaying current area map, with a viewport rectangle
* and PCs' ground circles
*/
class GEM_EXPORT MapControl : public Control {
public:
int ScrollX, ScrollY;
int NotePosX, NotePosY;
unsigned short lastMouseX, lastMouseY;
bool mouseIsDown;
bool mouseIsDragging;
bool convertToGame;
// Small map bitmap
Sprite2D* MapMOS;
// current map
Map *MyMap;
// map flags
Sprite2D *Flag[8];
// The MapControl can set the text of this label directly
Control *LinkedLabel;
// Size of big map (area) in pixels
short MapWidth, MapHeight;
// Size of area viewport. FIXME: hack!
short ViewWidth, ViewHeight;
short XCenter, YCenter;
EventHandler MapControlOnPress;
EventHandler MapControlOnRightPress;
EventHandler MapControlOnDoublePress;
MapControl(void);
~MapControl(void);
/** redraws the control after its associated variable has changed */
void RedrawMapControl(const char *VariableName, unsigned int Sum);
/** Draws the Control on the Output Display */
void Draw(unsigned short XWin, unsigned short YWin);
void DrawFog(unsigned short XWin, unsigned short YWin);
/** Compute parameters after changes in control's or screen geometry */
void Realize();
/** Sets the Text of the current control */
int SetText(const char* /*string*/, int /*pos*/) { return 0; }
/** Key Press Event */
void OnKeyPress(unsigned char Key, unsigned short Mod);
/** Mouse Over Event */
void OnMouseOver(unsigned short x, unsigned short y);
/** Mouse Leave Event */
void OnMouseLeave(unsigned short x, unsigned short y);
/** Mouse Button Down */
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Key Release Event */
void OnKeyRelease(unsigned char Key, unsigned short Mod);
/** Special Key Press */
void OnSpecialKeyPress(unsigned char Key);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
private:
/** Call event handler on click */
void ClickHandle(unsigned short Button);
/** Move viewport */
void ViewHandle(unsigned short x, unsigned short y);
};
#endif

View File

@@ -0,0 +1,184 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Progressbar.h"
#include "win32def.h"
#include "Interface.h"
#include "Video.h"
#include <cstring>
Progressbar::Progressbar( unsigned short KnobStepsCount, bool Clear)
{
BackGround = NULL;
BackGround2 = NULL;
this->Clear = Clear;
this->KnobStepsCount = KnobStepsCount;
PBarAnim = NULL;
PBarCap = NULL;
KnobXPos = KnobYPos = 0;
CapXPos = CapYPos = 0;
ResetEventHandler( EndReached );
}
Progressbar::~Progressbar()
{
if (!Clear) {
return;
}
core->GetVideoDriver()->FreeSprite( BackGround );
core->GetVideoDriver()->FreeSprite( BackGround2 );
delete PBarAnim;
core->GetVideoDriver()->FreeSprite( PBarCap );
}
/** Draws the Control on the Output Display */
void Progressbar::Draw(unsigned short x, unsigned short y)
{
//it is unlikely that a floating window is above us, but...
if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
return;
}
Changed = false;
if (XPos == 65535) {
return;
}
Sprite2D *bcksprite;
if((Value >= 100) && KnobStepsCount && BackGround2) {
bcksprite=BackGround2; //animated progbar end stage
}
else {
bcksprite=BackGround;
}
if (bcksprite) {
Region r( x + XPos, y + YPos, Width, Height );
core->GetVideoDriver()->BlitSprite( bcksprite,
x + XPos, y + YPos, true, &r );
if( bcksprite==BackGround2) {
return; //done for animated progbar
}
}
unsigned int Count;
if(!KnobStepsCount) {
//linear progressbar (pst, iwd)
int w = BackGround2->Width;
int h = BackGround2->Height;
//this is the PST/IWD specific part
Count = Value*w/100;
Region r( x + XPos + KnobXPos, y + YPos + KnobYPos, Count, h );
core->GetVideoDriver()->BlitSprite( BackGround2,
r.x, r.y, true, &r );
core->GetVideoDriver()->BlitSprite( PBarCap,
x+XPos+CapXPos+Count-PBarCap->Width, y+YPos+CapYPos, true );
return;
}
//animated progressbar (bg2)
Count=Value*KnobStepsCount/100;
for(unsigned int i=0; i<Count ;i++ ) {
Sprite2D *Knob = PBarAnim->GetFrame(i);
core->GetVideoDriver()->BlitSprite( Knob, x , y , true );
}
}
/** Returns the actual Progressbar Position */
unsigned int Progressbar::GetPosition()
{
return Value;
}
/** Sets the actual Progressbar Position trimming to the Max and Min Values */
void Progressbar::SetPosition(unsigned int pos)
{
if(pos>100) pos=100;
if (Value == pos)
return;
Value = pos;
Changed = true;
}
void Progressbar::RedrawProgressbar(const char* VariableName, int Sum)
{
if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
return;
}
SetPosition((unsigned int) Sum);
if((Value==100) && Changed)
RunEventHandler( EndReached );
}
/** Sets the selected image */
void Progressbar::SetImage(Sprite2D* img, Sprite2D* img2)
{
if (BackGround && Clear)
core->GetVideoDriver()->FreeSprite( BackGround );
BackGround = img;
if (BackGround2 && Clear)
core->GetVideoDriver()->FreeSprite( BackGround2 );
BackGround2 = img2;
Changed = true;
}
void Progressbar::SetBarCap(Sprite2D* img3)
{
core->GetVideoDriver()->FreeSprite( PBarCap );
PBarCap = img3;
}
void Progressbar::SetAnimation(Animation *arg)
{
delete PBarAnim;
PBarAnim = arg;
}
void Progressbar::SetSliderPos(int x, int y, int x2, int y2)
{
KnobXPos=x;
KnobYPos=y;
CapXPos=x2;
CapYPos=y2;
}
/* dummy virtual function */
int Progressbar::SetText(const char* /*string*/, int /*pos*/)
{
return 0;
}
bool Progressbar::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_PROGRESS_END_REACHED:
EndReached = handler;
break;
default:
return false;
}
return true;
}

View File

@@ -0,0 +1,89 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003-2005 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Progressbar.h
* Declares Progressbar widget for displaying progress of loading and saving games
*/
#ifndef PROGRESSBAR_H
#define PROGRESSBAR_H
#include "GUI/Control.h"
#include "exports.h"
#include "Animation.h"
#include "Sprite2D.h"
// !!! Keep in sync with GUIDefines.py !!!
#define IE_GUI_PROGRESS_END_REACHED 0x01000000
/**
* @class Progressbar
* Widget for displaying progressbars, mainly on loading/saving screens
*/
class GEM_EXPORT Progressbar : public Control {
public:
Progressbar(unsigned short KnobStepsCount, bool Clear = false);
~Progressbar();
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Returns the actual Progressbar Position */
unsigned int GetPosition();
/** Sets the actual Progressbar Position trimming to the Max and Min Values */
void SetPosition(unsigned int pos);
/** Sets the background images */
void SetImage(Sprite2D * img, Sprite2D * img2);
/** Sets a bam resource for progressbar */
void SetAnimation(Animation *arg);
/** Sets a mos resource for progressbar cap */
void SetBarCap(Sprite2D *img3);
/** Sets the mos coordinates for the progressbar filler mos/cap */
void SetSliderPos(int x, int y, int x2, int y2);
/** Dummy function */
int SetText(const char * string, int pos = 0);
/** Redraws a progressbar which is associated with VariableName */
void RedrawProgressbar(const char *VariableName, int Sum);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
private: // Private attributes
/** BackGround Images. If smaller than the Control Size, the image will be tiled. */
Sprite2D * BackGround;
Sprite2D * BackGround2; //mos resource for the filling of the bar
/** Knob Steps Count */
unsigned int KnobStepsCount;
int KnobXPos, KnobYPos; //relative coordinates for Background2
int CapXPos, CapYPos; //relative coordinates for PBarCap
/** If true, on deletion the Progressbar will destroy the associated images */
bool Clear;
/** The bam cycle whose frames work as a progressbar (animated progressbar) */
Animation *PBarAnim;
/** The most for the progressbar cap (linear progressbar) */
Sprite2D *PBarCap;
public:
/** EndReached Scripted Event Function Name */
EventHandler EndReached;
};
#endif

View File

@@ -0,0 +1,297 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/ScrollBar.h"
#include "win32def.h"
#include "Interface.h"
#include "Variables.h"
#include "Video.h"
ScrollBar::ScrollBar(void)
{
Pos = 0;
Value = 10;
State = 0;
ResetEventHandler( ScrollBarOnChange );
ta = NULL;
for(int i=0;i<SB_RES_COUNT;i++) {
Frames[i]=NULL;
}
}
ScrollBar::~ScrollBar(void)
{
Video *video=core->GetVideoDriver();
for(int i=0;i<SB_RES_COUNT;i++) {
if(Frames[i]) {
video->FreeSprite(Frames[i]);
}
}
}
/** Sets a new position, relays the change to an associated textarea and calls
any existing GUI OnChange callback */
void ScrollBar::SetPos(int NewPos)
{
if (Pos && ( Pos == NewPos )) {
return;
}
Changed = true;
Pos = (ieWord) NewPos;
if (ta) {
TextArea* t = ( TextArea* ) ta;
t->SetRow( Pos );
}
if (VarName[0] != 0) {
core->GetDictionary()->SetAt( VarName, Pos );
}
RunEventHandler( ScrollBarOnChange );
}
/** Refreshes the ScrollBar according to a guiscript variable */
void ScrollBar::RedrawScrollBar(const char* Variable, int Sum)
{
if (strnicmp( VarName, Variable, MAX_VARIABLE_LENGTH )) {
return;
}
SetPos( Sum );
}
/** Mousewheel support */
void ScrollBar::ScrollUp()
{
if (Pos > 0) {
SetPos( Pos - 1 );
}
}
/** Mousewheel support */
void ScrollBar::ScrollDown()
{
if ( (ieDword) Pos + 1 < Value ) {
SetPos( Pos + 1 );
}
}
/** Draws the ScrollBar control */
void ScrollBar::Draw(unsigned short x, unsigned short y)
{
if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
return;
}
Changed = false;
if (XPos == 65535) {
return;
}
int upMy = Frames[IE_GUI_SCROLLBAR_UP_UNPRESSED]->Height;
int doMy = Frames[IE_GUI_SCROLLBAR_DOWN_UNPRESSED]->Height;
unsigned int domy = (Height - doMy);
unsigned short slmy = ( unsigned short )
( upMy +
( Pos * ( ( domy - Frames[IE_GUI_SCROLLBAR_SLIDER]->Height - upMy ) /
( double ) ( Value < 2 ? 1 : Value - 1 ) ) ) );
unsigned short slx = ( unsigned short ) ((Width - Frames[IE_GUI_SCROLLBAR_SLIDER]->Width) / 2 );
if (( State & UP_PRESS ) != 0) {
core->GetVideoDriver()->BlitSprite( Frames[IE_GUI_SCROLLBAR_UP_PRESSED],
x + XPos, y + YPos, true );
} else {
core->GetVideoDriver()->BlitSprite( Frames[IE_GUI_SCROLLBAR_UP_UNPRESSED],
x + XPos, y + YPos, true );
}
int maxy = y + YPos + Height -
Frames[IE_GUI_SCROLLBAR_DOWN_UNPRESSED]->Height;
int stepy = Frames[IE_GUI_SCROLLBAR_TROUGH]->Height;
Region rgn( x + XPos, y + YPos + upMy, Width, domy - upMy);
for (int dy = y + YPos + upMy; dy < maxy; dy += stepy) {
core->GetVideoDriver()->BlitSprite( Frames[IE_GUI_SCROLLBAR_TROUGH],
x + XPos + ( ( Width / 2 ) -
Frames[IE_GUI_SCROLLBAR_TROUGH]->Width / 2 ),
dy, true, &rgn );
}
if (( State & DOWN_PRESS ) != 0) {
core->GetVideoDriver()->BlitSprite( Frames[IE_GUI_SCROLLBAR_DOWN_PRESSED],
x + XPos, maxy, true );
} else {
core->GetVideoDriver()->BlitSprite( Frames[IE_GUI_SCROLLBAR_DOWN_UNPRESSED],
x + XPos, maxy, true );
}
core->GetVideoDriver()->BlitSprite( Frames[IE_GUI_SCROLLBAR_SLIDER],
x + XPos + slx + Frames[IE_GUI_SCROLLBAR_SLIDER]->XPos,
y + YPos + slmy + Frames[IE_GUI_SCROLLBAR_SLIDER]->YPos,
true );
}
/** Sets a ScrollBar GUI resource */
void ScrollBar::SetImage(unsigned char type, Sprite2D* img)
{
if (type >= SB_RES_COUNT) {
return;
}
if (Frames[type]) {
core->GetVideoDriver()->FreeSprite(Frames[type]);
}
Frames[type] = img;
Changed = true;
}
/** Mouse Button Down */
void ScrollBar::OnMouseDown(unsigned short x, unsigned short y,
unsigned short Button, unsigned short /*Mod*/)
{
//removing the double click flag, use a more sophisticated method
//if it is needed later
Button&=GEM_MB_NORMAL;
if (Button==GEM_MB_SCRLUP) {
ScrollUp();
return;
}
if (Button==GEM_MB_SCRLDOWN) {
ScrollDown();
return;
}
core->RedrawAll();
unsigned short upMx = (unsigned short) Frames[IE_GUI_SCROLLBAR_UP_UNPRESSED]->Width;
unsigned short upMy = (unsigned short) Frames[IE_GUI_SCROLLBAR_UP_UNPRESSED]->Height;
unsigned short domy = (unsigned short) (Height - Frames[IE_GUI_SCROLLBAR_DOWN_UNPRESSED]->Height);
unsigned short slheight = domy - upMy;
unsigned short refheight = (unsigned short) (slheight - Frames[IE_GUI_SCROLLBAR_SLIDER]->Height);
double step = refheight / (double) ( Value < 2 ? 1 : Value - 1 );
unsigned short ymax = upMy + refheight;
unsigned short ymy = y - upMy;
unsigned short doMx = (unsigned short) Frames[IE_GUI_SCROLLBAR_DOWN_UNPRESSED]->Width;
unsigned short slMx = (unsigned short) Frames[IE_GUI_SCROLLBAR_SLIDER]->Width;
unsigned short slmy = (unsigned short) (upMy + Pos * step);
unsigned short slMy = (unsigned short) (slmy + Frames[IE_GUI_SCROLLBAR_SLIDER]->Height);
if (( x <= upMx ) && ( y <= upMy )) {
if (Pos > 0)
SetPos( Pos - 1 );
State |= UP_PRESS;
return;
}
if (y >= domy) {
if (( x <= doMx ) && ( y <= Height )) {
if ( (ieDword) Pos + 1 < Value )
SetPos( Pos + 1 );
State |= DOWN_PRESS;
return;
}
}
if (y >= slmy) {
if (( x <= slMx ) && ( y <= slMy )) {
State |= SLIDER_GRAB;
return;
}
}
if (y <= upMy) {
SetPos( 0 );
return;
}
if (y >= ymax) {
SetPos( Value - 1 );
return;
}
unsigned short befst = ( unsigned short ) ( ymy / step );
unsigned short aftst = befst + 1;
if (( ymy - ( befst * step ) ) < ( ( aftst * step ) - ymy )) {
SetPos( befst );
} else {
SetPos( aftst );
}
}
/** Mouse Button Up */
void ScrollBar::OnMouseUp(unsigned short /*x*/, unsigned short /*y*/,
unsigned short /*Button*/, unsigned short /*Mod*/)
{
Changed = true;
State = 0;
}
/** Mouse Over Event */
void ScrollBar::OnMouseOver(unsigned short /*x*/, unsigned short y)
{
if (( State & SLIDER_GRAB ) != 0) {
core->RedrawAll();
unsigned short upMy =(unsigned short) Frames[IE_GUI_SCROLLBAR_UP_UNPRESSED]->Height;
unsigned short domy = (unsigned short) (Height - Frames[IE_GUI_SCROLLBAR_DOWN_UNPRESSED]->Height);
unsigned short slheight = domy - upMy;
unsigned short refheight = (unsigned short) (slheight - Frames[IE_GUI_SCROLLBAR_SLIDER]->Height);
double step = refheight / ( double ) ( Value < 2 ? 1 : Value - 1 );
unsigned short yzero = (unsigned short) (upMy + Frames[IE_GUI_SCROLLBAR_SLIDER]->Height / 2 );
unsigned short ymax = yzero + refheight;
unsigned short ymy = y - yzero;
if (y <= yzero) {
SetPos( 0 );
return;
}
if (y >= ymax) {
SetPos( Value - 1 );
return;
}
unsigned short befst = ( unsigned short ) ( ymy / step );
unsigned short aftst = befst + 1;
if (( ymy - ( befst * step ) ) < ( ( aftst * step ) - ymy )) {
if (befst > Value )
SetPos( befst );
} else {
if (aftst < Value )
SetPos( aftst );
}
}
}
/** Sets the Text of the current control */
int ScrollBar::SetText(const char* /*string*/, int /*pos*/)
{
return 0;
}
/** Sets the Maximum Value of the ScrollBar */
void ScrollBar::SetMax(unsigned short Max)
{
Value = Max;
if (Max == 0) {
SetPos( 0 );
} else if (Pos >= Max) {
SetPos( Max - 1 );
}
}
/** Sets the ScrollBarOnChange event (guiscript callback) */
bool ScrollBar::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_SCROLLBAR_ON_CHANGE:
ScrollBarOnChange = handler;
break;
default:
return false;
}
return true;
}

View File

@@ -0,0 +1,103 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file ScrollBar.h
* Declares ScrollBar widget for paging in long text windows.
* This does not include scales and sliders, which are of Slider class.
* @author The GemRB Project
*/
#ifndef SCROLLBAR_H
#define SCROLLBAR_H
#include "GUI/Control.h"
#include "GUI/TextArea.h"
#include "exports.h"
#include "Sprite2D.h"
// !!! Keep these synchronized with GUIDefines.py !!!
#define IE_GUI_SCROLLBAR_ON_CHANGE 0x07000000
#define IE_GUI_SCROLLBAR_DEFAULT 0x00000040 // mousewheel triggers it
#define IE_GUI_SCROLLBAR_UP_UNPRESSED 0
#define IE_GUI_SCROLLBAR_UP_PRESSED 1
#define IE_GUI_SCROLLBAR_DOWN_UNPRESSED 2
#define IE_GUI_SCROLLBAR_DOWN_PRESSED 3
#define IE_GUI_SCROLLBAR_TROUGH 4
#define IE_GUI_SCROLLBAR_SLIDER 5
#define UP_PRESS 0x0001
#define DOWN_PRESS 0x0010
#define SLIDER_GRAB 0x0100
/**
* @class ScrollBar
* Widget displaying scrollbars for paging in long text windows
*/
#define SB_RES_COUNT 6
class GEM_EXPORT ScrollBar : public Control {
public:
ScrollBar(void);
~ScrollBar(void);
/**sets position, updates associated stuff */
void SetPos(int NewPos);
void ScrollUp();
void ScrollDown();
/**redraws scrollbar if associated with VarName */
void RedrawScrollBar(const char* VarName, int Sum);
/**/
void Draw(unsigned short x, unsigned short y);
private: //Private attributes
/** Images for drawing the Scroll Bar */
Sprite2D* Frames[SB_RES_COUNT];
/** Cursor Position */
unsigned short Pos;
/** Scroll Bar Status */
unsigned short State;
/** Sets the Text of the current control */
int SetText(const char* string, int pos = 0);
public:
void SetImage(unsigned char type, Sprite2D* img);
/** Sets the Maximum Value of the ScrollBar */
void SetMax(unsigned short Max);
/** TextArea Associated Control */
Control* ta;
public: // Public Events
/** Mouse Button Down */
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Over Event */
void OnMouseOver(unsigned short x, unsigned short y);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
/** OnChange Scripted Event Function Name */
EventHandler ScrollBarOnChange;
};
#endif

View File

@@ -0,0 +1,296 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Slider.h"
#include "win32def.h"
#include "Interface.h"
#include "Variables.h"
#include "Video.h"
#include <cmath>
Slider::Slider(short KnobXPos, short KnobYPos, short KnobStep,
unsigned short KnobStepsCount, bool Clear)
{
this->KnobXPos = KnobXPos;
this->KnobYPos = KnobYPos;
this->KnobStep = KnobStep;
this->KnobStepsCount = KnobStepsCount;
Knob = NULL;
GrabbedKnob = NULL;
BackGround = NULL;
this->Clear = Clear;
ResetEventHandler( SliderOnChange );
State = IE_GUI_SLIDER_KNOB;
Pos = 0;
Value = 1;
}
Slider::~Slider()
{
if (!Clear) {
return;
}
if (Knob) {
core->GetVideoDriver()->FreeSprite( Knob );
}
if (GrabbedKnob) {
core->GetVideoDriver()->FreeSprite( GrabbedKnob );
}
if (BackGround) {
core->GetVideoDriver()->FreeSprite( BackGround );
}
}
/** Draws the Control on the Output Display */
void Slider::Draw(unsigned short x, unsigned short y)
{
if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
return;
}
Changed = false;
if (XPos == 65535) {
return;
}
Region r( x + XPos, y + YPos, Width, Height );
if (BackGround) {
if (( BackGround->Width < Width ) || ( BackGround->Height < Height )) {
core->GetVideoDriver()->BlitTiled( r, BackGround, true );
} else {
core->GetVideoDriver()->BlitSprite( BackGround, x + XPos, y + YPos, true, &r );
}
}
switch (State) {
case IE_GUI_SLIDER_KNOB:
core->GetVideoDriver()->BlitSprite( Knob,
x + XPos + KnobXPos + ( Pos * KnobStep ),
y + YPos + KnobYPos, true );
break;
case IE_GUI_SLIDER_GRABBEDKNOB:
core->GetVideoDriver()->BlitSprite( GrabbedKnob,
x + XPos + KnobXPos + ( Pos * KnobStep ),
y + YPos + KnobYPos, true );
break;
}
}
/** Returns the actual Slider Position */
unsigned int Slider::GetPosition()
{
return Pos;
}
/** Sets the actual Slider Position trimming to the Max and Min Values */
void Slider::SetPosition(unsigned int pos)
{
if (pos <= KnobStepsCount) {
Pos = pos;
}
if (VarName[0] != 0) {
if (!Value)
Value = 1;
core->GetDictionary()->SetAt( VarName, pos * Value );
}
Changed = true;
}
/** Redraws a slider which is associated with VariableName */
void Slider::RedrawSlider(const char* VariableName, int Sum)
{
if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
return;
}
if (!Value) {
Value = 1;
}
Sum /= Value;
if (Sum <= KnobStepsCount) {
Pos = Sum;
}
Changed = true;
}
/** Sets the selected image */
void Slider::SetImage(unsigned char type, Sprite2D* img)
{
switch (type) {
case IE_GUI_SLIDER_KNOB:
if (Knob && Clear)
core->GetVideoDriver()->FreeSprite( Knob );
Knob = img;
break;
case IE_GUI_SLIDER_GRABBEDKNOB:
if (GrabbedKnob && Clear)
core->GetVideoDriver()->FreeSprite( GrabbedKnob );
GrabbedKnob = img;
break;
case IE_GUI_SLIDER_BACKGROUND:
if (BackGround && Clear)
core->GetVideoDriver()->FreeSprite( BackGround );
BackGround = img;
break;
}
Changed = true;
}
/** Mouse Button Down */
void Slider::OnMouseDown(unsigned short x, unsigned short y, unsigned short /*Button*/,
unsigned short /*Mod*/)
{
Changed = true;
unsigned int oldPos = Pos;
int mx = (KnobXPos + ( Pos * KnobStep ) - Knob->XPos);
int my = (KnobYPos - Knob->YPos);
int Mx = (mx + Knob->Width);
int My = (my + Knob->Height);
if (( x >= mx ) && ( y >= my )) {
if (( x <= Mx ) && ( y <= My )) {
State = IE_GUI_SLIDER_GRABBEDKNOB;
} else {
int mx = KnobXPos;
int xmx = x - mx;
if (x < mx) {
SetPosition( 0 );
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
return;
}
int befst = xmx / KnobStep;
if (befst >= KnobStepsCount) {
SetPosition( KnobStepsCount - 1 );
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
return;
}
int aftst = befst + KnobStep;
if (( xmx - ( befst * KnobStep ) ) <
( ( aftst * KnobStep ) - xmx )) {
SetPosition( befst );
} else {
SetPosition( aftst );
}
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
}
} else {
int mx = KnobXPos;
int xmx = x - mx;
if (x < mx) {
SetPosition( 0 );
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
return;
}
int befst = xmx / KnobStep;
if (befst >= KnobStepsCount) {
SetPosition( KnobStepsCount - 1 );
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
return;
}
int aftst = befst + KnobStep;
if (( xmx - ( befst * KnobStep ) ) < ( ( aftst * KnobStep ) - xmx )) {
SetPosition( befst );
} else {
SetPosition( aftst );
}
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
}
}
/** Mouse Button Up */
void Slider::OnMouseUp(unsigned short /*x*/, unsigned short /*y*/, unsigned short /*Button*/,
unsigned short /*Mod*/)
{
if (State != IE_GUI_SLIDER_KNOB) {
Changed = true;
}
State = IE_GUI_SLIDER_KNOB;
}
/** Mouse Over Event */
void Slider::OnMouseOver(unsigned short x, unsigned short /*y*/)
{
Changed = true;
unsigned int oldPos = Pos;
if (State == IE_GUI_SLIDER_GRABBEDKNOB) {
int mx = KnobXPos;
int xmx = x - mx;
if (x < mx) {
SetPosition( 0 );
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
return;
}
int befst = xmx / KnobStep;
if (befst >= KnobStepsCount) {
SetPosition( KnobStepsCount - 1 );
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
return;
}
short aftst = befst + KnobStep;
if (( xmx - ( befst * KnobStep ) ) < ( ( aftst * KnobStep ) - xmx )) {
SetPosition( befst );
} else {
SetPosition( aftst );
}
if (oldPos != Pos) {
RunEventHandler( SliderOnChange );
}
}
}
/** Sets the Text of the current control */
int Slider::SetText(const char* /*string*/, int /*pos*/)
{
return 0;
}
/** Sets the slider change event */
bool Slider::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_SLIDER_ON_CHANGE:
SliderOnChange = handler;
break;
default:
return false;
}
return true;
}

View File

@@ -0,0 +1,106 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Slider.h
* Declares Slider widget for displaying scales and sliders for setting
* numerical values
* @author The GemRB Project
*/
#ifndef SLIDER_H
#define SLIDER_H
#include "GUI/Control.h"
#include "exports.h"
#include "Sprite2D.h"
// !!! Keep these synchronized with GUIDefines.py !!!
#define IE_GUI_SLIDER_ON_CHANGE 0x02000000
#define IE_GUI_SLIDER_KNOB 0
#define IE_GUI_SLIDER_GRABBEDKNOB 1
#define IE_GUI_SLIDER_BACKGROUND 2
/**
* @class Slider
* Widget displaying sliders or scales for inputting numerical values
* with a limited range
*/
class GEM_EXPORT Slider : public Control {
public:
Slider(short KnobXPos, short KnobYPos, short KnobStep, unsigned short KnobStepsCount, bool Clear = false);
~Slider();
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Returns the actual Slider Position */
unsigned int GetPosition();
/** Sets the actual Slider Position trimming to the Max and Min Values */
void SetPosition(unsigned int pos);
/** Sets the selected image */
void SetImage(unsigned char type, Sprite2D * img);
/** Sets the Text of the current control */
int SetText(const char * string, int pos = 0);
/** Sets the State of the Slider */
void SetState(int arg) { State=(unsigned char) arg; }
/** Redraws a slider which is associated with VariableName */
void RedrawSlider(const char *VariableName, int Sum);
private: // Private attributes
/** BackGround Image. If smaller than the Control Size, the image will be tiled. */
Sprite2D * BackGround;
/** Knob Image */
Sprite2D * Knob;
/** Grabbed Knob Image */
Sprite2D * GrabbedKnob;
/** Knob Starting X Position */
short KnobXPos;
/** Knob Starting Y Position */
short KnobYPos;
/** Knob Step Size */
short KnobStep;
/** Knob Steps Count */
unsigned short KnobStepsCount;
/** If true, on deletion the Slider will destroy the associated images */
bool Clear;
/** Actual Knob Status */
unsigned char State;
/** Slider Position Value */
unsigned int Pos;
public: // Public Events
/** Mouse Button Down */
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Over Event */
void OnMouseOver(unsigned short x, unsigned short y);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
/** OnChange Scripted Event Function Name */
EventHandler SliderOnChange;
};
#endif

View File

@@ -0,0 +1,958 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/TextArea.h"
#include "GUI/GameControl.h"
#include "win32def.h"
#include "Audio.h"
#include "DialogHandler.h"
#include "GameData.h"
#include "ImageMgr.h"
#include "Interface.h"
#include "Palette.h"
#include "Variables.h"
#include "Video.h"
#include "Scriptable/Actor.h"
#include <cstdio>
#include <cstdlib>
TextArea::TextArea(Color hitextcolor, Color initcolor, Color lowtextcolor)
{
keeplines = 100;
rows = 0;
startrow = 0;
minrow = 0;
Cursor = NULL;
CurPos = 0;
CurLine = 0;
seltext = -1;
Value = 0xffffffff;
ResetEventHandler( TextAreaOnChange );
ResetEventHandler( TextAreaOutOfText );
PortraitResRef[0]=0;
palette = core->CreatePalette( hitextcolor, lowtextcolor );
initpalette = core->CreatePalette( initcolor, lowtextcolor );
Color tmp = {
hitextcolor.b, hitextcolor.g, hitextcolor.r, 0
};
selected = core->CreatePalette( tmp, lowtextcolor );
tmp.r = 255;
tmp.g = 152;
tmp.b = 102;
lineselpal = core->CreatePalette( tmp, lowtextcolor );
InternalFlags = 1;
//Drop Capitals means initials on!
core->GetDictionary()->Lookup("Drop Capitals", InternalFlags);
if (InternalFlags) {
InternalFlags = TA_INITIALS;
}
}
TextArea::~TextArea(void)
{
gamedata->FreePalette( palette );
gamedata->FreePalette( initpalette );
gamedata->FreePalette( selected );
gamedata->FreePalette( lineselpal );
core->GetVideoDriver()->FreeSprite( Cursor );
for (size_t i = 0; i < lines.size(); i++) {
free( lines[i] );
}
}
void TextArea::RefreshSprite(const char *portrait)
{
if (AnimPicture) {
if (!strnicmp(PortraitResRef, portrait, 8) ) {
return;
}
SetAnimPicture(NULL);
}
strnlwrcpy(PortraitResRef, portrait, 8);
if (!strnicmp(PortraitResRef, "none", 8) ) {
return;
}
ResourceHolder<ImageMgr> im(PortraitResRef);
if (im == NULL) {
return;
}
SetAnimPicture ( im->GetSprite2D() );
}
void TextArea::Draw(unsigned short x, unsigned short y)
{
/** Don't come back recursively */
if (InternalFlags&TA_BITEMYTAIL) {
return;
}
int tx=x+XPos;
int ty=y+YPos;
Region clip( tx, ty, Width, Height );
Video *video = core->GetVideoDriver();
if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
if (AnimPicture) {
video->BlitSprite(AnimPicture, tx,ty, true, &clip);
clip.x+=AnimPicture->Width;
clip.w-=AnimPicture->Width;
}
}
//this might look better in GlobalTimer
//or you might want to change the animated button to work like this
if (Flags &IE_GUI_TEXTAREA_SMOOTHSCROLL)
{
unsigned long thisTime;
GetTime( thisTime);
if (thisTime>starttime) {
starttime = thisTime+ticks;
smooth--;
while (smooth<=0) {
smooth+=ftext->maxHeight;
if (startrow<rows) {
startrow++;
}
}
/** Forcing redraw of whole screen before drawing text*/
Owner->Invalidate();
InternalFlags |= TA_BITEMYTAIL;
Owner->DrawWindow();
InternalFlags &= ~TA_BITEMYTAIL;
}
}
if (!Changed && !(Owner->Flags&WF_FLOAT) ) {
return;
}
Changed = false;
if (XPos == 65535) {
return;
}
size_t linesize = lines.size();
if (linesize == 0) {
return;
}
//smooth vertical scrolling up
if (Flags & IE_GUI_TEXTAREA_SMOOTHSCROLL) {
clip.y+=smooth;
clip.h-=smooth;
}
//if textarea is 'selectable' it actually means, it is a listbox
//in this case the selected value equals the line number
//if it is 'not selectable' it can still have selectable lines
//but then it is like the dialog window in the main game screen:
//the selected value is encoded into the line
if (!(Flags & IE_GUI_TEXTAREA_SELECTABLE) ) {
char* Buffer = (char *) malloc( 1 );
Buffer[0] = 0;
int len = 0;
int lastlen = 0;
for (size_t i = 0; i < linesize; i++) {
if (strnicmp( "[s=", lines[i], 3 ) == 0) {
int tlen;
unsigned long idx, acolor, bcolor;
char* rest;
idx = strtoul( lines[i] + 3, &rest, 0 );
if (*rest != ',')
goto notmatched;
acolor = strtoul( rest + 1, &rest, 16 );
if (*rest != ',')
goto notmatched;
bcolor = strtoul( rest + 1, &rest, 16 );
if (*rest != ']')
goto notmatched;
tlen = (int)(strstr( rest + 1, "[/s]" ) - rest - 1);
if (tlen < 0)
goto notmatched;
len += tlen + 23;
Buffer = (char *) realloc( Buffer, len + 2 );
if (seltext == (int) i) {
sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
acolor, tlen, rest + 1 );
} else {
sprintf( Buffer + lastlen, "[color=%6.6lX]%.*s[/color]",
bcolor, tlen, rest + 1 );
}
} else {
notmatched:
len += ( int ) strlen( lines[i] ) + 1;
Buffer = (char *) realloc( Buffer, len + 2 );
memcpy( &Buffer[lastlen], lines[i], len - lastlen );
}
lastlen = len;
if (i != linesize - 1) {
Buffer[lastlen - 1] = '\n';
Buffer[lastlen] = 0;
}
}
video->SetClipRect( &clip );
int pos;
if (startrow==CurLine) {
pos = CurPos;
} else {
pos = -1;
}
ftext->PrintFromLine( startrow, clip,
( unsigned char * ) Buffer, palette,
IE_FONT_ALIGN_LEFT, finit, Cursor, pos );
free( Buffer );
video->SetClipRect( NULL );
//streaming text
if (linesize>50) {
//the buffer is filled enough
return;
}
if (core->GetAudioDrv()->IsSpeaking() ) {
//the narrator is still talking
return;
}
if (RunEventHandler( TextAreaOutOfText )) {
return;
}
if (linesize==lines.size()) {
ResetEventHandler( TextAreaOutOfText );
return;
}
AppendText("\n",-1);
return;
}
// normal scrolling textarea
int rc = 0;
int sr = startrow;
unsigned int i;
int yl;
for (i = 0; i < linesize; i++) {
if (rc + lrows[i] <= sr) {
rc += lrows[i];
continue;
}
sr -= rc;
Palette* pal = NULL;
if (seltext == (int) i)
pal = selected;
else if (Value == i)
pal = lineselpal;
else
pal = palette;
ftext->PrintFromLine( sr, clip,
( unsigned char * ) lines[i], pal,
IE_FONT_ALIGN_LEFT, finit, NULL );
yl = ftext->size[1].h*(lrows[i]-sr);
clip.y+=yl;
clip.h-=yl;
break;
}
for (i++; i < linesize; i++) {
Palette* pal = NULL;
if (seltext == (int) i)
pal = selected;
else if (Value == i)
pal = lineselpal;
else
pal = palette;
ftext->Print( clip, ( unsigned char * ) lines[i], pal,
IE_FONT_ALIGN_LEFT, true );
yl = ftext->size[1].h*lrows[i];
clip.y+=yl;
clip.h-=yl;
}
}
/** Sets the Scroll Bar Pointer. If 'ptr' is NULL no Scroll Bar will be linked
to this Text Area Control. */
int TextArea::SetScrollBar(Control* ptr)
{
int ret = Control::SetScrollBar(ptr);
CalcRowCount();
return ret;
}
/** Sets the Actual Text */
int TextArea::SetText(const char* text, int pos)
{
if (pos==0) {
if (!text[0]) {
lines.clear();
lrows.clear();
}
if (lines.size() == 0) {
pos = -1;
}
}
if (pos >= ( int ) lines.size()) {
return -1;
}
int newlen = ( int ) strlen( text );
if (pos == -1) {
char* str = (char *) malloc( newlen + 1 );
memcpy( str, text, newlen + 1 );
lines.push_back( str );
lrows.push_back( 0 );
} else {
lines[pos] = (char *) realloc( lines[pos], newlen + 1 );
memcpy( lines[pos], text, newlen + 1 );
}
CurPos = newlen;
CurLine = lines.size()-1;
UpdateControls();
return 0;
}
void TextArea::SetMinRow(bool enable)
{
if (enable) {
minrow = (int) lines.size();
} else {
minrow = 0;
}
Changed = true;
}
//drop lines scrolled out at the top.
//keeplines is the number of lines that should still be
//preserved (for scrollback history)
void TextArea::DiscardLines()
{
if (rows<=keeplines) {
return;
}
int drop = rows-keeplines;
PopLines(drop, true);
}
static char *note_const = NULL;
static const char inserted_crap[]="[/color][color=ffffff]";
#define CRAPLENGTH sizeof(inserted_crap)-1
void TextArea::SetNoteString(const char *s)
{
free(note_const);
if (s) {
note_const = (char *) malloc(strlen(s)+5);
sprintf(note_const, "\r\n\r\n%s", s);
}
}
/** Appends a String to the current Text */
int TextArea::AppendText(const char* text, int pos)
{
int ret = 0;
if (pos >= ( int ) lines.size()) {
return -1;
}
int newlen = ( int ) strlen( text );
if (pos == -1) {
const char *note = NULL;
if (note_const) {
note = strstr(text,note_const);
}
char *str;
if (NULL == note) {
str = (char *) malloc( newlen +1 );
memcpy(str, text, newlen+1);
}
else {
unsigned int notepos = (unsigned int) (note - text);
str = (char *) malloc( newlen + CRAPLENGTH+1 );
memcpy(str,text,notepos);
memcpy(str+notepos,inserted_crap,CRAPLENGTH);
memcpy(str+notepos+CRAPLENGTH, text+notepos, newlen-notepos+1);
}
lines.push_back( str );
lrows.push_back( 0 );
ret =(int) (lines.size() - 1);
} else {
int mylen = ( int ) strlen( lines[pos] );
lines[pos] = (char *) realloc( lines[pos], mylen + newlen + 1 );
memcpy( lines[pos]+mylen, text, newlen + 1 );
ret = pos;
}
//if the textarea is not a listbox, then discard scrolled out
//lines
if (Flags&IE_GUI_TEXTAREA_HISTORY) {
DiscardLines();
}
UpdateControls();
return ret;
}
/** Deletes last or first `count' lines */
/** Probably not too optimal for many lines, but it isn't used */
/** for many lines */
void TextArea::PopLines(unsigned int count, bool top)
{
if (count > lines.size()) {
count = (unsigned int) lines.size();
}
while (count > 0 ) {
if (top) {
int tmp = lrows.front();
if (minrow || (startrow<tmp) )
break;
startrow -= tmp;
free(lines.front() );
lines.erase(lines.begin());
lrows.erase(lrows.begin());
} else {
free(lines.back() );
lines.pop_back();
lrows.pop_back();
}
count--;
}
UpdateControls();
}
void TextArea::UpdateControls()
{
int pos;
CalcRowCount();
Changed = true;
if (sb) {
ScrollBar* bar = ( ScrollBar* ) sb;
if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL)
pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
else
pos = 0;
if (pos < 0)
pos = 0;
bar->SetPos( pos );
} else {
if (Flags & IE_GUI_TEXTAREA_AUTOSCROLL) {
pos = rows - ( ( Height - 5 ) / ftext->maxHeight );
SetRow(pos);
}
}
core->RedrawAll();
}
/** Sets the Fonts */
void TextArea::SetFonts(Font* init, Font* text)
{
finit = init;
ftext = text;
Changed = true;
}
/** Key Press Event */
void TextArea::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
{
if (Flags & IE_GUI_TEXTAREA_EDITABLE) {
if (Key >= 0x20) {
Owner->Invalidate();
Changed = true;
int len = GetRowLength(CurLine);
//printf("len: %d Before: %s\n",len, lines[CurLine]);
lines[CurLine] = (char *) realloc( lines[CurLine], len + 2 );
for (int i = len; i > CurPos; i--) {
lines[CurLine][i] = lines[CurLine][i - 1];
}
lines[CurLine][CurPos] = Key;
lines[CurLine][len + 1] = 0;
CurPos++;
//printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
CalcRowCount();
RunEventHandler( TextAreaOnChange );
}
return;
}
//Selectable=false for dialogs, rather unintuitive, but fact
if ((Flags & IE_GUI_TEXTAREA_SELECTABLE) || ( Key < '1' ) || ( Key > '9' ))
return;
GameControl *gc = core->GetGameControl();
if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
Changed = true;
seltext=minrow-1;
if ((unsigned int) seltext>=lines.size()) {
return;
}
for(int i=0;i<Key-'0';i++) {
do {
seltext++;
if ((unsigned int) seltext>=lines.size()) {
return;
}
}
while (strnicmp( lines[seltext], "[s=", 3 ) != 0 );
}
int idx=-1;
sscanf( lines[seltext], "[s=%d,", &idx);
if (idx==-1) {
//this kills this object, don't use any more data!
gc->dialoghandler->EndDialog();
return;
}
gc->dialoghandler->DialogChoose( idx );
}
}
/** Special Key Press */
void TextArea::OnSpecialKeyPress(unsigned char Key)
{
int len;
int i;
if (!(Flags&IE_GUI_TEXTAREA_EDITABLE)) {
return;
}
Owner->Invalidate();
Changed = true;
switch (Key) {
case GEM_HOME:
CurPos = 0;
CurLine = 0;
break;
case GEM_UP:
if (CurLine) {
CurLine--;
}
break;
case GEM_DOWN:
if (CurLine<lines.size()) {
CurLine++;
}
break;
case GEM_END:
CurLine=lines.size()-1;
CurPos = GetRowLength((unsigned int) CurLine);
break;
case GEM_LEFT:
if (CurPos > 0) {
CurPos--;
} else {
if (CurLine) {
CurLine--;
CurPos = GetRowLength(CurLine);
}
}
break;
case GEM_RIGHT:
len = GetRowLength(CurLine);
if (CurPos < len) {
CurPos++;
} else {
if(CurLine<lines.size()) {
CurPos=0;
CurLine++;
}
}
break;
case GEM_DELETE:
len = GetRowLength(CurLine);
//printf("len: %d Before: %s\n",len, lines[CurLine]);
if (CurPos>=len) {
//TODO: merge next line
break;
}
lines[CurLine] = (char *) realloc( lines[CurLine], len );
for (i = CurPos; i < len; i++) {
lines[CurLine][i] = lines[CurLine][i + 1];
}
//printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
break;
case GEM_BACKSP:
len = GetRowLength(CurLine);
if (CurPos != 0) {
//printf("len: %d Before: %s\n",len, lines[CurLine]);
if (len<1) {
break;
}
lines[CurLine] = (char *) realloc( lines[CurLine], len );
for (i = CurPos; i < len; i++) {
lines[CurLine][i - 1] = lines[CurLine][i];
}
lines[CurLine][len - 1] = 0;
CurPos--;
//printf("pos: %d After: %s\n",CurPos, lines[CurLine]);
} else {
if (CurLine) {
//TODO: merge lines
int oldline = CurLine;
CurLine--;
int old = GetRowLength(CurLine);
//printf("len: %d Before: %s\n",old, lines[CurLine]);
//printf("len: %d Before: %s\n",len, lines[oldline]);
lines[CurLine] = (char *) realloc (lines[CurLine], len+old);
memcpy(lines[CurLine]+old, lines[oldline],len);
free(lines[oldline]);
lines[CurLine][old+len]=0;
lines.erase(lines.begin()+oldline);
lrows.erase(lrows.begin()+oldline);
CurPos = old;
//printf("pos: %d len: %d After: %s\n",CurPos, GetRowLength(CurLine), lines[CurLine]);
}
}
break;
case GEM_RETURN:
//add an empty line after CurLine
//printf("pos: %d Before: %s\n",CurPos, lines[CurLine]);
lrows.insert(lrows.begin()+CurLine, 0);
len = GetRowLength(CurLine);
//copy the text after the cursor into the new line
char *str = (char *) malloc(len-CurPos+2);
memcpy(str, lines[CurLine]+CurPos, len-CurPos+1);
str[len-CurPos+1] = 0;
lines.insert(lines.begin()+CurLine+1, str);
//truncate the current line
lines[CurLine] = (char *) realloc (lines[CurLine], CurPos+1);
lines[CurLine][CurPos]=0;
//move cursor to next line beginning
CurLine++;
CurPos=0;
//printf("len: %d After: %s\n",GetRowLength(CurLine-1), lines[CurLine-1]);
//printf("len: %d After: %s\n",GetRowLength(CurLine), lines[CurLine]);
break;
}
CalcRowCount();
RunEventHandler( TextAreaOnChange );
}
/** Returns Row count */
int TextArea::GetRowCount()
{
return ( int ) lines.size();
}
int TextArea::GetRowLength(unsigned int row)
{
if (lines.size()<=row) {
return 0;
}
//this is just roughly the line size, escape sequences need to be removed
return strlen( lines[row] );
}
int TextArea::GetVisibleRowCount()
{
return (Height-5) / ftext->maxHeight;
}
/** Returns top index */
int TextArea::GetTopIndex()
{
return startrow;
}
/** Set Starting Row */
void TextArea::SetRow(int row)
{
if (row < rows) {
startrow = row;
}
Changed = true;
}
void TextArea::CalcRowCount()
{
int tr;
int w = Width;
if (Flags&IE_GUI_TEXTAREA_SPEAKER) {
const char *portrait = NULL;
Actor *actor = NULL;
GameControl *gc = core->GetGameControl();
if (gc) {
Scriptable *target = gc->dialoghandler->GetTarget();
if (target && target->Type == ST_ACTOR) {
actor = (Actor *)target;
}
}
if (actor) {
portrait = actor->GetPortrait(1);
}
if (portrait) {
RefreshSprite(portrait);
}
if (AnimPicture) {
w-=AnimPicture->Width;
}
}
rows = 0;
if (lines.size() != 0) {
for (size_t i = 0; i < lines.size(); i++) {
// rows++;
tr = 0;
int len = ( int ) strlen( lines[i] );
char* tmp = (char *) malloc( len + 1 );
memcpy( tmp, lines[i], len + 1 );
ftext->SetupString( tmp, w );
for (int p = 0; p <= len; p++) {
if (( ( unsigned char ) tmp[p] ) == '[') {
p++;
//char tag[256];
int k = 0;
for (k = 0; k < 256; k++) {
if (tmp[p] == ']') {
//tag[k] = 0;
break;
}
p++;
//tag[k] = tmp[p++];
}
continue;
}
if (tmp[p] == 0) {
// if (p != len)
// rows++;
tr++;
}
}
lrows[i] = tr;
rows += tr;
free( tmp );
}
}
if (lines.size())
{
if (CurLine>=lines.size()) {
CurLine=lines.size()-1;
}
w = strlen(lines[CurLine]);
if (CurPos>w) {
CurPos = w;
}
} else {
CurLine=0;
CurPos=0;
}
if (!sb) {
return;
}
ScrollBar* bar = ( ScrollBar* ) sb;
tr = rows - Height/ftext->size[1].h + 1;
if (tr<0) {
tr = 0;
}
bar->SetMax( (ieWord) tr );
}
/** Mouse Over Event */
void TextArea::OnMouseOver(unsigned short /*x*/, unsigned short y)
{
int height = ftext->maxHeight; //size[1].h;
int r = y / height;
int row = 0;
for (size_t i = 0; i < lines.size(); i++) {
row += lrows[i];
if (r < ( row - startrow )) {
if (seltext != (int) i)
core->RedrawAll();
seltext = ( int ) i;
//printf("CtrlId = 0x%08lx, seltext = %d, rows = %d, row = %d, r = %d\n", ControlID, i, rows, row, r);
return;
}
}
if (seltext != -1) {
core->RedrawAll();
}
seltext = -1;
//printf("CtrlId = 0x%08lx, seltext = %d, rows %d, row %d, r = %d\n", ControlID, seltext, rows, row, r);
}
/** Mouse Button Up */
void TextArea::OnMouseUp(unsigned short x, unsigned short y, unsigned short /*Button*/,
unsigned short /*Mod*/)
{
if (( x <= Width ) && ( y <= ( Height - 5 ) ) && ( seltext != -1 )) {
Value = (unsigned int) seltext;
Changed = true;
if (strnicmp( lines[seltext], "[s=", 3 ) == 0) {
if (minrow > seltext)
return;
int idx;
sscanf( lines[seltext], "[s=%d,", &idx );
GameControl* gc = core->GetGameControl();
if (gc && (gc->GetDialogueFlags()&DF_IN_DIALOG) ) {
if (idx==-1) {
//this kills this object, don't use any more data!
gc->dialoghandler->EndDialog();
return;
}
gc->dialoghandler->DialogChoose( idx );
return;
}
}
}
if (VarName[0] != 0) {
core->GetDictionary()->SetAt( VarName, Value );
}
RunEventHandler( TextAreaOnChange );
}
/** Copies the current TextArea content to another TextArea control */
void TextArea::CopyTo(TextArea* ta)
{
ta->Clear();
for (size_t i = 0; i < lines.size(); i++) {
ta->SetText( lines[i], -1 );
}
}
void TextArea::RedrawTextArea(const char* VariableName, unsigned int Sum)
{
if (strnicmp( VarName, VariableName, MAX_VARIABLE_LENGTH )) {
return;
}
Value = Sum;
Changed = true;
}
const char* TextArea::QueryText()
{
if ( Value<lines.size() ) {
return ( const char * ) lines[Value];
}
return ( const char *) "";
}
bool TextArea::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_TEXTAREA_ON_CHANGE:
TextAreaOnChange = handler;
break;
case IE_GUI_TEXTAREA_OUT_OF_TEXT:
TextAreaOutOfText = handler;
break;
default:
return false;
}
return true;
}
void TextArea::PadMinRow()
{
int row = 0;
int i=(int) (lines.size()-1);
//minrow -1 ->gap
//minrow -2 ->npc text
while (i>=minrow-2 && i>=0) {
row+=lrows[i];
i--;
}
row = GetVisibleRowCount()-row;
while (row>0) {
AppendText("",-1);
row--;
}
}
void TextArea::SetPreservedRow(int arg)
{
keeplines=arg;
Flags |= IE_GUI_TEXTAREA_HISTORY;
}
void TextArea::Clear()
{
for (size_t i = 0; i < lines.size(); i++) {
free( lines[i] );
}
lines.clear();
lrows.clear();
rows = 0;
}
//setting up the textarea for smooth scrolling, the first
//TEXTAREA_OUTOFTEXT callback is called automatically
void TextArea::SetupScroll(unsigned long tck)
{
SetPreservedRow(0);
smooth = ftext->maxHeight;
startrow = 0;
ticks = tck;
//clearing the textarea
Clear();
unsigned int i = (unsigned int) (Height/smooth);
while (i--) {
char *str = (char *) malloc(1);
str[0]=0;
lines.push_back(str);
lrows.push_back(0);
}
i = (unsigned int) lines.size();
Flags |= IE_GUI_TEXTAREA_SMOOTHSCROLL;
GetTime( starttime );
if (RunEventHandler( TextAreaOutOfText )) {
//event handler destructed this object?
return;
}
if (i==lines.size()) {
ResetEventHandler( TextAreaOutOfText );
return;
}
//recalculates rows
AppendText("\n",-1);
}
void TextArea::OnMouseDown(unsigned short /*x*/, unsigned short /*y*/, unsigned short Button,
unsigned short /*Mod*/)
{
ScrollBar* scrlbr = (ScrollBar*) sb;
if (!scrlbr) {
Control *ctrl = Owner->GetScrollControl();
if (ctrl && (ctrl->ControlType == IE_GUI_SCROLLBAR)) {
scrlbr = (ScrollBar *) ctrl;
}
}
if (scrlbr) {
switch(Button) {
case GEM_MB_SCRLUP:
scrlbr->ScrollUp();
core->RedrawAll();
break;
case GEM_MB_SCRLDOWN:
scrlbr->ScrollDown();
core->RedrawAll();
break;
}
}
}

View File

@@ -0,0 +1,175 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file TextArea.h
* Declares TextArea widget for displaying long paragraphs of text
* @author The GemRB Project
*/
#ifndef TEXTAREA_H
#define TEXTAREA_H
#include "GUI/Control.h"
#include "GUI/ScrollBar.h"
#include "RGBAColor.h"
#include "exports.h"
#include "Font.h"
// Keep these synchronized with GUIDefines.py
// 0x05 is the control type of TextArea
#define IE_GUI_TEXTAREA_ON_CHANGE 0x05000000
#define IE_GUI_TEXTAREA_OUT_OF_TEXT 0x05000001
// TextArea flags, keep these in sync too
// the control type is intentionally left out
#define IE_GUI_TEXTAREA_SELECTABLE 1
#define IE_GUI_TEXTAREA_AUTOSCROLL 2
#define IE_GUI_TEXTAREA_SMOOTHSCROLL 4
#define IE_GUI_TEXTAREA_HISTORY 8
#define IE_GUI_TEXTAREA_SPEAKER 16
#define IE_GUI_TEXTAREA_ALT_FONT 32 //this one disables drop capitals
#define IE_GUI_TEXTAREA_EDITABLE 64
// internal flags
#define TA_INITIALS 1
#define TA_BITEMYTAIL 2
/**
* @class TextArea
* Widget capable of displaying long paragraphs of text.
* It is usually scrolled with a ScrollBar widget
*/
class GEM_EXPORT TextArea : public Control {
public:
TextArea(Color hitextcolor, Color initcolor, Color lowtextcolor);
~TextArea(void);
/** global configuration */
static void SetNoteString(const char *s);
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Sets the Actual Text */
int SetText(const char* text, int pos = 0);
/** Clears the textarea */
void Clear();
/** Discards scrolled out lines from the textarea */
/** preserving 'keeplines' lines for scroll back history */
void DiscardLines();
/** Appends a String to the current Text */
int AppendText(const char* text, int pos = 0);
/** Deletes `count' lines (either last or top lines)*/
void PopLines(unsigned int count, bool top = false);
/** Deletes last lines up to current 'minrow' */
void PopMinRow()
{
PopLines((unsigned int) (lines.size()-minrow));
}
/** adds empty lines so minrow will be the uppermost visible row */
void PadMinRow();
/** Sets up scrolling, tck is the scrolling speed */
void SetupScroll(unsigned long tck);
/** Sets the Fonts */
void SetFonts(Font* init, Font* text);
/** Returns Number of Rows */
int GetRowCount();
/** Returns the length of a Row */
int GetRowLength(unsigned int row);
/** Returns Number of Visible Rows */
int GetVisibleRowCount();
/** Returns Starting Row */
int GetTopIndex();
/** Set Starting Row */
void SetRow(int row);
/** Sets preserved lines */
void SetPreservedRow(int arg);
/** Set Selectable */
void SetSelectable(bool val);
/** Set Minimum Selectable Row (to the current ceiling) */
void SetMinRow(bool enable);
/** Copies the current TextArea content to another TextArea control */
void CopyTo(TextArea* ta);
/** Returns the selected text */
const char* QueryText();
/** Marks textarea for redraw with a new value */
void RedrawTextArea(const char* VariableName, unsigned int Sum);
int SetScrollBar(Control *ptr);
private: // Private attributes
std::vector< char*> lines;
std::vector< int> lrows;
int seltext;
/** minimum selectable row */
int minrow;
/** lines to be kept even if scrolled out */
int keeplines;
/** vertical offset for smooth scrolling */
int smooth;
/** timer for scrolling */
unsigned long starttime;
/** timer ticks for scrolling (speed) */
unsigned long ticks;
/** Number of Text Rows */
int rows;
/** Starting Row */
int startrow;
/** Text Colors */
Palette* palette;
Palette* initpalette;
Palette* selected;
Palette* lineselpal;
/** a hack for smooth windows, drop capitals */
ieDword InternalFlags;
/** Fonts */
Font* finit, * ftext;
ieResRef PortraitResRef;
/** Text Editing Cursor Sprite */
Sprite2D* Cursor;
unsigned short CurPos, CurLine;
private: //internal functions
void CalcRowCount();
void UpdateControls();
void RefreshSprite(const char *portrait);
public: //Events
/** Key Press Event */
void OnKeyPress(unsigned char Key, unsigned short Mod);
/** Special Key Press */
void OnSpecialKeyPress(unsigned char Key);
/** Mouse Over Event */
void OnMouseOver(unsigned short x, unsigned short y);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse button down*/
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
/** OnChange Scripted Event Function Name */
EventHandler TextAreaOnChange;
/** OutOfText Scripted Event Function Name */
EventHandler TextAreaOutOfText;
};
#endif

View File

@@ -0,0 +1,231 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/TextEdit.h"
#include "GameData.h"
#include "Interface.h"
#include "Palette.h"
#include "Video.h"
TextEdit::TextEdit(unsigned short maxLength, unsigned short px, unsigned short py)
{
max = maxLength;
FontPosX = px;
FontPosY = py;
Buffer = ( unsigned char * ) malloc( max + 1 );
font = NULL;
Cursor = NULL;
Back = NULL;
CurPos = 0;
Buffer[0] = 0;
ResetEventHandler( EditOnChange );
ResetEventHandler( EditOnDone );
ResetEventHandler( EditOnCancel );
Color white = {0xff, 0xff, 0xff, 0x00}, black = {0x00, 0x00, 0x00, 0x00};
palette = core->CreatePalette( white, black );
}
TextEdit::~TextEdit(void)
{
Video *video = core->GetVideoDriver();
gamedata->FreePalette( palette );
free( Buffer );
video->FreeSprite( Back );
video->FreeSprite( Cursor );
}
/** Draws the Control on the Output Display */
void TextEdit::Draw(unsigned short x, unsigned short y)
{
if (!Changed && !(Owner->Flags&WF_FLOAT)) {
return;
}
Changed = false;
if (Back) {
core->GetVideoDriver()->BlitSprite( Back, x + XPos, y + YPos, true );
}
if (!font)
return;
//The aligning of textedit fields is done by absolute positioning (FontPosX, FontPosY)
if (hasFocus) {
font->Print( Region( x + XPos + FontPosX, y + YPos + FontPosY, Width, Height ), Buffer,
palette, IE_FONT_ALIGN_LEFT | IE_FONT_ALIGN_TOP,
true, NULL, Cursor, CurPos );
} else {
font->Print( Region( x + XPos + FontPosX, y + YPos + FontPosY, Width, Height ), Buffer,
palette, IE_FONT_ALIGN_LEFT | IE_FONT_ALIGN_TOP, true );
}
}
/** Set Font */
void TextEdit::SetFont(Font* f)
{
if (f != NULL) {
font = f;
Changed = true;
return;
}
printMessage("TextEdit","Invalid font set!\n", LIGHT_RED);
}
Font *TextEdit::GetFont() { return font; }
/** Set Cursor */
void TextEdit::SetCursor(Sprite2D* cur)
{
core->GetVideoDriver()->FreeSprite( Cursor );
if (cur != NULL) {
Cursor = cur;
}
Changed = true;
}
/** Set BackGround */
void TextEdit::SetBackGround(Sprite2D* back)
{
//if 'back' is NULL then no BackGround will be drawn
if (Back)
core->GetVideoDriver()->FreeSprite(Back);
Back = back;
Changed = true;
}
/** Key Press Event */
void TextEdit::OnKeyPress(unsigned char Key, unsigned short /*Mod*/)
{
if (Key >= 0x20) {
if (Value && ( (Key<'0') || (Key>'9') ) )
return;
Owner->Invalidate();
Changed = true;
int len = ( int ) strlen( ( char* ) Buffer );
if (len + 1 < max) {
for (int i = len; i > CurPos; i--) {
Buffer[i] = Buffer[i - 1];
}
Buffer[CurPos] = Key;
Buffer[len + 1] = 0;
CurPos++;
}
RunEventHandler( EditOnChange );
}
}
/** Special Key Press */
void TextEdit::OnSpecialKeyPress(unsigned char Key)
{
int len;
Owner->Invalidate();
Changed = true;
switch (Key) {
case GEM_HOME:
CurPos = 0;
break;
case GEM_END:
CurPos = (ieWord) strlen( (char * ) Buffer);
break;
case GEM_LEFT:
if (CurPos > 0)
CurPos--;
break;
case GEM_RIGHT:
len = ( int ) strlen( ( char * ) Buffer );
if (CurPos < len) {
CurPos++;
}
break;
case GEM_DELETE:
len = ( int ) strlen( ( char * ) Buffer );
if (CurPos < len) {
for (int i = CurPos; i < len; i++) {
Buffer[i] = Buffer[i + 1];
}
}
break;
case GEM_BACKSP:
if (CurPos != 0) {
int len = ( int ) strlen( ( char* ) Buffer );
for (int i = CurPos; i < len; i++) {
Buffer[i - 1] = Buffer[i];
}
Buffer[len - 1] = 0;
CurPos--;
}
break;
case GEM_RETURN:
RunEventHandler( EditOnDone );
return;
}
RunEventHandler( EditOnChange );
}
/** Sets the Text of the current control */
int TextEdit::SetText(const char* string, int /*pos*/)
{
strncpy( ( char * ) Buffer, string, max );
Buffer[max]=0;
CurPos = (ieWord) strlen((char *) Buffer);
if (Owner) {
Owner->Invalidate();
}
return 0;
}
void TextEdit::SetBufferLength(ieWord buflen)
{
if(buflen<1) return;
if(buflen!=max) {
Buffer = (unsigned char *) realloc(Buffer, buflen+1);
max=(ieWord) buflen;
Buffer[max]=0;
}
}
/** Simply returns the pointer to the text, don't modify it! */
const char* TextEdit::QueryText()
{
return ( const char * ) Buffer;
}
bool TextEdit::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_EDIT_ON_CHANGE:
EditOnChange = handler;
break;
case IE_GUI_EDIT_ON_DONE:
EditOnDone = handler;
break;
case IE_GUI_EDIT_ON_CANCEL:
EditOnCancel = handler;
break;
default:
return false;
}
return true;
}

View File

@@ -0,0 +1,101 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file TextEdit.h
* Declares TextEdit widget for displaying single line text input field
* @author The GemRB Project
*/
#ifndef TEXTEDIT_H
#define TEXTEDIT_H
#include "GUI/Control.h"
#include "RGBAColor.h"
#include "exports.h"
#include "Font.h"
class Palette;
// !!! Keep these synchronized with GUIDefines.py
#define IE_GUI_EDIT_ON_CHANGE 0x03000000
#define IE_GUI_EDIT_ON_DONE 0x03000001
#define IE_GUI_EDIT_ON_CANCEL 0x03000002
//this is stored in 'Value' of Control class
#define IE_GUI_EDIT_NUMBER 1
/**
* @class TextEdit
* Widget displaying single line text input field
*/
class GEM_EXPORT TextEdit : public Control {
public:
TextEdit(unsigned short maxLength, unsigned short x, unsigned short y);
~TextEdit(void);
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Set Font */
void SetFont(Font* f);
Font *GetFont();
/** Set Cursor */
void SetCursor(Sprite2D* cur);
/** Set BackGround */
void SetBackGround(Sprite2D* back);
/** Sets the Text of the current control */
int SetText(const char* string, int pos = 0);
/** Sets the Text of the current control */
const char* QueryText();
/** Sets the buffer length */
void SetBufferLength(ieWord buflen);
private:
/** Text Editing Cursor Sprite */
Sprite2D* Cursor;
/** Text Font */
Font* font;
/** Background */
Sprite2D* Back;
/** Max Edit Text Length */
unsigned short max;
/** Client area position */
unsigned short FontPosX, FontPosY;
/** Text Buffer */
unsigned char* Buffer;
/** Cursor Position */
unsigned short CurPos;
/** Color Palette */
Palette* palette;
public: //Events
/** Key Press Event */
void OnKeyPress(unsigned char Key, unsigned short Mod);
/** Special Key Press */
void OnSpecialKeyPress(unsigned char Key);
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
/** OnChange Scripted Event Function Name */
EventHandler EditOnChange;
EventHandler EditOnDone;
EventHandler EditOnCancel;
};
#endif

View File

@@ -0,0 +1,442 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GUI/Window.h"
#include "GUI/Button.h"
#include "GUI/Control.h"
#include "GUI/MapControl.h"
#include "GUI/Progressbar.h"
#include "GUI/Slider.h"
#include "win32def.h"
#include "Interface.h"
#include "Video.h"
Window::Window(unsigned short WindowID, unsigned short XPos,
unsigned short YPos, unsigned short Width, unsigned short Height)
{
this->WindowID = WindowID;
this->XPos = XPos;
this->YPos = YPos;
this->Width = Width;
this->Height = Height;
this->BackGround = NULL;
lastC = NULL;
lastFocus = NULL;
lastMouseFocus = NULL;
lastOver = NULL;
Visible = WINDOW_INVISIBLE;
Flags = WF_CHANGED;
Cursor = IE_CURSOR_NORMAL;
DefaultControl[0] = -1;
DefaultControl[1] = -1;
ScrollControl = -1;
}
Window::~Window()
{
std::vector< Control*>::iterator m = Controls.begin();
while (Controls.size() != 0) {
Control* ctrl = ( *m );
delete ctrl;
Controls.erase( m );
m = Controls.begin();
}
core->GetVideoDriver()->FreeSprite( BackGround );
BackGround = NULL;
}
/** Add a Control in the Window */
void Window::AddControl(Control* ctrl)
{
if (ctrl == NULL) {
return;
}
ctrl->Owner = this;
for (size_t i = 0; i < Controls.size(); i++) {
if (Controls[i]->ControlID == ctrl->ControlID) {
delete( Controls[i] );
Controls[i] = ctrl;
Invalidate();
return;
}
}
Controls.push_back( ctrl );
Invalidate();
}
/** Set the Window's BackGround Image. If 'img' is NULL, no background will be set. If the 'clean' parameter is true (default is false) the old background image will be deleted. */
void Window::SetBackGround(Sprite2D* img, bool clean)
{
if (clean && BackGround) {
core->GetVideoDriver()->FreeSprite( this->BackGround );
}
BackGround = img;
Invalidate();
}
/** This function Draws the Window on the Output Screen */
void Window::DrawWindow()
{
Video* video = core->GetVideoDriver();
Region clip( XPos, YPos, Width, Height );
//Frame && Changed
if ( (Flags & (WF_FRAME|WF_CHANGED) )== (WF_FRAME|WF_CHANGED) ) {
Region screen( 0, 0, core->Width, core->Height );
video->SetClipRect( NULL );
//removed this?
Color black = { 0, 0, 0, 255 };
video->DrawRect( screen, black );
if (core->WindowFrames[0])
video->BlitSprite( core->WindowFrames[0], 0, 0, true );
if (core->WindowFrames[1])
video->BlitSprite( core->WindowFrames[1], core->Width - core->WindowFrames[1]->Width, 0, true );
if (core->WindowFrames[2])
video->BlitSprite( core->WindowFrames[2], (core->Width - core->WindowFrames[2]->Width) / 2, 0, true );
if (core->WindowFrames[3])
video->BlitSprite( core->WindowFrames[3], (core->Width - core->WindowFrames[3]->Width) / 2, core->Height - core->WindowFrames[3]->Height, true );
} else if (clip_regions.size()) {
// clip drawing (we only do Background right now) for InvalidateForControl
for (unsigned int i = 0; i < clip_regions.size(); i++) {
Region to_clip = clip_regions[i];
to_clip.x += XPos;
to_clip.y += YPos;
video->SetClipRect(&to_clip);
if (BackGround) {
video->BlitSprite( BackGround, XPos, YPos, true );
}
}
}
clip_regions.clear();
video->SetClipRect( &clip );
//Float || Changed
if (BackGround && (Flags & (WF_FLOAT|WF_CHANGED) ) ) {
video->BlitSprite( BackGround, XPos, YPos, true );
}
std::vector< Control*>::iterator m;
for (m = Controls.begin(); m != Controls.end(); ++m) {
( *m )->Draw( XPos, YPos );
}
if ( (Flags&WF_CHANGED) && (Visible == WINDOW_GRAYED) ) {
Color black = { 0, 0, 0, 128 };
video->DrawRect(clip, black);
}
video->SetClipRect( NULL );
Flags &= ~WF_CHANGED;
}
/** Set window frame used to fill screen on higher resolutions*/
void Window::SetFrame()
{
if ( (Width < core->Width) || (Height < core->Height) ) {
Flags|=WF_FRAME;
}
Invalidate();
}
/** Returns the Control at X,Y Coordinates */
Control* Window::GetControl(unsigned short x, unsigned short y, bool ignore)
{
Control* ctrl = NULL;
//Check if we are still on the last control
if (( lastC != NULL )) {
if (( XPos + lastC->XPos <= x )
&& ( YPos + lastC->YPos <= y )
&& ( XPos + lastC->XPos + lastC->Width >= x )
&& ( YPos + lastC->YPos + lastC->Height >= y )
&& ! lastC->IsPixelTransparent (x - XPos - lastC->XPos, y - YPos - lastC->YPos)) {
//Yes, we are on the last returned Control
return lastC;
}
}
std::vector< Control*>::const_iterator m;
for (m = Controls.begin(); m != Controls.end(); m++) {
if (ignore && (*m)->ControlID&IGNORE_CONTROL) {
continue;
}
if (( XPos + ( *m )->XPos <= x )
&& ( YPos + ( *m )->YPos <= y )
&& ( XPos + ( *m )->XPos + ( *m )->Width >= x )
&& ( YPos + ( *m )->YPos + ( *m )->Height >= y )
&& ! ( *m )->IsPixelTransparent (x - XPos - ( *m )->XPos, y - YPos - ( *m )->YPos)) {
ctrl = *m;
break;
}
}
lastC = ctrl;
return ctrl;
}
Control* Window::GetOver() const
{
return lastOver;
}
Control* Window::GetFocus() const
{
return lastFocus;
}
Control* Window::GetMouseFocus() const
{
return lastMouseFocus;
}
/** Sets 'ctrl' as Focused */
void Window::SetFocused(Control* ctrl)
{
if (lastFocus != NULL) {
lastFocus->hasFocus = false;
lastFocus->Changed = true;
}
lastFocus = ctrl;
if (ctrl != NULL) {
lastFocus->hasFocus = true;
lastFocus->Changed = true;
}
}
/** Sets 'ctrl' as Mouse Focused */
void Window::SetMouseFocused(Control* ctrl)
{
if (lastMouseFocus != NULL) {
lastMouseFocus->Changed = true;
}
lastMouseFocus = ctrl;
if (ctrl != NULL) {
lastMouseFocus->Changed = true;
}
}
unsigned int Window::GetControlCount() const
{
return Controls.size();
}
Control* Window::GetControl(unsigned short i) const
{
if (i < Controls.size()) {
return Controls[i];
}
return NULL;
}
bool Window::IsValidControl(unsigned short ID, Control *ctrl) const
{
size_t i = Controls.size();
while (i--) {
if (Controls[i]==ctrl) {
return ctrl->ControlID==ID;
}
}
return false;
}
void Window::DelControl(unsigned short i)
{
if (i < Controls.size() ) {
Control *ctrl = Controls[i];
if (ctrl==lastC) {
lastC=NULL;
}
if (ctrl==lastOver) {
lastOver=NULL;
}
if (ctrl==lastFocus) {
lastFocus=NULL;
}
if (ctrl==lastMouseFocus) {
lastMouseFocus=NULL;
}
delete ctrl;
Controls.erase(Controls.begin()+i);
}
Invalidate();
}
Control* Window::GetDefaultControl(unsigned int ctrltype) const
{
if (!Controls.size()) {
return NULL;
}
if (ctrltype>=2) {
return NULL;
}
return GetControl( (ieWord) DefaultControl[ctrltype] );
}
Control* Window::GetScrollControl() const
{
if (!Controls.size()) {
return NULL;
}
return GetControl( (ieWord) ScrollControl );
}
void Window::release(void)
{
Visible = WINDOW_INVALID;
lastC = NULL;
lastFocus = NULL;
lastMouseFocus = NULL;
lastOver = NULL;
}
/** Redraw all the Window */
void Window::Invalidate()
{
DefaultControl[0] = -1;
DefaultControl[1] = -1;
ScrollControl = -1;
for (unsigned int i = 0; i < Controls.size(); i++) {
if (!Controls[i]) {
continue;
}
Controls[i]->Changed = true;
switch (Controls[i]->ControlType) {
case IE_GUI_SCROLLBAR:
if ((ScrollControl == -1) || (Controls[i]->Flags & IE_GUI_SCROLLBAR_DEFAULT))
ScrollControl = i;
break;
case IE_GUI_BUTTON:
if (( Controls[i]->Flags & IE_GUI_BUTTON_DEFAULT )) {
DefaultControl[0] = i;
}
if (( Controls[i]->Flags & IE_GUI_BUTTON_CANCEL )) {
DefaultControl[1] = i;
}
break;
//falling through
case IE_GUI_GAMECONTROL:
DefaultControl[0] = i;
DefaultControl[1] = i;
break;
default: ;
}
}
Flags |= WF_CHANGED;
}
/** Redraw enough to update the specified Control */
void Window::InvalidateForControl(Control *ctrl) {
// TODO: for this to be general-purpose, we should mark anything inside this
// region with Changed, and also do mass Invalidate() if we overlap with
// another window, but for now this just clips the *background*, see DrawWindow()
clip_regions.push_back( Region(ctrl->XPos, ctrl->YPos, ctrl->Width, ctrl->Height) );
}
void Window::RedrawControls(const char* VarName, unsigned int Sum)
{
for (unsigned int i = 0; i < Controls.size(); i++) {
switch (Controls[i]->ControlType) {
case IE_GUI_MAP:
{
MapControl *mc = ( MapControl* ) (Controls[i]);
mc->RedrawMapControl( VarName, Sum );
break;
}
case IE_GUI_BUTTON:
{
Button* bt = ( Button* ) ( Controls[i] );
bt->RedrawButton( VarName, Sum );
break;
}
case IE_GUI_TEXTAREA:
{
TextArea* pb = ( TextArea* ) ( Controls[i] );
pb->RedrawTextArea( VarName, Sum );
break;
}
case IE_GUI_PROGRESSBAR:
{
Progressbar* pb = ( Progressbar* ) ( Controls[i] );
pb->RedrawProgressbar( VarName, Sum );
break;
}
case IE_GUI_SLIDER:
{
Slider* sl = ( Slider* ) ( Controls[i] );
sl->RedrawSlider( VarName, Sum );
break;
}
case IE_GUI_SCROLLBAR:
{
ScrollBar* sb = ( ScrollBar* ) ( Controls[i] );
sb->RedrawScrollBar( VarName, Sum );
break;
}
}
}
}
/** Searches for a ScrollBar and a TextArea to link them */
void Window::Link(unsigned short SBID, unsigned short TAID)
{
ScrollBar* sb = NULL;
TextArea* ta = NULL;
std::vector< Control*>::iterator m;
for (m = Controls.begin(); m != Controls.end(); m++) {
if (( *m )->Owner != this)
continue;
if (( *m )->ControlType == IE_GUI_SCROLLBAR) {
if (( *m )->ControlID == SBID) {
sb = ( ScrollBar * ) ( *m );
if (ta != NULL)
break;
}
} else if (( *m )->ControlType == IE_GUI_TEXTAREA) {
if (( *m )->ControlID == TAID) {
ta = ( TextArea * ) ( *m );
if (sb != NULL)
break;
}
}
}
if (sb && ta) {
sb->ta = ta;
ta->SetScrollBar( sb );
}
}
void Window::OnMouseEnter(unsigned short x, unsigned short y, Control *ctrl)
{
lastOver = ctrl;
if (!lastOver) {
return;
}
lastOver->OnMouseEnter( x - XPos - lastOver->XPos, y - YPos - lastOver->YPos );
}
void Window::OnMouseLeave(unsigned short x, unsigned short y)
{
if (!lastOver) {
return;
}
lastOver->OnMouseLeave( x - XPos - lastOver->XPos, y - YPos - lastOver->YPos );
lastOver = NULL;
}
void Window::OnMouseOver(unsigned short x, unsigned short y)
{
if (!lastOver) {
return;
}
lastOver->OnMouseOver( x - XPos - lastOver->XPos, y - YPos - lastOver->YPos );
}

View File

@@ -0,0 +1,190 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Window.h
* Declares Window, class serving as a container for Control/widget objects
* and displaying windows in GUI
* @author The GemRB Project
*/
#ifndef WINDOW_H
#define WINDOW_H
#include "GUI/Control.h"
#include "GUI/ScrollBar.h"
#include "GUI/TextArea.h"
#include "exports.h"
#include "Sprite2D.h"
#include <vector>
// Window Flags
#define WF_CHANGED 1 //window changed
#define WF_FRAME 2 //window has frame
#define WF_FLOAT 4 //floating window
#define WF_CHILD 8 //if invalidated, it invalidates all windows on top of it
// Window position anchors (actually flags for WindowSetPos())
// !!! Keep these synchronized with GUIDefines.py !!!
#define WINDOW_TOPLEFT 0x00
#define WINDOW_CENTER 0x01
#define WINDOW_ABSCENTER 0x02
#define WINDOW_RELATIVE 0x04
#define WINDOW_SCALE 0x08
#define WINDOW_BOUNDED 0x10
// IE specific cursor types
#define IE_CURSOR_INVALID -1
#define IE_CURSOR_NORMAL 0
#define IE_CURSOR_TAKE 2 //over pile type containers
#define IE_CURSOR_WALK 4
#define IE_CURSOR_BLOCKED 6
#define IE_CURSOR_USE 8 //never hardcoded
#define IE_CURSOR_WAIT 10 //hourglass
#define IE_CURSOR_ATTACK 12
#define IE_CURSOR_SWAP 14 //dragging portraits
#define IE_CURSOR_DEFEND 16
#define IE_CURSOR_TALK 18
#define IE_CURSOR_CAST 20 //targeting with non weapon
#define IE_CURSOR_INFO 22 //never hardcoded
#define IE_CURSOR_LOCK 24 //locked door
#define IE_CURSOR_LOCK2 26 //locked container
#define IE_CURSOR_STAIR 28 //never hardcoded
#define IE_CURSOR_DOOR 30 //doors
#define IE_CURSOR_CHEST 32
#define IE_CURSOR_TRAVEL 34
#define IE_CURSOR_STEALTH 36
#define IE_CURSOR_TRAP 38
#define IE_CURSOR_PICK 40 //pickpocket
#define IE_CURSOR_PASS 42 //never hardcoded
#define IE_CURSOR_GRAB 44
#define IE_CURSOR_WAY 46 //waypoint (not in PST)
#define IE_CURSOR_INFO2 46 //PST
#define IE_CURSOR_PORTAL 48 //PST
#define IE_CURSOR_STAIR2 50 //PST
#define IE_CURSOR_EXTRA 52 //PST
#define IE_CURSOR_MASK 127
#define IE_CURSOR_GRAY 128
/**
* @class Window
* Class serving as a container for Control/widget objects
* and displaying windows in GUI.
*/
class GEM_EXPORT Window {
public:
Window(unsigned short WindowID, unsigned short XPos, unsigned short YPos,
unsigned short Width, unsigned short Height);
~Window();
/** Set the Window's BackGround Image.
* If 'img' is NULL, no background will be set. If the 'clean' parameter is true (default is false) the old background image will be deleted. */
void SetBackGround(Sprite2D* img, bool clean = false);
/** Add a Control in the Window */
void AddControl(Control* ctrl);
/** This function Draws the Window on the Output Screen */
void DrawWindow();
/** Set window frame used to fill screen on higher resolutions*/
void SetFrame();
/** Returns the Control at X,Y Coordinates */
Control* GetControl(unsigned short x, unsigned short y, bool ignore=0);
/** Returns the Control by Index */
Control* GetControl(unsigned short i) const;
/** Returns the number of Controls */
unsigned int GetControlCount() const;
/** Returns true if ctrl is valid and ctrl->ControlID is ID */
bool IsValidControl(unsigned short ID, Control *ctrl) const;
/** Deletes the xth. Control */
void DelControl(unsigned short i);
/** Returns the Default Control which may be a button/gamecontrol atm */
Control* GetDefaultControl(unsigned int ctrltype) const;
/** Returns the Control which should get mouse scroll events */
Control* GetScrollControl() const;
/** Sets 'ctrl' as currently under mouse */
void SetOver(Control* ctrl);
/** Returns last control under mouse */
Control* GetOver() const;
/** Sets 'ctrl' as Focused */
void SetFocused(Control* ctrl);
/** Sets 'ctrl' as mouse event Focused */
void SetMouseFocused(Control* ctrl);
/** Returns last focused control */
Control* GetFocus() const;
/** Returns last mouse event focused control */
Control* GetMouseFocus() const;
/** Redraw all the Window */
void Invalidate();
/** Redraw enough to update the specified Control */
void InvalidateForControl(Control *ctrl);
/** Redraw controls of the same group */
void RedrawControls(const char* VarName, unsigned int Sum);
/** Links a scrollbar to a text area */
void Link(unsigned short SBID, unsigned short TAID);
/** Mouse entered a new control's rectangle */
void OnMouseEnter(unsigned short x, unsigned short y, Control *ctrl);
/** Mouse left the current control */
void OnMouseLeave(unsigned short x, unsigned short y);
/** Mouse is over the current control */
void OnMouseOver(unsigned short x, unsigned short y);
public: //Public attributes
/** WinPack */
char WindowPack[10];
/** Window ID */
unsigned short WindowID;
/** X Position */
unsigned short XPos;
/** Y Position */
unsigned short YPos;
/** Width */
unsigned short Width;
/** Height */
unsigned short Height;
/** Visible value: deleted, invisible, visible, grayed */
signed char Visible; //-1,0,1,2
/** Window flags: Changed, Floating, Framed, Child */
int Flags;
int Cursor;
int DefaultControl[2]; //default enter and cancel
int ScrollControl;
private: // Private attributes
/** BackGround Image. No BackGround if this variable is NULL. */
Sprite2D* BackGround;
/** Controls Array */
std::vector< Control*> Controls;
/** Last Control returned by GetControl */
Control* lastC;
/** Last Focused Control */
Control* lastFocus;
/** Last mouse event Focused Control */
Control* lastMouseFocus;
/** Last Control under mouse */
Control* lastOver;
/** Regions which need to be redrawn */
std::vector< Region> clip_regions;
public:
void release(void);
};
#endif

View File

@@ -0,0 +1,399 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "GUI/WorldMapControl.h"
#include "win32def.h"
#include "Game.h"
#include "GameData.h"
#include "Interface.h"
#include "Video.h"
#include "WorldMap.h"
#define MAP_TO_SCREENX(x) XWin + XPos - ScrollX + (x)
#define MAP_TO_SCREENY(y) YWin + YPos - ScrollY + (y)
WorldMapControl::WorldMapControl(const char *font, int direction)
{
ScrollX = 0;
ScrollY = 0;
MouseIsDown = false;
Changed = true;
Area = NULL;
Value = direction;
Game* game = core->GetGame();
WorldMap* worldmap = core->GetWorldMap();
strncpy(currentArea, game->CurrentArea, 8);
int entry = core->GetAreaAlias(currentArea);
if (entry >= 0) {
WMPAreaEntry *m = worldmap->GetEntry(entry);
strncpy(currentArea, m->AreaResRef, 8);
}
//if there is no trivial area, look harder
if (!worldmap->GetArea(currentArea, (unsigned int &) entry) &&
core->HasFeature(GF_FLEXIBLE_WMAP) ) {
WMPAreaEntry *m = worldmap->FindNearestEntry(currentArea, (unsigned int &) entry);
if (m) {
strncpy(currentArea, m->AreaResRef, 8);
}
}
//this also updates visible locations
worldmap->CalculateDistances(currentArea, Value);
// alpha bit is unfortunately ignored
if (font[0]) {
ftext = core->GetFont(font);
} else {
ftext = NULL;
}
// initialize label colors
Color normal = { 0xf0, 0xf0, 0xf0, 0xff };
Color selected = { 0xf0, 0x80, 0x80, 0xff };
Color notvisited = { 0x80, 0x80, 0xf0, 0xff };
Color black = { 0x00, 0x00, 0x00, 0x00 };
pal_normal = core->CreatePalette ( normal, black );
pal_selected = core->CreatePalette ( selected, black );
pal_notvisited = core->CreatePalette ( notvisited, black );
ResetEventHandler( WorldMapControlOnPress );
ResetEventHandler( WorldMapControlOnEnter );
}
WorldMapControl::~WorldMapControl(void)
{
//Video *video = core->GetVideoDriver();
gamedata->FreePalette( pal_normal );
gamedata->FreePalette( pal_selected );
gamedata->FreePalette( pal_notvisited );
}
/** Draws the Control on the Output Display */
void WorldMapControl::Draw(unsigned short XWin, unsigned short YWin)
{
WorldMap* worldmap = core->GetWorldMap();
if (!Width || !Height) {
return;
}
if(!Changed)
return;
Changed = false;
Video* video = core->GetVideoDriver();
Region r( XWin+XPos, YWin+YPos, Width, Height );
Region clipbackup;
video->GetClipRect(clipbackup);
video->SetClipRect(&r);
video->BlitSprite( worldmap->GetMapMOS(), MAP_TO_SCREENX(0), MAP_TO_SCREENY(0), true, &r );
unsigned int i;
unsigned int ec = worldmap->GetEntryCount();
for(i=0;i<ec;i++) {
WMPAreaEntry *m = worldmap->GetEntry(i);
if (! (m->GetAreaStatus() & WMP_ENTRY_VISIBLE)) continue;
int xOffs = MAP_TO_SCREENX(m->X);
int yOffs = MAP_TO_SCREENY(m->Y);
Sprite2D* icon = m->GetMapIcon(worldmap->bam);
if( icon ) {
video->BlitSprite( icon, xOffs, yOffs, true, &r );
video->FreeSprite( icon );
}
if (AnimPicture && !strnicmp(m->AreaResRef, currentArea, 8) ) {
core->GetVideoDriver()->BlitSprite( AnimPicture, xOffs, yOffs, true, &r );
}
}
// Draw WMP entry labels
if (ftext==NULL) {
video->SetClipRect(&clipbackup);
return;
}
for(i=0;i<ec;i++) {
WMPAreaEntry *m = worldmap->GetEntry(i);
if (! (m->GetAreaStatus() & WMP_ENTRY_VISIBLE)) continue;
Sprite2D *icon=m->GetMapIcon(worldmap->bam);
int h=0,w=0,xpos=0,ypos=0;
if (icon) {
h=icon->Height;
w=icon->Width;
xpos=icon->XPos;
ypos=icon->YPos;
video->FreeSprite( icon );
}
Region r2 = Region( MAP_TO_SCREENX(m->X-xpos), MAP_TO_SCREENY(m->Y-ypos), w, h );
if (!m->GetCaption())
continue;
int tw = ftext->CalcStringWidth( m->GetCaption() ) + 5;
int th = ftext->maxHeight;
Palette* text_pal = pal_normal;
if (Area == m) {
text_pal = pal_selected;
} else {
if (! (m->GetAreaStatus() & WMP_ENTRY_VISITED)) {
text_pal = pal_notvisited;
}
}
ftext->Print( Region( r2.x + (r2.w - tw)/2, r2.y + r2.h, tw, th ),
( const unsigned char * ) m->GetCaption(), text_pal, 0, true );
}
video->SetClipRect(&clipbackup);
}
/** Key Release Event */
void WorldMapControl::OnKeyRelease(unsigned char Key, unsigned short Mod)
{
switch (Key) {
case 'f':
if (Mod & GEM_MOD_CTRL)
core->GetVideoDriver()->ToggleFullscreenMode();
break;
default:
break;
}
}
void WorldMapControl::AdjustScrolling(short x, short y)
{
WorldMap* worldmap = core->GetWorldMap();
if (x || y) {
ScrollX += x;
ScrollY += y;
} else {
//center worldmap on current area
unsigned entry;
WMPAreaEntry *m = worldmap->GetArea(currentArea,entry);
if (m) {
ScrollX = m->X - Width/2;
ScrollY = m->Y - Height/2;
}
}
Sprite2D *MapMOS = worldmap->GetMapMOS();
if (ScrollX > MapMOS->Width - Width)
ScrollX = MapMOS->Width - Width;
if (ScrollY > MapMOS->Height - Height)
ScrollY = MapMOS->Height - Height;
if (ScrollX < 0)
ScrollX = 0;
if (ScrollY < 0)
ScrollY = 0;
Changed = true;
Area = NULL;
}
/** Mouse Over Event */
void WorldMapControl::OnMouseOver(unsigned short x, unsigned short y)
{
WorldMap* worldmap = core->GetWorldMap();
lastCursor = IE_CURSOR_GRAB;
if (MouseIsDown) {
AdjustScrolling(lastMouseX-x, lastMouseY-y);
}
lastMouseX = x;
lastMouseY = y;
if (Value!=(ieDword) -1) {
x =(ieWord) (x + ScrollX);
y =(ieWord) (y + ScrollY);
WMPAreaEntry *oldArea = Area;
Area = NULL;
unsigned int i;
unsigned int ec = worldmap->GetEntryCount();
for (i=0;i<ec;i++) {
WMPAreaEntry *ae = worldmap->GetEntry(i);
if ( (ae->GetAreaStatus() & WMP_ENTRY_WALKABLE)!=WMP_ENTRY_WALKABLE) {
continue; //invisible or inaccessible
}
if (!strnicmp(ae->AreaResRef, currentArea, 8) ) {
continue; //current area
}
Sprite2D *icon=ae->GetMapIcon(worldmap->bam);
int h=0,w=0;
if (icon) {
h=icon->Height;
w=icon->Width;
core->GetVideoDriver()->FreeSprite( icon );
}
if (ftext && ae->GetCaption()) {
int tw = ftext->CalcStringWidth( ae->GetCaption() ) + 5;
int th = ftext->maxHeight;
if(h<th)
h=th;
if(w<tw)
w=tw;
}
if (ae->X > x) continue;
if (ae->X + w < x) continue;
if (ae->Y > y) continue;
if (ae->Y + h < y) continue;
lastCursor = IE_CURSOR_NORMAL;
Area=ae;
if(oldArea!=ae) {
RunEventHandler(WorldMapControlOnEnter);
}
break;
}
}
Owner->Cursor = lastCursor;
}
/** Sets the tooltip to be displayed on the screen now */
void WorldMapControl::DisplayTooltip()
{
if (Area) {
int x = Owner->XPos+XPos+lastMouseX;
int y = Owner->YPos+YPos+lastMouseY-50;
core->DisplayTooltip( x, y, this );
} else {
core->DisplayTooltip( 0, 0, NULL );
}
}
/** Mouse Leave Event */
void WorldMapControl::OnMouseLeave(unsigned short /*x*/, unsigned short /*y*/)
{
Owner->Cursor = IE_CURSOR_NORMAL;
Area = NULL;
}
/** Mouse Button Down */
void WorldMapControl::OnMouseDown(unsigned short x, unsigned short y,
unsigned short Button, unsigned short /*Mod*/)
{
switch(Button) {
case GEM_MB_ACTION:
MouseIsDown = true;
lastMouseX = x;
lastMouseY = y;
break;
case GEM_MB_SCRLUP:
OnSpecialKeyPress(GEM_UP);
break;
case GEM_MB_SCRLDOWN:
OnSpecialKeyPress(GEM_DOWN);
break;
}
}
/** Mouse Button Up */
void WorldMapControl::OnMouseUp(unsigned short /*x*/, unsigned short /*y*/,
unsigned short Button, unsigned short /*Mod*/)
{
if (Button != GEM_MB_ACTION) {
return;
}
if (lastCursor==IE_CURSOR_NORMAL) {
RunEventHandler( WorldMapControlOnPress );
}
MouseIsDown = false;
}
/** Special Key Press */
void WorldMapControl::OnSpecialKeyPress(unsigned char Key)
{
WorldMap* worldmap = core->GetWorldMap();
switch (Key) {
case GEM_LEFT:
ScrollX -= 64;
break;
case GEM_UP:
ScrollY -= 64;
break;
case GEM_RIGHT:
ScrollX += 64;
break;
case GEM_DOWN:
ScrollY += 64;
break;
case GEM_ALT:
printf( "ALT pressed\n" );
break;
case GEM_TAB:
printf( "TAB pressed\n" );
break;
}
Sprite2D *MapMOS = worldmap->GetMapMOS();
if (ScrollX > MapMOS->Width - Width)
ScrollX = MapMOS->Width - Width;
if (ScrollY > MapMOS->Height - Height)
ScrollY = MapMOS->Height - Height;
if (ScrollX < 0)
ScrollX = 0;
if (ScrollY < 0)
ScrollY = 0;
}
bool WorldMapControl::SetEvent(int eventType, EventHandler handler)
{
Changed = true;
switch (eventType) {
case IE_GUI_WORLDMAP_ON_PRESS:
WorldMapControlOnPress = handler;
break;
case IE_GUI_MOUSE_ENTER_WORLDMAP:
WorldMapControlOnEnter = handler;
break;
default:
return false;
}
return true;
}
void WorldMapControl::SetColor(int which, Color color)
{
Color black = { 0x00, 0x00, 0x00, 0x00 };
switch (which) {
case IE_GUI_WMAP_COLOR_NORMAL:
gamedata->FreePalette( pal_normal );
pal_normal = core->CreatePalette( color, black );
break;
case IE_GUI_WMAP_COLOR_SELECTED:
gamedata->FreePalette( pal_selected );
pal_selected = core->CreatePalette( color, black );
break;
case IE_GUI_WMAP_COLOR_NOTVISITED:
gamedata->FreePalette( pal_notvisited );
pal_notvisited = core->CreatePalette( color, black );
break;
default:
break;
}
Changed = true;
}

View File

@@ -0,0 +1,115 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file WorldMapControl.h
* Declares WorldMapControl, widget for displaying world map
*/
#ifndef WORLDMAPCONTROL_H
#define WORLDMAPCONTROL_H
#include "GUI/Control.h"
#include "exports.h"
#include "Dialog.h"
#include "Interface.h"
class Palette;
class WMPAreaEntry;
class WorldMapControl;
// !!! Keep these synchronized with GUIDefines.py !!!
/** Which label color is set with SetColor() */
#define IE_GUI_WMAP_COLOR_NORMAL 0
#define IE_GUI_WMAP_COLOR_SELECTED 1
#define IE_GUI_WMAP_COLOR_NOTVISITED 2
/**
* @class WorldMapControl
* Widget displaying "world" map, with particular locations and possibly
* allowing travelling between areas.
*/
#define IE_GUI_WORLDMAP_ON_PRESS 0x08000000
#define IE_GUI_MOUSE_ENTER_WORLDMAP 0x08000002
class GEM_EXPORT WorldMapControl : public Control {
public:
WorldMapControl(const char *fontname, int direction);
~WorldMapControl(void);
/** Allows modification of the scrolling factor from outside */
void AdjustScrolling(short x, short y);
/** Draws the Control on the Output Display */
void Draw(unsigned short x, unsigned short y);
/** Sets the exit direction (we need this to calculate distances) */
void SetDirection(int direction);
/** Sets the Text of the current control */
int SetText(const char* /*string*/, int /*pos*/) { return 0; }
/** Set color for one type of area labels */
void SetColor(int which, Color color);
int ScrollX, ScrollY;
unsigned short lastMouseX, lastMouseY;
bool MouseIsDown;
/** pointer to last pointed area */
WMPAreaEntry *Area;
/** Set handler for specified event */
bool SetEvent(int eventType, EventHandler handler);
private:
//font for printing area names
Font* ftext;
//mouse cursor
unsigned char lastCursor;
//current area
ieResRef currentArea;
/** Label color of a visited area */
Palette *pal_normal;
/** Label color of a currently selected area */
Palette *pal_selected;
/** Label color of a not yet visited area */
Palette *pal_notvisited;
/** guiscript Event when button pressed */
EventHandler WorldMapControlOnPress;
/** guiscript Event when mouse is over a reachable area */
EventHandler WorldMapControlOnEnter;
/** Mouse Over Event */
void OnMouseOver(unsigned short x, unsigned short y);
/** Mouse Leave Event */
void OnMouseLeave(unsigned short x, unsigned short y);
/** Mouse Button Down */
void OnMouseDown(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Mouse Button Up */
void OnMouseUp(unsigned short x, unsigned short y, unsigned short Button,
unsigned short Mod);
/** Key Release Event */
void OnKeyRelease(unsigned char Key, unsigned short Mod);
/** Special Key Press */
void OnSpecialKeyPress(unsigned char Key);
/** DisplayTooltip */
void DisplayTooltip();
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,424 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
/**
* @file Game.h
* Declares Game class, object representing current game state.
* @author The GemRB Project
*/
class Game;
#ifndef GAME_H
#define GAME_H
#include "exports.h"
#include "ie_types.h"
#include "Callback.h"
#include "Map.h"
#include "Variables.h"
#include "Scriptable/Actor.h"
#include <vector>
class Particles;
//the size of the bestiary register
#define BESTIARY_SIZE 260
//ShareXP flags
#define SX_DIVIDE 1 //divide XP among team members
#define SX_CR 2 //use challenge rating resolution
//joinparty flags
#define JP_JOIN 1 //refresh join time
#define JP_INITPOS 2 //init startpos
#define JP_SELECT 4 //select the actor after joining
//protagonist mode
#define PM_NO 0 //no death checks
#define PM_YES 1 //if protagonist dies, game over
#define PM_TEAM 2 //if team dies, game over
// Flags bits for SelectActor()
// !!! Keep these synchronized with GUIDefines.py !!!
#define SELECT_NORMAL 0x00
#define SELECT_REPLACE 0x01 // when selecting actor, deselect all others
#define SELECT_QUIET 0x02 // do not run handler when changing selection
// Flags bits for EveryoneNearPoint()
#define ENP_CANMOVE 1 // also check if the PC can move
#define ENP_ONLYSELECT 2 // check only selected PC
// GUI Control Status flags (saved in game)
#define CS_PARTY_AI 1 //enable party AI
#define CS_MEDIUM 2 //medium dialog
#define CS_LARGE 6 //large dialog, both bits set
#define CS_DIALOGSIZEMASK 6
#define CS_DIALOG 8 //dialog is running
#define CS_HIDEGUI 16 //hide all gui
#define CS_ACTION 32 //hide action pane
#define CS_PORTRAIT 64 //hide portrait pane
#define CS_MAPNOTES 128 //hide mapnotes
//Weather bits
#define WB_NORMAL 0
#define WB_RAIN 1
#define WB_SNOW 2
#define WB_FOG 3
#define WB_MASK 7
#define WB_LIGHTNING 8
#define WB_HASWEATHER 0x40
#define WB_START 0x80
//Rest flags
#define REST_NOAREA 1 //no area check
#define REST_NOSCATTER 2 //no scatter check
#define REST_NOMOVE 4 //no movement check
#define REST_NOCRITTER 8 //no hostiles check
//Song types (hardcoded)
#define SONG_DAY 0
#define SONG_NIGHT 1
#define SONG_BATTLE 3
/**
* @struct PCStruct
* Information about party member.
*/
struct PCStruct {
ieWord Selected;
ieWord PartyOrder;
ieDword OffsetToCRE;
ieDword CRESize;
ieResRef CREResRef;
ieDword Orientation;
ieResRef Area;
ieWord XPos;
ieWord YPos;
ieWord ViewXPos;
ieWord ViewYPos;
ieWord ModalState;
ieWord Happiness;
ieDword Interact[MAX_INTERACT];
ieWord QuickWeaponSlot[MAX_QUICKWEAPONSLOT];
ieWord QuickWeaponHeader[MAX_QUICKWEAPONSLOT];
ieResRef QuickSpellResRef[MAX_QSLOTS];
ieWord QuickItemSlot[MAX_QUICKITEMSLOT];
ieWord QuickItemHeader[MAX_QUICKITEMSLOT];
char Name[32];
ieDword TalkCount;
ieByte QSlots[GUIBT_COUNT];
ieByte QuickSpellClass[MAX_QSLOTS];
};
#define IE_GAM_JOURNAL 0
#define IE_GAM_QUEST_UNSOLVED 1
#define IE_GAM_QUEST_DONE 2
#define IE_GAM_JOURNAL_USER 3
/**
* @struct GAMJournalEntry
* Single entry in a journal
*/
struct GAMJournalEntry {
ieStrRef Text;
ieDword GameTime; // in game time seconds
ieByte Chapter;
ieByte unknown09;
ieByte Section;
ieByte Group; // this is a GemRB extension
};
// Saved location of party member.
struct GAMLocationEntry {
ieResRef AreaResRef;
Point Pos;
};
#define MAX_CRLEVEL 32
typedef int CRRow[MAX_CRLEVEL];
/**
* @class Game
* Object representing current game state, mostly party.
*/
class GEM_EXPORT Game : public Scriptable {
public:
Game(void);
~Game(void);
private:
std::vector< Actor*> PCs;
std::vector< Actor*> NPCs;
std::vector< Map*> Maps;
std::vector< GAMJournalEntry*> Journals;
std::vector< GAMLocationEntry*> savedpositions;
std::vector< GAMLocationEntry*> planepositions;
std::vector< char*> mastarea;
std::vector< ieDword> Attackers;
CRRow *crtable;
ieResRef restmovies[8];
ieResRef daymovies[8];
ieResRef nightmovies[8];
int MapIndex;
public:
std::vector< Actor*> selected;
int version;
Variables* kaputz;
ieByte* beasts;
ieByte* mazedata; //only in PST
ieResRef Familiars[9];
ieDword CombatCounter;
ieDword StateOverrideFlag, StateOverrideTime;
ieDword BanterBlockFlag, BanterBlockTime;
/** Index of PC selected in non-walking environment (shops, inventory...) */
int SelectedSingle;
/** 0 if the protagonist's death doesn't cause game over */
/** 1 if the protagonist's death causes game over */
/** 2 if no check is needed (pst) */
int protagonist;
/** if party size exceeds this amount, a callback will be called */
size_t partysize;
ieDword Ticks;
ieDword interval; // 1000/AI_UPDATE (a tenth of a round in ms)
ieDword GameTime;
ieDword LastScriptUpdate; // GameTime at which UpdateScripts last ran
ieDword RealTime;
ieWord WhichFormation;
ieWord Formations[5];
ieDword PartyGold;
ieWord NpcInParty;
ieWord WeatherBits;
ieDword Unknown48; //still unknown
ieDword Reputation;
ieDword ControlStatus; // used in bg2, iwd (where you can switch panes off)
ieDword Expansion; // mostly used by BG2. IWD games set it to 3 on newgame
ieResRef AnotherArea;
ieResRef CurrentArea;
ieResRef PreviousArea; //move here if the worldmap exit is illegal?
ieResRef LoadMos;
Actor *timestop_owner;
ieDword timestop_end;
Particles *weather;
int event_timer;
EventHandler event_handler; //like in Control
bool hasInfra;
private:
/** reads the challenge rating table */
void LoadCRTable();
public:
/** Returns the PC's slot count for partyID */
int FindPlayer(unsigned int partyID);
/** Returns actor by slot */
Actor* GetPC(unsigned int slot, bool onlyalive);
/** Finds an actor in party by party ID, returns Actor, if not there, returns NULL*/
Actor* FindPC(unsigned int partyID);
Actor* FindNPC(unsigned int partyID);
/** Finds a global actor by global ID */
Actor* GetGlobalActorByGlobalID(ieDword globalID);
/** Finds an actor in party, returns slot, if not there, returns -1*/
int InParty(Actor* pc) const;
/** Finds an actor in store, returns slot, if not there, returns -1*/
int InStore(Actor* pc) const;
/** Finds an actor in party by scripting name*/
Actor* FindPC(const char *deathvar);
/** Finds an actor in store by scripting name*/
Actor* FindNPC(const char *deathvar);
/** Sets the area and position of the actor to the starting position */
void InitActorPos(Actor *actor);
/** Joins party */
int JoinParty(Actor* pc, int join=JP_JOIN);
/** Return current party size */
int GetPartySize(bool onlyalive) const;
/** Returns the npcs count */
int GetNPCCount() const { return (int)NPCs.size(); }
/** Sends the hotkey trigger to all selected pcs */
void SetHotKey(unsigned long Key);
/** Select PC for non-walking environment (shops, inventory, ...) */
bool SelectPCSingle(int index);
/** Get index of selected PC for non-walking env (shops, inventory, ...) */
int GetSelectedPCSingle() const;
/** (De)selects actor. */
bool SelectActor( Actor* actor, bool select, unsigned flags );
/** Return current party level count for xp calculations */
int GetPartyLevel(bool onlyalive) const;
/** Reassigns inparty numbers, call it after party creation */
void ConsolidateParty();
/** Removes actor from party (if in there) */
int LeaveParty(Actor* pc);
/** Returns slot*/
int DelPC(unsigned int slot, bool autoFree = false);
int DelNPC(unsigned int slot, bool autoFree = false);
/** Returns map in index */
Map* GetMap(unsigned int index) const;
/** Returns a map from area name, loads it if needed
* use it for the biggest safety, change = true will change the current map */
Map* GetMap(const char *areaname, bool change);
/** Returns slot of the map if found */
int FindMap(const char *ResRef);
int AddMap(Map* map);
/** Determine if area is master area*/
bool MasterArea(const char *area);
/** Dynamically adding an area to master areas*/
void SetMasterArea(const char *area);
/** Returns slot of the map, if it was already loaded,
* don't load it again, set changepf == true,
* if you want to change the pathfinder too. */
int LoadMap(const char* ResRef, bool loadscreen);
int DelMap(unsigned int index, int forced = 0);
int AddNPC(Actor* npc);
Actor* GetNPC(unsigned int Index);
void SwapPCs(unsigned int Index1, unsigned int Index2);
bool IsDay();
void InAttack(ieDword globalID);
void OutAttack(ieDword globalID);
int AttackersOf(ieDword globalID, Map *area) const;
//journal entries
/** Deletes one or all journal entries if strref is -1 */
void DeleteJournalEntry(ieStrRef strref);
/** Delete entries of the same group */
void DeleteJournalGroup(int Group);
/** Adds a journal entry from dialog data.
* Time and chapter are calculated on the fly
* Returns false if the entry already exists */
bool AddJournalEntry(ieStrRef strref, int section, int group);
/** Adds a journal entry while loading the .gam structure */
void AddJournalEntry(GAMJournalEntry* entry);
unsigned int GetJournalCount() const;
GAMJournalEntry* FindJournalEntry(ieStrRef strref);
GAMJournalEntry* GetJournalEntry(unsigned int Index);
//saved locations
unsigned int GetSavedLocationCount() const;
void ClearSavedLocations();
GAMLocationEntry* GetSavedLocationEntry(unsigned int Index);
//plane locations
unsigned int GetPlaneLocationCount() const;
void ClearPlaneLocations();
GAMLocationEntry* GetPlaneLocationEntry(unsigned int Index);
char *GetFamiliar(unsigned int Index);
bool IsBeastKnown(unsigned int Index) const {
if (!beasts) {
return false;
}
if (Index>=BESTIARY_SIZE) {
return false;
}
return beasts[Index] != 0;
}
void SetBeastKnown(unsigned int Index) {
if (!beasts) {
return;
}
if (Index>=BESTIARY_SIZE) {
return;
}
beasts[Index] = 1;
}
ieWord GetFormation() const {
if (WhichFormation>4) {
return 0;
}
return Formations[WhichFormation];
}
size_t GetAttackerCount() const {
return Attackers.size();
}
/** converts challenge rating to xp */
int GetXPFromCR(int cr);
/** shares XP among all party members */
void ShareXP(int XP, int flags);
/** returns true if we should start the party overflow window */
bool PartyOverflow() const;
/** returns true if actor is an attacker or being attacked */
bool PCInCombat(Actor *actor) const;
/** returns true if any pc is attacker or being attacked */
bool AnyPCInCombat() const;
/** returns true if the party death condition is true */
bool EveryoneDead() const;
/** returns true if no one moves */
bool EveryoneStopped() const;
bool EveryoneNearPoint(Map *map, const Point &p, int flags) const;
/** returns true if a PC just died */
int PartyMemberDied() const;
/** a party member just died now */
void PartyMemberDied(Actor *);
/** Increments chapter variable and refreshes kill stats */
void IncrementChapter();
/** Sets party reputation */
void SetReputation(ieDword r);
/** Sets the gamescreen control status (pane states, dialog textarea size) */
void SetControlStatus(int value, int operation);
/** Sets party size (1-32000) */
void SetPartySize(int value);
/** Sets a guiscript function to happen after x AI cycles have elapsed */
void SetTimedEvent(EventHandler func, int count);
/** Sets protagonist mode to 0-none,1-protagonist,2-team */
void SetProtagonistMode(int value);
void StartRainOrSnow(bool conditional, int weather);
size_t GetLoadedMapCount() const { return Maps.size(); }
/** Adds or removes gold */
void AddGold(ieDword add);
/** Adds ticks to game time */
void AdvanceTime(ieDword add);
/** Runs the script engine on the global script and the area scripts
areas run scripts on door, infopoint, container, actors too */
void UpdateScripts();
/** runs area functionality, sets partyrested trigger */
void RestParty(int checks, int dream, int hp);
/** timestop effect initiated by actor */
void TimeStop(Actor *actor, ieDword end);
/** gets the colour which should be applied over the game area,
may return NULL */
const Color *GetGlobalTint() const;
/** returns true if party has infravision */
bool PartyHasInfravision() const { return hasInfra; }
/** draw weather */
void DrawWeather(const Region &screen, bool update);
/** updates current area music */
void ChangeSong(bool always = true, bool force = true);
/** sets expansion mode */
void SetExpansion(ieDword value);
/** Dumps information about the object */
void DebugDump();
/** Finds an actor by global ID */
Actor *GetActorByGlobalID(ieDword objectID);
/** updates the infravision info */
void Infravision();
private:
bool DetermineStartPosType(const TableMgr *strta);
ieResRef *GetDream(Map *area);
void PlayerDream();
};
#endif // ! GAME_H

View File

@@ -0,0 +1,490 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003-2005 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#include "GameData.h"
#include "ActorMgr.h"
#include "AnimationMgr.h"
#include "Cache.h"
#include "Effect.h"
#include "EffectMgr.h"
#include "Factory.h"
#include "Game.h"
#include "ImageFactory.h"
#include "ImageMgr.h"
#include "Interface.h"
#include "Item.h"
#include "ItemMgr.h"
#include "ResourceDesc.h"
#include "Spell.h"
#include "SpellMgr.h"
#include "Scriptable/Actor.h"
#include "System/FileStream.h"
#include <cstdio>
static void ReleaseItem(void *poi)
{
delete ((Item *) poi);
}
static void ReleaseSpell(void *poi)
{
delete ((Spell *) poi);
}
static void ReleaseEffect(void *poi)
{
delete ((Effect *) poi);
}
static void ReleasePalette(void *poi)
{
//we allow nulls, but we shouldn't release them
if (!poi) return;
//as long as palette has its own refcount, this should be Release
((Palette *) poi)->Release();
}
GEM_EXPORT GameData* gamedata;
GameData::GameData()
{
factory = new Factory();
}
GameData::~GameData()
{
delete factory;
}
void GameData::ClearCaches()
{
ItemCache.RemoveAll(ReleaseItem);
SpellCache.RemoveAll(ReleaseSpell);
EffectCache.RemoveAll(ReleaseEffect);
PaletteCache.RemoveAll(ReleasePalette);
}
Actor *GameData::GetCreature(const char* ResRef, unsigned int PartySlot)
{
DataStream* ds = GetResource( ResRef, IE_CRE_CLASS_ID );
if (!ds)
return 0;
PluginHolder<ActorMgr> actormgr(IE_CRE_CLASS_ID);
if (!actormgr->Open( ds, true )) {
return 0;
}
Actor* actor = actormgr->GetActor(PartySlot);
return actor;
}
int GameData::LoadCreature(const char* ResRef, unsigned int PartySlot, bool character, int VersionOverride)
{
DataStream *stream;
Actor* actor;
if (character) {
char nPath[_MAX_PATH], fName[16];
snprintf( fName, sizeof(fName), "%s.chr", ResRef);
PathJoin( nPath, core->GamePath, "characters", fName, NULL );
FileStream *fs = new FileStream();
fs -> Open( nPath, true );
stream = (DataStream *) fs;
PluginHolder<ActorMgr> actormgr(IE_CRE_CLASS_ID);
if (!actormgr->Open( stream, true )) {
return -1;
}
actor = actormgr->GetActor(PartySlot);
} else {
actor = GetCreature(ResRef, PartySlot);
}
if ( !actor ) {
return -1;
}
if (VersionOverride != -1) {
actor->version = VersionOverride;
}
//both fields are of length 9, make this sure!
memcpy(actor->Area, core->GetGame()->CurrentArea, sizeof(actor->Area) );
if (actor->BaseStats[IE_STATE_ID] & STATE_DEAD) {
actor->SetStance( IE_ANI_TWITCH );
} else {
actor->SetStance( IE_ANI_AWAKE );
}
actor->SetOrientation( 0, false );
if ( PartySlot != 0 ) {
return core->GetGame()->JoinParty( actor, JP_JOIN|JP_INITPOS );
}
else {
return core->GetGame()->AddNPC( actor );
}
}
/** Loads a 2DA Table, returns -1 on error or the Table Index on success */
int GameData::LoadTable(const ieResRef ResRef)
{
int ind = GetTableIndex( ResRef );
if (ind != -1) {
tables[ind].refcount++;
return ind;
}
//printf("(%s) Table not found... Loading from file\n", ResRef);
DataStream* str = GetResource( ResRef, IE_2DA_CLASS_ID );
if (!str) {
return -1;
}
PluginHolder<TableMgr> tm(IE_2DA_CLASS_ID);
if (!tm) {
delete str;
return -1;
}
if (!tm->Open( str, true )) {
return -1;
}
Table t;
t.refcount = 1;
strncpy( t.ResRef, ResRef, 8 );
t.tm = tm;
ind = -1;
for (size_t i = 0; i < tables.size(); i++) {
if (tables[i].refcount == 0) {
ind = ( int ) i;
break;
}
}
if (ind != -1) {
tables[ind] = t;
return ind;
}
tables.push_back( t );
return ( int ) tables.size() - 1;
}
/** Gets the index of a loaded table, returns -1 on error */
int GameData::GetTableIndex(const char* ResRef) const
{
for (size_t i = 0; i < tables.size(); i++) {
if (tables[i].refcount == 0)
continue;
if (strnicmp( tables[i].ResRef, ResRef, 8 ) == 0)
return ( int ) i;
}
return -1;
}
/** Gets a Loaded Table by its index, returns NULL on error */
Holder<TableMgr> GameData::GetTable(unsigned int index) const
{
if (index >= tables.size()) {
return NULL;
}
if (tables[index].refcount == 0) {
return NULL;
}
return tables[index].tm;
}
/** Frees a Loaded Table, returns false on error, true on success */
bool GameData::DelTable(unsigned int index)
{
if (index==0xffffffff) {
tables.clear();
return true;
}
if (index >= tables.size()) {
return false;
}
if (tables[index].refcount == 0) {
return false;
}
tables[index].refcount--;
if (tables[index].refcount == 0)
if (tables[index].tm)
tables[index].tm.release();
return true;
}
Palette *GameData::GetPalette(const ieResRef resname)
{
Palette *palette = (Palette *) PaletteCache.GetResource(resname);
if (palette) {
return palette;
}
//additional hack for allowing NULL's
if (PaletteCache.RefCount(resname)!=-1) {
return NULL;
}
ResourceHolder<ImageMgr> im(resname);
if (im == NULL) {
PaletteCache.SetAt(resname, NULL);
return NULL;
}
palette = new Palette();
im->GetPalette(256,palette->col);
palette->named=true;
PaletteCache.SetAt(resname, (void *) palette);
return palette;
}
void GameData::FreePalette(Palette *&pal, const ieResRef name)
{
int res;
if (!pal) {
return;
}
if (!name || !name[0]) {
if(pal->named) {
printf("Palette is supposed to be named, but got no name!\n");
abort();
} else {
pal->Release();
pal=NULL;
}
return;
}
if (!pal->named) {
printf("Unnamed palette, it should be %s!\n", name);
abort();
}
res=PaletteCache.DecRef((void *) pal, name, true);
if (res<0) {
printMessage( "Core", "Corrupted Palette cache encountered (reference count went below zero), ", LIGHT_RED );
printf( "Palette name is: %.8s\n", name);
abort();
}
if (!res) {
pal->Release();
}
pal = NULL;
}
Item* GameData::GetItem(const ieResRef resname)
{
Item *item = (Item *) ItemCache.GetResource(resname);
if (item) {
return item;
}
DataStream* str = GetResource( resname, IE_ITM_CLASS_ID );
PluginHolder<ItemMgr> sm(IE_ITM_CLASS_ID);
if (!sm) {
delete ( str );
return NULL;
}
if (!sm->Open( str, true )) {
return NULL;
}
item = new Item();
//this is required for storing the 'source'
strnlwrcpy(item->Name, resname, 8);
sm->GetItem( item );
if (item == NULL) {
return NULL;
}
ItemCache.SetAt(resname, (void *) item);
return item;
}
//you can supply name for faster access
void GameData::FreeItem(Item const *itm, const ieResRef name, bool free)
{
int res;
res=ItemCache.DecRef((void *) itm, name, free);
if (res<0) {
printMessage( "Core", "Corrupted Item cache encountered (reference count went below zero), ", LIGHT_RED );
printf( "Item name is: %.8s\n", name);
abort();
}
if (res) return;
if (free) delete itm;
}
Spell* GameData::GetSpell(const ieResRef resname, bool silent)
{
Spell *spell = (Spell *) SpellCache.GetResource(resname);
if (spell) {
return spell;
}
DataStream* str = GetResource( resname, IE_SPL_CLASS_ID, silent );
PluginHolder<SpellMgr> sm(IE_SPL_CLASS_ID);
if (!sm) {
delete ( str );
return NULL;
}
if (!sm->Open( str, true )) {
return NULL;
}
spell = new Spell();
//this is required for storing the 'source'
strnlwrcpy(spell->Name, resname, 8);
sm->GetSpell( spell, silent );
if (spell == NULL) {
return NULL;
}
SpellCache.SetAt(resname, (void *) spell);
return spell;
}
void GameData::FreeSpell(Spell *spl, const ieResRef name, bool free)
{
int res;
res=SpellCache.DecRef((void *) spl, name, free);
if (res<0) {
printMessage( "Core", "Corrupted Spell cache encountered (reference count went below zero), ", LIGHT_RED );
printf( "Spell name is: %.8s or %.8s\n", name, spl->Name);
abort();
}
if (res) return;
if (free) delete spl;
}
Effect* GameData::GetEffect(const ieResRef resname)
{
Effect *effect = (Effect *) EffectCache.GetResource(resname);
if (effect) {
return effect;
}
DataStream* str = GetResource( resname, IE_EFF_CLASS_ID );
PluginHolder<EffectMgr> em(IE_EFF_CLASS_ID);
if (!em) {
delete ( str );
return NULL;
}
if (!em->Open( str, true )) {
return NULL;
}
effect = em->GetEffect(new Effect() );
if (effect == NULL) {
return NULL;
}
EffectCache.SetAt(resname, (void *) effect);
return effect;
}
void GameData::FreeEffect(Effect *eff, const ieResRef name, bool free)
{
int res;
res=EffectCache.DecRef((void *) eff, name, free);
if (res<0) {
printMessage( "Core", "Corrupted Effect cache encountered (reference count went below zero), ", LIGHT_RED );
printf( "Effect name is: %.8s\n", name);
abort();
}
if (res) return;
if (free) delete eff;
}
//if the default setup doesn't fit for an animation
//create a vvc for it!
ScriptedAnimation* GameData::GetScriptedAnimation( const char *effect, bool doublehint)
{
ScriptedAnimation *ret = NULL;
if (Exists( effect, IE_VVC_CLASS_ID ) ) {
DataStream *ds = GetResource( effect, IE_VVC_CLASS_ID );
ret = new ScriptedAnimation(ds, true);
} else {
AnimationFactory *af = (AnimationFactory *)
GetFactoryResource( effect, IE_BAM_CLASS_ID, IE_NORMAL );
if (af) {
ret = new ScriptedAnimation();
ret->LoadAnimationFactory( af, doublehint?2:0);
}
}
if (ret) {
strnlwrcpy(ret->ResName, effect, 8);
}
return ret;
}
// Return single BAM frame as a sprite. Use if you want one frame only,
// otherwise it's not efficient
Sprite2D* GameData::GetBAMSprite(const ieResRef ResRef, int cycle, int frame)
{
Sprite2D *tspr;
AnimationFactory* af = ( AnimationFactory* )
GetFactoryResource( ResRef, IE_BAM_CLASS_ID, IE_NORMAL );
if (!af) return 0;
if (cycle == -1)
tspr = af->GetFrameWithoutCycle( (unsigned short) frame );
else
tspr = af->GetFrame( (unsigned short) frame, (unsigned char) cycle );
return tspr;
}
void* GameData::GetFactoryResource(const char* resname, SClass_ID type,
unsigned char mode, bool silent)
{
int fobjindex = factory->IsLoaded(resname,type);
// already cached
if ( fobjindex != -1)
return factory->GetFactoryObject( fobjindex );
// empty resref
if (!strcmp(resname, ""))
return NULL;
switch (type) {
case IE_BAM_CLASS_ID:
{
DataStream* ret = GetResource( resname, type, silent );
if (ret) {
PluginHolder<AnimationMgr> ani(IE_BAM_CLASS_ID);
if (!ani)
return NULL;
ani->Open( ret, true );
AnimationFactory* af = ani->GetAnimationFactory( resname, mode );
factory->AddFactoryObject( af );
return af;
}
return NULL;
}
case IE_BMP_CLASS_ID:
{
ResourceHolder<ImageMgr> img(resname);
if (img) {
ImageFactory* fact = img->GetImageFactory( resname );
factory->AddFactoryObject( fact );
return fact;
}
return NULL;
}
default:
printf( "\n" );
printMessage( "KEYImporter", " ", WHITE );
printf( "%s files are not supported.\n", core->TypeExt( type ) );
return NULL;
}
}

View File

@@ -0,0 +1,121 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef GAMEDATA_H
#define GAMEDATA_H
#include "SClassID.h"
#include "exports.h"
#include "ie_types.h"
#include "Cache.h"
#include "Holder.h"
#include "ResourceManager.h"
class Actor;
struct Effect;
class Factory;
class Item;
class Palette;
class ScriptedAnimation;
class Spell;
class Sprite2D;
class TableMgr;
struct Table {
Holder<TableMgr> tm;
char ResRef[8];
unsigned int refcount;
};
class GEM_EXPORT GameData : public ResourceManager
{
public:
GameData();
~GameData();
void ClearCaches();
/** Returns actor */
Actor *GetCreature(const char *ResRef, unsigned int PartySlot=0);
/** Returns a PC index, by loading a creature */
int LoadCreature(const char *ResRef, unsigned int PartySlot, bool character=false, int VersionOverride=-1);
// 2DA table functions.
// (See also the AutoTable class)
/** Loads a 2DA Table, returns -1 on error or the Table Index on success */
int LoadTable(const char * ResRef);
/** Gets the index of a loaded table, returns -1 on error */
int GetTableIndex(const char * ResRef) const;
/** Gets a Loaded Table by its index, returns NULL on error */
Holder<TableMgr> GetTable(unsigned int index) const;
/** Frees a Loaded Table, returns false on error, true on success */
bool DelTable(unsigned int index);
Palette* GetPalette(const ieResRef resname);
void FreePalette(Palette *&pal, const ieResRef name=NULL);
Item* GetItem(const ieResRef resname);
void FreeItem(Item const *itm, const ieResRef name, bool free=false);
Spell* GetSpell(const ieResRef resname, bool silent=false);
void FreeSpell(Spell *spl, const ieResRef name, bool free=false);
Effect* GetEffect(const ieResRef resname);
void FreeEffect(Effect *eff, const ieResRef name, bool free=false);
/** creates a vvc/bam animation object at point */
ScriptedAnimation* GetScriptedAnimation( const char *ResRef, bool doublehint);
/** returns a single sprite (not cached) from a BAM resource */
Sprite2D* GetBAMSprite(const ieResRef ResRef, int cycle, int frame);
/** returns factory resource, currently works only with animations */
void* GetFactoryResource(const char* resname, SClass_ID type,
unsigned char mode = IE_NORMAL, bool silent=false);
private:
Cache ItemCache;
Cache SpellCache;
Cache EffectCache;
Cache PaletteCache;
Factory* factory;
std::vector<Table> tables;
};
extern GEM_EXPORT GameData * gamedata;
template <class T>
class ResourceHolder : public Holder<T>
{
public:
ResourceHolder()
{
}
ResourceHolder(const char* resname)
: Holder<T>(static_cast<T*>(gamedata->GetResource(resname,&T::ID)))
{
}
ResourceHolder(const char* resname, const ResourceManager& manager, bool silent = false)
: Holder<T>(static_cast<T*>(manager.GetResource(resname,&T::ID,silent)))
{
}
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
/* GemRB - Infinity Engine Emulator
* Copyright (C) 2003 The GemRB Project
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*
*/
#ifndef GSUTILS_H
#define GSUTILS_H
#include "GameScript/GameScript.h"
#include "defsounds.h"
#include "exports.h"
#include "strrefs.h"
#include "Interface.h"
//indebug flags
#define ID_REFERENCE 1
#define ID_CUTSCENE 2
#define ID_VARIABLES 4
#define ID_ACTIONS 8
#define ID_TRIGGERS 16
extern Holder<SymbolMgr> triggersTable;
extern Holder<SymbolMgr> actionsTable;
extern Holder<SymbolMgr> overrideActionsTable;
extern Holder<SymbolMgr> objectsTable;
extern TriggerFunction triggers[MAX_TRIGGERS];
extern ActionFunction actions[MAX_ACTIONS];
extern short actionflags[MAX_ACTIONS];
extern short triggerflags[MAX_TRIGGERS];
extern ObjectFunction objects[MAX_OBJECTS];
extern IDSFunction idtargets[MAX_OBJECT_FIELDS];
extern Cache SrcCache; //cache for string resources (pst)
extern Cache BcsCache; //cache for scripts
extern int ObjectIDSCount;
extern int MaxObjectNesting;
extern bool HasAdditionalRect;
extern bool HasTriggerPoint;
extern ieResRef *ObjectIDSTableNames;
extern int ObjectFieldsCount;
extern int ExtraParametersCount;
extern int InDebug;
extern int *SkillStats;
extern int SkillCount;
extern Gem_Polygon **polygons;
#define MIC_INVALID -2
#define MIC_FULL -1
#define MIC_NOITEM 0
#define MIC_GOTITEM 1
GEM_EXPORT int GetReaction(Actor *target, Scriptable *Sender);
int GetHappiness(Scriptable *Sender, int reputation);
int GetHPPercent(Scriptable *Sender);
bool StoreHasItemCore(const ieResRef storename, const ieResRef itemname);
bool HasItemCore(Inventory *inventory, const ieResRef itemname, ieDword flags);
void ClickCore(Scriptable *Sender, Point point, int type, int speed);
void TransformItemCore(Actor *actor, Action *parameters, bool onlyone);
void CreateVisualEffectCore(Actor *target, const char *effect, int iterations);
void CreateVisualEffectCore(Scriptable *Sender, const Point &position, const char *effect, int iterations);
void GetPositionFromScriptable(Scriptable* scr, Point &position, bool trap);
void BeginDialog(Scriptable* Sender, Action* parameters, int flags);
void ChangeAnimationCore(Actor *src, const char *resref, bool effect);
void PolymorphCopyCore(Actor *src, Actor *tar, bool base);
void CreateCreatureCore(Scriptable* Sender, Action* parameters, int flags);
int MoveItemCore(Scriptable *Sender, Scriptable *target, const char *resref, int flags, int setflag);
void MoveToObjectCore(Scriptable *Sender, Action *parameters, ieDword flags, bool untilsee);
void CreateItemCore(CREItem *item, const char *resref, int a, int b, int c);
void AttackCore(Scriptable *Sender, Scriptable *target, int flags);
void InitScriptTables();
void HandleBitMod(ieDword &value1, ieDword value2, int opcode);
bool ResolveSpellName(ieResRef spellres, Action *parameter);
GEM_EXPORT void ResolveSpellName(ieResRef spellres, ieDword number);
GEM_EXPORT ieDword ResolveSpellNumber(const ieResRef spellres);
bool ResolveItemName(ieResRef itemres, Actor *act, ieDword Slot);
void EscapeAreaCore(Scriptable *Sender, const Point &p, const char *area, const Point &enter, int flags, int wait);
void GoNear(Scriptable *Sender, const Point &p);
void MoveNearerTo(Scriptable *Sender, Scriptable *target, int distance);
int MoveNearerTo(Scriptable *Sender, const Point &p, int distance, int no_release);
void GoNearAndRetry(Scriptable *Sender, Scriptable *target, bool destination, int distance);
void GoNearAndRetry(Scriptable *Sender, const Point &p, int distance);
#define NO_OPERATION -1
#define LESS_OR_EQUALS 0
//iwd2 diffmode with gemrb enhancements
#define EQUALS 1
#define LESS_THAN 2
#define GREATER_THAN 3
#define GREATER_OR_EQUALS 4
#define NOT_EQUALS 5
#define BINARY_LESS_OR_EQUALS 6 //(left has only bits in right)
#define BINARY_MORE_OR_EQUALS 7 //(left has equal or more bits than right)
#define BINARY_INTERSECT 8 //(left and right has at least one common bit)
#define BINARY_NOT_INTERSECT 9 //(no common bits)
#define BINARY_MORE 10 //left has more bits than right
#define BINARY_LESS 11 //left has less bits than right
GEM_EXPORT int GetGroup(Actor *actor);
void FreeSrc(SrcVector *poi, const ieResRef key);
SrcVector *LoadSrc(const ieResRef resname);
Action *ParamCopy(Action *parameters);
Action *ParamCopyNoOverride(Action *parameters);
void SetVariable(Scriptable* Sender, const char* VarName, ieDword value);
Point GetEntryPoint(const char *areaname, const char *entryname);
//these are used from other plugins
GEM_EXPORT int CanSee(Scriptable* Sender, Scriptable* target, bool range, int nodead);
GEM_EXPORT int SeeCore(Scriptable* Sender, Trigger* parameters, int justlos);
GEM_EXPORT int DiffCore(ieDword a, ieDword b, int diffmode);
GEM_EXPORT void DisplayStringCore(Scriptable* Sender, int Strref, int flags);
GEM_EXPORT void SetVariable(Scriptable* Sender, const char* VarName, const char* Context, ieDword value);
GEM_EXPORT void MoveBetweenAreasCore(Actor* actor, const char *area, const Point &position, int face, bool adjust);
GEM_EXPORT ieDword CheckVariable(Scriptable* Sender, const char* VarName, bool *valid = NULL);
GEM_EXPORT ieDword CheckVariable(Scriptable* Sender, const char* VarName, const char* Context, bool *valid = NULL);
Action* GenerateActionCore(const char *src, const char *str, unsigned short actionID);
Trigger *GenerateTriggerCore(const char *src, const char *str, int trIndex, int negate);
unsigned int GetSpellDistance(const ieResRef spellres, Scriptable *Sender);
unsigned int GetItemDistance(const ieResRef itemres, int header);
void SetupWishCore(Scriptable *Sender, int column, int picks);
Gem_Polygon *GetPolygon2DA(ieDword index);
inline int Bones(ieDword value)
{
return core->Roll((value&0xf000)>>12, (value&0xff0)>>8, value&15);
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More