Added full source code

This commit is contained in:
Emmanuel BENOîT 2016-01-10 11:01:49 +01:00
commit 33f8586698
1377 changed files with 123808 additions and 0 deletions

11
AUTHORS Normal file
View file

@ -0,0 +1,11 @@
Legacy Worlds Beta 5 authors
-----------------------------
Legacy Worlds Beta 4:
Chris Wicks <el_christoph@deepclone.co.uk>
Legacy Worlds Beta 5:
Emmanuel Benoît <tseeker@deepclone.co.uk>
Julie Bourbeillon <ju@deepclone.co.uk>
Douglas Rodgers <sycop@deepclone.co.uk>
Dave Timmermans <lord_omega@legacyworlds.com>

32
COPYING Normal file
View file

@ -0,0 +1,32 @@
Licensing information
----------------------
The IRC bot code is based on PHP-IRC (http://www.phpbots.org/) with some
changes for LW integration. It is distributed under the GNU GPL license.
The main LW code (admin and scripts directories), as well as the CSS and JS
code (with the exception of the jquery library) in site/static, the planet
generator and the SQL database structure and associated functions are
distributed under the GNU GPL license. Same goes for whatever is in the
misc/ directory.
The outdated copy of the JQuery (http://www.jquery.org) library found in the
site/static/main/js/ directory is distributed under the MIT license.
Icons used in the site's appearance have been taken and modified from various
sources. Their respective licenses are mostly unknown.
The game data (including the manual and all files in the sql subdirectory
which contain actual values - sql/beta5/data/ most notably) remain the
exclusive property of Deep Clone Development. This data may be copied,
distributed or used as long as:
1) the distribution is free,
2) the distribution is complete and unmodified (it should match the
contents of the official SVN repository),
3) no profits are made from using this data.
Feel free to replace this data with something else entirely to get rid of
these licensing terms.
A copy of the GPLv2 is included in COPYING.GPL ; the MIT license may be found
in COPYING.MIT.

339
COPYING.GPL Normal file
View file

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
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 Lesser 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.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General
Public License instead of this License.

17
COPYING.MIT Normal file
View file

@ -0,0 +1,17 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

96
README Normal file
View file

@ -0,0 +1,96 @@
Legacy Worlds Beta 5 source code
---------------------------------
1. Introduction
This file contains information regarding the source code release for Legacy
Worlds Beta 5 - how the source code is organised and how it may be used.
For licensing information, please read the COPYING file. For the list of
contributors, please read the AUTHORS file. For stuff that could be done
considering one had a lot of time to waste, please read the TODO file.
The official SVN repository for the LWB5 code can be found at:
* https://lwb5.svn.deepclone.co.uk (IPv6 users)
* https://secure.nocternity.net/deepclone.co.uk/svn/lwb5/ (IPv4 users)
2. Organisation of the source code
... admin/ Administration interface scripts
... ircbot/ IRC bot
... ircbot/modules/lw/ LWB5-specific code for the IRC bot
... manual/ Source code (as XML) of the LWB5 manual
... misc/ Various optional elements
... planetgen/ Planet generator source code
... scripts/ Scripts that implement most of the game
... scripts/game/ Back-end scripts
... scripts/lib/ Core library
... scripts/site/ Web front-end
... site/ Root directory of the public part of the site
... site/static/ Images, CSS and JavaScript elements
... sql/ Database creation scripts
3. Requirements
In order to run Legacy Worlds, you will need the following software:
* Apache + PHP 5.2
* (optional) a PHP opcode cache
* PostgreSQL 8.3 or higher
* the POVRay raytracer (used for planet generation)
4. Installing and running LWB5
These instructions may be erroneous on some points, as I didn't bother to try
and re-install it myself.
* Set the database users' passwords in sql/00-init.sql
* (optional) Modify sql/30-beta5.sql to select the games that will be created
on initialisation.
* Create the database by running sql/INSTALL.sql
* Create an administrative user in the main.account table
* Create some system users for the various parts of the LWB5 backend:
** user "lwbot"; when su'd to, this user should start the IRC bot,
** user "lwticks"; when su'd to, this user should start scripts/ticks.php
** user "lwproxy"; when su'd to, this user should start scripts/proxycheck.php
* In addition to the above users, the planet picture generator should run with
privileges allowing it to write to subdirectories of site/static/beta5/pics/pl/
* Modify scripts/config.inc and scripts/legacyworlds.xml
** Also modify ircbot/bot.conf to have the bot connect to a server
* Set up the web server:
** the main site should use the site/ directory,
** the administration interface should use the admin/ directory; it should be
protected using HTTP authentication.
Once the installation is complete, it is possible to start (most of) the game
by running scripts/control.pl with the --start command line argument. However,
the planet generator script has to be started manually.
5. The misc/ subdirectory
The misc/ subdirectory contains two things:
* the source code of the MacOS dashboard widget,
* the "forums branch" patch.
The forums branch patch has been created by doing a very quick and dirty merge
of an old development branch that was mostly abandoned; it contains some
improvements on the core library - notably a class to prepare database queries
and some other improvements in the DB query API. Of course, it also includes an
incomplete rewrite of the in-game forums.
Because I had to merge the branches to generate the patch, and because I didn't
bother with testing it, the patch is likely to break a lot of things. However
it may be a good starting point for improving the LWB5 code. See the TODO file
for more information.

47
TODO Normal file
View file

@ -0,0 +1,47 @@
This file lists stuff that could be done to improve the current LWB5 source
code. It's mostly stuff that I had the intention of doing at some point but
didn't have the time to work on or finish. Of course, this is just a list of
ideas - feel free to ignore it altogether.
Back-end clean up:
* A lot of the game and site functions use older APIs that are deprecated.
** Calls to gameAction()
** Calls to logText()
** There's more, but I can't remember...
* Some of the improvements to the core library found in the forums branch
patch should be included - most importantly the SQL query stuff. Of course
this also implies modifying a lot of the code that actually uses SQL queries.
* While some of it has been removed, there is still a lot of SQL in the
various web handlers; it should be moved to the library.
* Internal messages are sent by inserting into the database directly in many
of the game's functions; this should be changed as there is an API for that.
Front-end clean up:
* When LWB5 was first written, I hadn't planned on using that much JavaScript.
In addition, JS libraries were not as common then as they are now. Therefore
most of the JS code is a terrible, ugly heap of spaghetti code and copy pasta.
It should be rewritten.
Improvements and missing features:
* Finishing the forums rewrite (started in the forums branch patch).
* Rewrite fleet handling - the database structure is brain dead, normalisation
is clearly required, and it'd reduce the various checks performed wherever
fleets are accessed.
* Fleet trajectory is buggy, it contains a relatively easily exploitable bug.
Needs redesign.
* Probes never made it into the final version.
* The IRC bot's source code should be upgraded to the latest version of
PHP-IRC.

20
admin/as_log.inc Normal file
View file

@ -0,0 +1,20 @@
<?php
/** This function writes an entry to the system log. */
function __logAdmin($txt, $level = null) {
static $logInit = false;
if (!$logInit) {
global $__logPrefix;
define_syslog_variables();
openlog("lwControl", LOG_PID, LOG_USER);
$logInit = true;
}
if (is_null($level)) {
$level = LOG_INFO;
}
syslog($level, "*** ADMIN {$_SERVER['PHP_AUTH_USER']} $txt");
}
?>

24
admin/as_manager.inc Normal file
View file

@ -0,0 +1,24 @@
<?php
function __isManagerRunning() {
global $aConfig;
$fName = $aConfig['ctrlPath'] . "/tickManager.pid";
if (!file_exists($fName)) {
return false;
}
$file = fopen($fName, "r");
$line = rtrim(fgets($file));
fclose($file);
list($pid, $time) = explode(" ", $line);
if (time() - $time > 22) {
return false;
}
return $pid;
}
?>

80
admin/bot.php Normal file
View file

@ -0,0 +1,80 @@
<?php
set_magic_quotes_runtime(false);
include('config.inc');
include('../scripts/config.inc');
include('as_manager.inc');
include('as_log.inc');
function redirect() {
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > IRC bot</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > IRC bot</h1>
<h2>Operation in progress...</h2>
<p>
A system operation is in progress. Please wait, the page will update in a few seconds.
</p>
<script language="JavaScript">
window.setTimeout('window.location="bot.php"', 1000);
</script>
</body>
</html>
<?php
exit(0);
}
function sendCommand($cmd) {
global $aConfig;
$fName = $aConfig['ctrlFifo'];
if (!file_exists($fName)) {
return false;
}
$fifo = fopen($fName, "w");
fwrite($fifo, "$cmd\n");
fclose($fifo);
redirect();
}
if ($_GET['c'] == 'kb') {
__logAdmin("is stopping the IRC bot");
sendCommand("BOTOFF");
} elseif ($_GET['c'] == 'sb') {
__logAdmin("is starting the IRC bot");
sendCommand("BOTON");
}
$running = file_exists($config['cs_path'] . "/ircbot.pid");
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > IRC bot</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > IRC bot</h1>
<?php
if ($running) {
?>
<p>
IRC bot is (probably) running. <a href="?c=kb">Kill bot</a>
</p>
<?php
} else {
?>
<p>
IRC bot is not running. <a href="?c=sb">Start bot</a>
</p>
<?php
}
?>
</body>
</html>

56
admin/cg_done.php Normal file
View file

@ -0,0 +1,56 @@
<?php
set_magic_quotes_runtime(false);
session_start();
?>
<html>
<head>
<title>Legacy Worlds Beta 5 > Administration > Create game</title>
</head>
<body style="background-color: #dfdfff">
<table style="margin: 50px 0; padding: 0px;width:100%" cellspacing="0" cellpadding="0">
<tr>
<td width="33%">&nbsp;</td>
<td width="34%"><table style="border: 4px solid blue; background-color:white; padding: 5px;width: 100%">
<tr>
<td colspan="3" style="padding: 2px 0px;font-size:150%;color:blue;text-align:center">LegacyWorlds Beta 5</td>
</tr>
<tr>
<td colspan="3" style="padding: 2px 0px;font-size:150%;color:red;text-align:center"><?=$_SESSION['lw_new_game']['name']?></td>
</tr>
<tr><td colspan="3" style="height:5px;font-size:1pt">&nbsp;</td></tr>
<tr><td colspan="3" style="padding: 2px 0px;color:#3f3fff;text-align:center">Game creation complete!</td></tr>
<tr>
<td style="width:10%">&nbsp;</td>
<td><table style="border: 1px solid black; padding: 1px; margin: 0px; width: 100%; height: 16px"><tr>
<td style='font-size:1pt;background-color:#00007f'>&nbsp;</td>
</tr></table></td>
<td style="width:10%">&nbsp;</td>
</tr>
<tr><td colspan="3" style="padding: 2px 0px;color:#ff3f3f;text-align:center">100% complete</td></tr>
<tr><td colspan="3">&nbsp;</td></tr>
</table></td>
<td width="33%">&nbsp;</td>
<tr><td colspan="3">&nbsp;</td></tr>
<tr>
<td>&nbsp;</td>
<td style="text-align:center">
The new game has been created; however, it is not visible from the interface yet, you will have to
<a href="game_status.php">make it visible</a><br/>
<br/>
The server is still in <a href="maintenance.php">maintenance mode</a>, you will have to disable it manually.<br/>
<br/>
<a href="index.html">Main admin page</a>
</td>
<td>&nbsp;</td>
</tr>
</table>
</body>
</html>
<?php
$_SESSION['lw_new_game']['started'] = false;
?>

45
admin/cg_operation.inc Normal file
View file

@ -0,0 +1,45 @@
<html>
<head>
<title>Legacy Worlds Beta 5 > Administration > Create game</title>
</head>
<body style="background-color: #ffdfdf">
<table style="margin: 50px 0; padding: 0px;width:100%" cellspacing="0" cellpadding="0">
<tr>
<td width="33%">&nbsp;</td>
<td width="34%"><table style="border: 4px solid red; background-color:white; padding: 5px;width: 100%">
<tr>
<td colspan="3" style="padding: 2px 0px;font-size:150%;color:red;text-align:center">LegacyWorlds Beta 5</td>
</tr>
<tr>
<td colspan="3" style="padding: 2px 0px;font-size:150%;color:red;text-align:center">Game creation in progress</td>
</tr>
<tr><td colspan="3" style="height:5px;font-size:1pt">&nbsp;</td></tr>
<tr><td colspan="3" style="padding: 2px 0px;color:#ff3f3f;text-align:center"><?=$op['text']?></td></tr>
<tr>
<td style="width:10%">&nbsp;</td>
<td><table style="border: 1px solid black; padding: 1px; margin: 0px; width: 100%; height: 16px"><tr>
<?php
if ($op['pc'] == 0) {
print "<td style='font-size:1pt'>&nbsp;</td>";
} elseif ($op['pc'] == 100) {
print "<td style='font-size:1pt;background-color:#7f0000'>&nbsp;</td>";
} else {
print "<td style='font-size:1pt;background-color:#7f0000;width:" . $op['pc'] . "%'>&nbsp;</td>"
. "<td style='font-size:1pt'>&nbsp;</td>";
}
?>
</tr></table></td>
<td style="width:10%">&nbsp;</td>
</tr>
<tr><td colspan="3" style="padding: 2px 0px;color:#ff3f3f;text-align:center"><?=$op['pc']?>% complete</td></tr>
<tr><td colspan="3">&nbsp;</td></tr>
</table></td>
<td width="33%">&nbsp;</td>
</table>
<script language="JavaScript">
window.setTimeout('window.location="<?=$op['to']?>"', <?=$op['delay']*1000?>);
</script>
</body>
</html>

24
admin/cg_step0.php Normal file
View file

@ -0,0 +1,24 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || $_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
$_SESSION['lw_new_game']['started'] = true;
include("as_log.inc");
__logAdmin("is creating game {$_SESSION['lw_new_game']['name']}");
$op = array(
"pc" => 0,
"text" => "Initialising ...",
"delay" => 1,
"to" => "cg_step1.php"
);
include('cg_operation.inc');
?>

30
admin/cg_step1.php Normal file
View file

@ -0,0 +1,30 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
$_SESSION['lw_new_game']['started'] = true;
include("../scripts/config.inc");
if (is_null($config['maintenance'])) {
$text = "Enabling maintenance mode";
$next = "cg_step2.php";
} else {
$text = "Checking existing IDs";
$next = "cg_step4.php";
}
$op = array(
"pc" => 5,
"text" => $text,
"delay" => 1,
"to" => $next
);
include('cg_operation.inc');
?>

28
admin/cg_step10.php Normal file
View file

@ -0,0 +1,28 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
/* Execute an universe tick manually */
$ns = $_SESSION['lw_new_game']['found_id'];
$__runFromAdmin = true;
$__adminParams = array($ns, 'universe');
include("../scripts/ticks.php");
$op = array(
"pc" => 85,
"text" => "Adding silent admins",
"delay" => 1,
"to" => "cg_step11.php"
);
include('cg_operation.inc');
?>

60
admin/cg_step11.php Normal file
View file

@ -0,0 +1,60 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
include('as_manager.inc');
/* Insert "silent admins" into the new game's player table */
$cnx = __dbConnect();
if (!$cnx) {
$argh = "Could not connect to the database";
} else {
$ns = $_SESSION['lw_new_game']['found_id'];
$error = false;
foreach ($_SESSION['lw_new_game']['silent'] as $aId) {
if (!pg_query($cnx, "INSERT INTO \"{$ns}\".player (userid, first_planet, hidden) VALUES ($aId, 1, TRUE)")) {
$error = true;
break;
}
}
if ($error) {
$argh = "Failed to insert silent admin data";
} else {
$argh = null;
}
pg_close($cnx);
}
if (!is_null($argh)) {
include('cg_argh.inc');
exit(0);
}
if (__isManagerRunning()) {
$op = array(
"pc" => 90,
"text" => "Restarting ticks",
"delay" => 1,
"to" => "cg_step12.php"
);
} else {
$op = array(
"pc" => 100,
"text" => "Cleaning up",
"delay" => 1,
"to" => "cg_done.php"
);
}
include('cg_operation.inc');
?>

35
admin/cg_step12.php Normal file
View file

@ -0,0 +1,35 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
include("as_manager.inc");
include("../scripts/config.inc");
if (!__isManagerRunning() || !file_exists($config['cachedir'] . "/ticks_stopped")) {
$op = array(
"pc" => 100,
"text" => "Cleaning up",
"delay" => 1,
"to" => "cg_done.php"
);
} else {
touch($config['cachedir'] . "/start_ticks");
$op = array(
"pc" => 95,
"text" => "Waiting for ticks to restart",
"delay" => 1,
"to" => "cg_step13.php"
);
}
include('cg_operation.inc');
?>

33
admin/cg_step13.php Normal file
View file

@ -0,0 +1,33 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
include("as_manager.inc");
include("../scripts/config.inc");
if (__isManagerRunning() && file_exists($config['cachedir'] . "/ticks_stopped")) {
$op = array(
"pc" => 95,
"text" => "Waiting for ticks to restart",
"delay" => 1,
"to" => "cg_step13.php"
);
} else {
$op = array(
"pc" => 100,
"text" => "Cleaning up",
"delay" => 1,
"to" => "cg_done.php"
);
}
include('cg_operation.inc');
?>

31
admin/cg_step2.php Normal file
View file

@ -0,0 +1,31 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
$maintenance = array(
"until" => time() + 15 * 60,
"reason" => "Creating game " . $_SESSION['lw_new_game']['name']
);
include("../scripts/config.inc");
$f = fopen($config['cachedir'] . '/maintenance.ser', "w");
fwrite($f, serialize($maintenance));
fclose($f);
$_SESSION['lw_new_game']['menable'] = time();
$op = array(
"pc" => 10,
"text" => "Waiting ...",
"delay" => 1,
"to" => "cg_step3.php"
);
include('cg_operation.inc');
?>

29
admin/cg_step3.php Normal file
View file

@ -0,0 +1,29 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
$t = time() - $_SESSION['lw_new_game']['menable'];
if ($t < 20) {
$text = "Waiting ...";
$next = "cg_step3.php";
} else {
$text = "Checking existing IDs";
$next = "cg_step4.php";
}
$op = array(
"pc" => 10 + floor($t/2),
"text" => $text,
"delay" => 1,
"to" => $next
);
include('cg_operation.inc');
?>

41
admin/cg_step4.php Normal file
View file

@ -0,0 +1,41 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
$cnx = __dbConnect();
$minId = 1;
$gameType = "b5" . ($_SESSION['lw_new_game']['game_type'] == 'r' ? 'r' : 'm');
do {
$minId ++;
$q = pg_query($cnx, "SELECT nspname FROM pg_namespace WHERE nspname='{$gameType}{$minId}'");
} while ($q && pg_num_rows($q) == 1);
pg_close($cnx);
if (!$q) {
$argh = "Error while accessing the database";
include('cg_argh.inc');
exit(1);
}
$_SESSION['lw_new_game']['found_id'] = $gameType . $minId;
$op = array(
"pc" => 25,
"text" => "Inserting data for ID $gameType$minId",
"delay" => 1,
"to" => "cg_step5.php"
);
include('cg_operation.inc');
?>

205
admin/cg_step5.php Normal file
View file

@ -0,0 +1,205 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
include("as_manager.inc");
class dbParser {
static private $instructions = array();
static private $aConnection;
static private $uConnection;
static private $cConnection = null;
static public function parse($contents) {
$all = explode("\n", $contents);
$state = 0;
foreach ($all as $line) {
// print "PARSING LINE: $line<br/>\n";
if ($state == 0) {
// Remove comments
$line = preg_replace('/\s*--.*$/', '', $line);
if ($line == '') {
continue;
}
// \c ?
if (preg_match('/^\\\\c\s+[^\s]+\s([^\s]+)\s*$/', $line, $match)) {
if ($match[1] == "legacyworlds_admin") {
//echo "<b>CONNECT AS ADMIN</b><br/>";
array_push(self::$instructions, array("CADM"));
} else {
//echo "<b>CONNECT AS USER</b><br/>";
array_push(self::$instructions, array("CUSR"));
}
}
// \i ?
elseif (preg_match('/^\\\\i\s+([^\s]+)\s*$/', $line, $match)) {
self::parseFile($match[1]);
}
// COPY table FROM STDIN ?
elseif (preg_match('/^COPY\s+([^\s]+)\s+FROM\s+STDIN\s*;\s*$/i', $line, $match)) {
//echo "<b>COPY DATA</b> INTO {$match[1]}: ";
array_push(self::$instructions, array("COPY", $match[1]));
$state = 1;
$copyArray = array();
}
// Other commands
else {
$rv = self::parseCommand($line);
if ($rv[0]) {
//echo "<b>EXECUTE QUERY</b> " . htmlentities($rv[1]) . "<br/>\n";
array_push(self::$instructions, array("QUERY", $rv[1]));
} else {
$buffer = $rv[1];
$state = 2;
}
}
} elseif ($state == 1) {
if ($line == "\\.") {
//echo count($copyArray) . " LINE(S) OF DATA<br/>\n";
self::$instructions[count(self::$instructions) - 1][2] = $copyArray;
$state = 0;
} else {
array_push($copyArray, "$line\n");
}
} elseif ($state == 2) {
$rv = self::parseCommand($line, $buffer);
if ($rv[0]) {
//echo "<b>EXECUTE QUERY</b> " . htmlentities($rv[1]) . "<br/>\n";
array_push(self::$instructions, array("QUERY", $rv[1]));
$state = 0;
} else {
$buffer = $rv[1];
}
}
}
}
private static function parseFile($fileName) {
$file = fopen("../sql/$fileName", "r");
$text = "";
while (($line = fgets($file)) !== FALSE) {
$text .= $line;
}
fclose($file);
self::parse($text);
}
private static function parseCommand($line, $buffer = "") {
$state = 0;
for ($i = 0; $i < strlen($line); $i ++) {
if ($state == 0) {
if ($line{$i} == ';') {
return array(true, $buffer);
}
$buffer .= $line{$i};
if ($line{$i} == "'") {
$state = 1;
}
} else {
$buffer .= $line{$i};
if ($line{$i} == "'") {
$state = 0;
}
}
}
return array(false, "$buffer ");
}
public static function connect() {
self::$uConnection = __dbConnect(false);
if (!self::$uConnection) {
$argh = "Error while accessing the database in user mode";
include('cg_argh.inc');
exit(1);
}
self::$aConnection = __dbConnect(true);
if (!self::$aConnection) {
$argh = "Error while accessing the database in admin mode";
include('cg_argh.inc');
exit(1);
}
}
public static function execute($schema) {
foreach (self::$instructions as $instr) {
$iType = array_shift($instr);
if ($iType == 'CADM') {
self::setConnection(self::$aConnection);
} elseif ($iType == 'CUSR') {
self::setConnection(self::$aConnection);
} elseif ($iType == 'QUERY') {
if (!pg_query(self::$cConnection, $instr[0])) {
$argh = "Could not execute query {$instr[0]}";
pg_query(self::$aConnection, "DROP SCHEMA \"$schema\" CASCADE");
include('cg_argh.inc');
exit(1);
}
} elseif ($iType == 'COPY') {
if (!pg_copy_from(self::$cConnection, $instr[0], $instr[1])) {
$argh = "Copy failed for table {$instr[0]}";
pg_query(self::$aConnection, "DROP SCHEMA \"$schema\" CASCADE");
include('cg_argh.inc');
exit(1);
}
}
}
}
public static function setConnection($cnx) {
self::$cConnection = $cnx;
}
}
$gtData = array(
"r" => array('round', 'r'),
"m" => array('match', 'm'),
"c" => array('ctf', 'm'),
);
$gData = $gtData[$_SESSION['lw_new_game']['game_type']];
$substStr = "b5" . $gData[1] . "X";
// Load base match script
$fileName = "../sql/beta5/beta5-" . $gData[0] . ".sql";
$baseFile = fopen($fileName, "r");
$base = "";
while (($line = fgets($baseFile)) !== FALSE) {
$base .= preg_replace("/$substStr/", $_SESSION['lw_new_game']['found_id'], $line);
}
fclose($baseFile);
dbParser::parse($base);
dbParser::connect();
dbParser::execute($_SESSION['lw_new_game']['found_id']);
if (__isManagerRunning()) {
$op = array(
"pc" => 50,
"text" => "Stopping all ticks",
"delay" => 1,
"to" => "cg_step6.php"
);
} else {
$op = array(
"pc" => 60,
"text" => "Generating configuration",
"delay" => 1,
"to" => "cg_step8.php"
);
}
include('cg_operation.inc');
?>

35
admin/cg_step6.php Normal file
View file

@ -0,0 +1,35 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
include("as_manager.inc");
include("../scripts/config.inc");
if (!__isManagerRunning() || file_exists($config['cachedir'] . "/ticks_stopped")) {
$op = array(
"pc" => 60,
"text" => "Generating configuration",
"delay" => 1,
"to" => "cg_step8.php"
);
} else {
touch($config['cachedir'] . "/stop_ticks");
$op = array(
"pc" => 55,
"text" => "Waiting for ticks to stop",
"delay" => 1,
"to" => "cg_step7.php"
);
}
include('cg_operation.inc');
?>

33
admin/cg_step7.php Normal file
View file

@ -0,0 +1,33 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
include("as_manager.inc");
include("../scripts/config.inc");
if (__isManagerRunning() && !file_exists($config['cachedir'] . "/ticks_stopped")) {
$op = array(
"pc" => 55,
"text" => "Waiting for ticks to stop",
"delay" => 1,
"to" => "cg_step7.php"
);
} else {
$op = array(
"pc" => 60,
"text" => "Generating configuration",
"delay" => 1,
"to" => "cg_step8.php"
);
}
include('cg_operation.inc');
?>

109
admin/cg_step8.php Normal file
View file

@ -0,0 +1,109 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
require_once("config.inc");
function makeCTFParams() {
$cnx = __dbConnect();
if (!$cnx) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$query = pg_query("SELECT * FROM main.ctf_map_def ORDER BY name");
if (!$query) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
$ctfMaps = array();
while ($r = pg_fetch_assoc($query)) {
$ctfMaps[$r['id']] = $r;
$query2 = pg_query("SELECT COUNT(*) FROM main.ctf_map_layout WHERE map={$r['id']} AND spawn_here");
if (!$query2) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
list($ctfMaps[$r['id']]['players']) = pg_fetch_array($query2);
pg_free_result($query2);
}
pg_free_result($query);
pg_close($cnx);
$map = $ctfMaps[$_SESSION['lw_new_game']['ctfmap']];
$cParams = $_SESSION['lw_new_game']['ctfparams'];
$params = array(
'usemap' => $map['id'],
'maxplayers' => $map['players'],
'norealloc' => 1,
'partialtechs' => 0,
'lockalliances' => $map['alliances'],
'alliancecap' => 0,
'victory' => 2,
'novacation' => 1
);
foreach ($cParams as $p => $v) {
$params[$p] = $v;
}
return $params;
}
$ns = $_SESSION['lw_new_game']['found_id'];
$newConfig = "\t\t<!-- Game added automatically by the game creation tool -->\n"
. "\t\t<Game id=\"$ns\" version=\"beta5\" namespace=\"$ns\" text=\""
. $_SESSION['lw_new_game']['name'] . "\" public=\"0\" canjoin=\"0\">\n"
. "\t\t\t<!-- Game parameters -->\n";
if ($_SESSION['lw_new_game']['game_type'] == 'c') {
$_SESSION['lw_new_game']['params'] = makeCTFParams();
}
foreach ($_SESSION['lw_new_game']['params'] as $p => $v) {
$newConfig .= "\t\t\t<Param name=\"$p\" value=\"$v\" />\n";
}
$newConfig .= "\n"
. "\t\t\t<!-- Description -->\n"
. "\t\t\t<Description lang=\"en\">\n"
. "\t\t\t\t" . $_SESSION['lw_new_game']['descr'] . "\n"
. "\t\t\t</Description>\n\n"
. "\t\t\t<!-- Ticks -->\n\n";
require_once("cg_ticks_schedule.inc");
$ticks = __computeTicks($_SESSION['lw_new_game']['ft_y'],
$_SESSION['lw_new_game']['ft_m'], $_SESSION['lw_new_game']['ft_d'],
$_SESSION['lw_new_game']['speed'], $_SESSION['lw_new_game']['shift_ticks']);
foreach ($ticks as $tid => $data) {
$time = $data[1];
$time = ($time - ($secs = $time % 60)) / 60;
$time = ($time - ($mins = $time % 60)) / 60;
$newConfig .= "\t\t\t<!-- \"$tid\" tick: first tick " . gmstrftime("%H:%M:%S on %Y-%m-%d", $data[0])
. ", interval {$time}h, {$mins}min, {$secs}s -->\n"
. "\t\t\t<Tick script=\"$tid\" first=\"{$data[0]}\" interval=\"{$data[1]}\" />\n";
}
$newConfig .= "\t\t</Game>\n";
$file = fopen($aConfig['ctrlPath'] . "/config.$ns.xml", "w");
fwrite($file, $newConfig);
fclose($file);
$op = array(
"pc" => 70,
"text" => "Merging configuration",
"delay" => 1,
"to" => "cg_step9.php"
);
include('cg_operation.inc');
?>

27
admin/cg_step9.php Normal file
View file

@ -0,0 +1,27 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || !$_SESSION['lw_new_game']['do_it_now'] || !$_SESSION['lw_new_game']['started']) {
echo "Sorry, can't do that.";
exit(0);
}
include("config.inc");
$ns = $_SESSION['lw_new_game']['found_id'];
$file = fopen($aConfig['ctrlFifo'], "w");
fwrite($file, "MERGE $ns\n");
fclose($file);
$op = array(
"pc" => 75,
"text" => "Initialising universe",
"delay" => 1,
"to" => "cg_step10.php"
);
include('cg_operation.inc');
?>

View file

@ -0,0 +1,86 @@
<?php
function __computeTicks($year, $month, $day, $speed, $shift) {
$tickDefs = array(
// Modifiable ticks
"hour" => array(
'now' => false,
'change' => true,
'interval' => 60 * 60,
'desync' => 60 * 60
),
"battle" => array(
'now' => false,
'change' => true,
'interval' => 4 * 60 * 60,
'desync' => 55 * 60,
),
"cash" => array(
'now' => false,
'change' => true,
'interval' => 12 * 60 * 60,
'desync' => (12 * 60 + 5) * 60
),
"day" => array(
'now' => false,
'change' => true,
'interval' => 24 * 60 * 60,
'desync' => (24 * 60 + 10) * 60
),
"move" => array(
'now' => false,
'change' => true,
'interval' => 60,
'desync' => 60 * 60 + 27
),
// Immediate ticks
'universe' => array(
'now' => true,
'change' => false,
'interval' => 60 * 5,
'desync' => 57
),
'punishment' => array(
'now' => true,
'change' => false,
'interval' => 39,
'desync' => 28
),
// Immutable ticks
'quit' => array(
'now' => false,
'change' => false,
'interval' => 50,
'desync' => 7
),
'sales' => array(
'now' => false,
'change' => false,
'interval' => 21,
'desync' => 13
),
);
$startTime = gmmktime(7, 0, 0, $month, $day, $year);
$now = time();
$results = array();
foreach ($tickDefs as $tid => $def) {
$interval = $def['change'] ? ceil($def['interval']/$speed) : $def['interval'];
if ($def['now']) {
$first = $startTime + $def['desync'];
while ($first > $now) {
$first -= $def['interval'];
}
} else {
$first = $startTime + ($def['change'] ? ceil($def['desync']/$speed) : $def['desync']);
}
$results[$tid] = array($first + $shift * 60, $interval);
}
return $results;
}
?>

12
admin/cg_user_dsp_1.inc Normal file
View file

@ -0,0 +1,12 @@
<h2>Step 1 / 6 : game type</h2>
<p>Please select the type of game you want to create from the form below.</p>
<form method="GET" action="?">
<p>
<input type="radio" value="m" name="gt" id="gtm" <?=$_SESSION['lw_new_game']['game_type'] == 'm' ? "checked='checked'" : ""?>/> <label for="gtm"><b>Match</b></label><br/>
<input type="radio" value="r" name="gt" id="gtr" <?=$_SESSION['lw_new_game']['game_type'] == 'r' ? "checked='checked'" : ""?>/> <label for="gtr"><b>Round</b></label><br/>
<input type="radio" value="c" name="gt" id="gtc" <?=$_SESSION['lw_new_game']['game_type'] == 'c' ? "checked='checked'" : ""?>/> <label for="gtc"><b>Kings of the Hill</b></label>
</p>
<p>
<input type="submit" value="Proceed >>" />
</p>
</form>

30
admin/cg_user_dsp_2.inc Normal file
View file

@ -0,0 +1,30 @@
<h2>Step 2 / 6 : game description</h2>
<p>Please type in the name and description of the new game.</p>
<form method="POST" action="?">
<p>
<b>Game name:</b> <input type="text" name="gn" size="31" maxlength="30" value="<?=htmlentities($_SESSION['lw_new_game']['name'], ENT_QUOTES)?>" /><?php
switch ($err1) :
case 1: print " <span style='color:red;font-weigth:bold'>Too short!</span>\n"; break;
case 2: print " <span style='color:red;font-weigth:bold'>Invalid characters!</span>\n"; break;
endswitch;
?><br/>
This is the name that will appear in menus and lists.
</p>
<p>
<b>Description:</b> <input type="text" name="gd" size="50" maxlength="200" value="<?=htmlentities($_SESSION['lw_new_game']['descr'], ENT_QUOTES)?>" /><?php
switch ($err2) :
case 1: print " <span style='color:red;font-weigth:bold'>Too short!</span>\n"; break;
case 2: print " <span style='color:red;font-weigth:bold'>Invalid characters!</span>\n"; break;
endswitch;
?><br/>
This is the description that will appear next to the name on people's account pages.
</p>
<p>
<input type="submit" name="back" value="<< Back" />
<input type="submit" name="go" value="Proceed >>" />
</p>
</form>

111
admin/cg_user_dsp_3.inc Normal file
View file

@ -0,0 +1,111 @@
<?php
if ($_SESSION['lw_new_game']['game_type'] == 'c') {
include('cg_user_dsp_3ctf.inc');
return;
}
if (!is_array($errors)) {
$errors = array();
}
$params = array(
array(
'id' => 'maxplayers',
'title' => 'Maximum amount of players',
'notes' => '0 for unlimited, -1 for "1/system"'
),
array(
'id' => 'minsystems',
'title' => 'Minimum amount of free systems',
'notes' => 'Also influences the initial universe'
),
array(
'id' => 'maxsystems',
'title' => 'Maximum amount of systems',
'notes' => '0 for unlimited'
),
array(
'id' => 'partialtechs',
'title' => 'Partial tech graph',
'notes' => '0 for complete tech graph, 1 for partial'
),
array(
'id' => 'initialcash',
'title' => 'Initial amount of money',
'notes' => '0 for default (20,000)'
),
array(
'id' => 'zonesize',
'title' => 'Universe generator: zone size',
'notes' => '0 = default (5x5); 1 for 3x3, 2 for 5x5, etc...'
),
array(
'id' => 'nebulaprob',
'title' => 'Probability of a nebula',
'notes' => '0 .. 20, -1 = default'
),
array(
'id' => 'norealloc',
'title' => 'Prevent planet reallocation',
'notes' => '0 to allow players to get new planets'
),
array(
'id' => 'novacation',
'title' => 'Disable vacation mode',
'notes' => '0 = normal / 1 = disable'
),
array(
'id' => 'victory',
'title' => 'Victory conditions',
'notes' => '0 = none / 1 = alliance holds 75% of the planets for 1 week'
),
array(
'id' => 'lockalliances',
'title' => 'Use predefined alliances',
'notes' => 'Disabled if smaller than 2; maximum value = 8'
),
array(
'id' => 'alliancecap',
'title' => 'Alliance capping %',
'notes' => '% of players; 0 to disable (no effect on predefined alliances)'
),
array(
'id' => 'prot_after',
'title' => 'Protection after',
'notes' => 'Day ticks. Only applies to rounds.'
),
array(
'id' => 'prot_duration',
'title' => 'Protection duration',
'notes' => 'Day ticks. Only applies to rounds.'
)
);
?>
<h2>Step 3 / 6 : parameters</h2>
<p>Define the new game's parameters here.</p>
<form method="POST" action="?">
<table border="1">
<?php
foreach ($params as $p) {
print "<tr><th style='align:right";
if (in_array($p['id'], $errors)) {
print ";color:red";
}
print "'>" . htmlentities($p['title']) . " : </th><td>"
. "<input type='text' name='p_{$p['id']}' size='10' maxlength='10' value='"
. $_SESSION['lw_new_game']['params'][$p['id']] . "' /></td><td><i>"
. htmlentities($p['notes']) . "</i></td></tr>";
}
?>
<tr><td colspan="3"><input type="submit" name="gtdef" value="Game type defaults" style="width: 100%" /></td></tr>
</table>
<p>
<input type="submit" name="back" value="<< Back" />
<input type="submit" name="go" value="Proceed >>" />
</p>
</form>

137
admin/cg_user_dsp_3ctf.inc Normal file
View file

@ -0,0 +1,137 @@
<?php
if (!is_array($ctfMaps)) {
require_once("config.inc");
$cnx = __dbConnect();
if (!$cnx) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$query = pg_query("SELECT * FROM main.ctf_map_def ORDER BY name");
if (!$query) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
$ctfMaps = array();
while ($r = pg_fetch_assoc($query)) {
$ctfMaps[$r['id']] = $r;
$query2 = pg_query("SELECT COUNT(*) FROM main.ctf_map_layout WHERE map={$r['id']} AND spawn_here");
if (!$query2) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
list($ctfMaps[$r['id']]['players']) = pg_fetch_array($query2);
pg_free_result($query2);
}
pg_free_result($query);
pg_close($cnx);
}
if (!is_array($errors)) {
$errors = array();
}
$params = array(
array(
'id' => 'initialcash',
'title' => 'Initial amount of money',
'notes' => '0 for default (20,000)'
),
array(
'id' => 'v2time',
'title' => 'Time for victory',
'notes' => 'Number of hours an alliance must hold the targets to win'
),
array(
'id' => 'v2grace',
'title' => 'Grace period',
'notes' => 'Number of hours an alliance has to retake the targets. Set to 0 to disable.'
),
array(
'id' => 'v2points',
'title' => 'Points per victory',
'notes' => 'Number of points an alliance gains at each victory. Must be > 0 and < 100'
)
);
?>
<h2>Step 3 / 6 : parameters</h2>
<script language="JavaScript"><!--
var games = [];
<?php
foreach ($ctfMaps as $id => $map) {
print "games[$id] = {\n\tdescription: '" . addslashes($map['description'])
. "',\n\tsize: '{$map['width']}x{$map['height']}',\n\t"
. "alliances: {$map['alliances']},\n\tplayers: {$map['players']}\n};\n";
}
?>
function showDetails(selector) {
var sel = selector.options[selector.selectedIndex].value;
var str;
if (sel == '') {
str = "&nbsp;";
} else {
str = "<h4>Map information</h4><p><b>Players:</b> " + games[sel].players
+ " - <b>Teams:</b> " + games[sel].alliances
+ " - <b>Size:</b> " + games[sel].size;
if (games[sel].description != '') {
str += '<br/><b>Description:</b> ' + games[sel].description;
}
str += '</p>';
}
document.getElementById('mapinfo').innerHTML = str;
}
// --></script>
<p>Define the new game's parameters here.</p>
<form method="POST" action="?">
<div id="mapinfo" style="float:right;width: 50%;padding: 0px 10px">&nbsp;</div>
<table border="1" width="45%">
<tr>
<th style='align:right<?php if (in_array('map', $errors)) { print ";color:red"; } ?>'>
Map to use:
</th>
<td colspan="2">
<select name="map" onChange="showDetails(this)">
<option value="">-- Select --</option>
<?php
foreach ($ctfMaps as $id => $map) {
print " <option value='$id'";
if ($_SESSION['lw_new_game']['ctfmap'] == $id) {
print " selected='selected'";
}
print ">" . htmlentities($map['name']) . "</option>\n";
}
?>
</select>
</td>
</tr>
<?php
foreach ($params as $p) {
print "<tr><th style='align:right";
if (in_array($p['id'], $errors)) {
print ";color:red";
}
print "'>" . htmlentities($p['title']) . " : </th><td>"
. "<input type='text' name='p_{$p['id']}' size='10' maxlength='10' value='"
. $_SESSION['lw_new_game']['ctfparams'][$p['id']] . "' /></td><td><i>"
. htmlentities($p['notes']) . "</i></td></tr>";
}
?>
</table>
<p>
<input type="submit" name="back" value="<< Back" />
<input type="submit" name="go" value="Proceed >>" />
</p>
</form>

54
admin/cg_user_dsp_4.inc Normal file
View file

@ -0,0 +1,54 @@
<?php
$speeds = array(
"" => "-- select speed --",
"1" => "Normal",
"2" => "2x",
"3" => "3x",
"4" => "4x"
);
?>
<h2>Step 4 / 6 : ticks configuration</h2>
<p>Please indicate the speed of the game and the day the game will begin on.</p>
<form method="GET" action="?">
<p>
Game speed:
<select name="gs">
<?php
foreach ($speeds as $val => $disp) {
print "<option value='$val'";
if ($_SESSION['lw_new_game']['speed'] == $val) {
print " selected='selected'";
}
print ">$disp</option>\n";
}
?>
</select> (4x games = bad for the server!)
</p>
<p>
First tick on (YYYY-MM-DD):
<input type="text" name="ft_y" size="4" maxlength="4" value="<?=htmlentities($_SESSION['lw_new_game']['ft_y'], ENT_QUOTES)?>" /> -
<input type="text" name="ft_m" size="2" maxlength="2" value="<?=htmlentities($_SESSION['lw_new_game']['ft_m'], ENT_QUOTES)?>" /> -
<input type="text" name="ft_d" size="2" maxlength="2" value="<?=htmlentities($_SESSION['lw_new_game']['ft_d'], ENT_QUOTES)?>" /><br/>
<?php
if ($ftError) {
print "<span style='color:red'>Invalid date! Must be in the future.</span>";
} else {
print "Ticks will start on the specified day, at the first hour tick after 7:00 AM";
}
?>
</p>
<p>
Shift ticks by <input type="text" name="st" size="3" maxlength="3" value="<?=(int) $_SESSION['lw_new_game']['shift_ticks']?>" /> minutes
</p>
<p>
<input type="submit" name="back" value="<< Back" />
<input type="submit" name="go" value="Proceed >>" />
</p>
</form>

43
admin/cg_user_dsp_5.inc Normal file
View file

@ -0,0 +1,43 @@
<?php
if (!is_array($allAdmins)) {
require_once("config.inc");
$cnx = __dbConnect();
if (!$cnx) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$query = pg_query("SELECT id,name FROM main.account WHERE admin AND NOT name LIKE 'AI>%' ORDER BY name");
if (!$query) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$allAdmins = array();
while ($r = pg_fetch_row($query)) {
$allAdmins[$r[0]] = $r[1];
}
pg_close($cnx);
}
?>
<h2>Step 5 / 6 : silent admins</h2>
<p>"Silent admins" are admins that will join the game for administrative purposes but won't play it. Please beware with this function, as a silent admin will no longer be able to join the game as a player.</p>
<form method="POST" action="?">
<p>
<?php
foreach ($allAdmins as $id => $name) {
?>
<input type="checkbox" name="sa[]" value="<?=$id?>" id="sa<?=$id?>" <?=(is_array($_SESSION['lw_new_game']['silent']) && in_array($id, $_SESSION['lw_new_game']['silent'])) ? "checked='checked'" : ""?> /> <label for="sa<?=$id?>"><?=htmlentities($name)?></label><br/>
<?
}
?>
</p>
<p>
<input type="submit" name="back" value="<< Back" />
<input type="submit" name="go" value="Proceed >>" />
</p>
</form>

213
admin/cg_user_dsp_6.inc Normal file
View file

@ -0,0 +1,213 @@
<?php
require_once("cg_ticks_schedule.inc");
require_once("config.inc");
require_once("as_manager.inc");
require_once("../scripts/config.inc");
$cnx = __dbConnect();
if (!$cnx) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$query = pg_query("SELECT id,name FROM main.account WHERE admin AND NOT name LIKE 'AI>%' ORDER BY name");
if (!$query) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$allAdmins = array();
while ($r = pg_fetch_row($query)) {
$allAdmins[$r[0]] = $r[1];
}
$query = pg_query("SELECT * FROM main.ctf_map_def ORDER BY name");
if (!$query) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
$ctfMaps = array();
while ($r = pg_fetch_assoc($query)) {
$ctfMaps[$r['id']] = $r;
$query2 = pg_query("SELECT COUNT(*) FROM main.ctf_map_layout WHERE map={$r['id']} AND spawn_here");
if (!$query2) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
list($ctfMaps[$r['id']]['players']) = pg_fetch_array($query2);
pg_free_result($query2);
}
pg_free_result($query);
pg_close($cnx);
function __start($title) {
?>
<h3><?=htmlentities($title)?></h3>
<table border="1" width="80%" style="margin: 5px 30px">
<?
}
function __line($title, $contents) {
?>
<tr>
<th align="right" width="50%"><?=htmlentities($title)?>: </th>
<td><?=htmlentities($contents)?></td>
</tr>
<?
}
function __end() {
echo "</table>\n";
}
$params = array(
array(
'id' => 'maxplayers',
'title' => 'Maximum amount of players',
),
array(
'id' => 'minsystems',
'title' => 'Minimum amount of free systems',
),
array(
'id' => 'maxsystems',
'title' => 'Maximum amount of systems',
),
array(
'id' => 'partialtechs',
'title' => 'Partial tech graph',
),
array(
'id' => 'initialcash',
'title' => 'Initial amount of money',
),
array(
'id' => 'zonesize',
'title' => 'Universe generator: zone size',
),
array(
'id' => 'nebulaprob',
'title' => 'Probability of a nebula',
),
array(
'id' => 'norealloc',
'title' => 'Prevent planet reallocation',
),
array(
'id' => 'novacation',
'title' => 'Disable vacation mode',
),
array(
'id' => 'victory',
'title' => 'Victory conditions',
),
array(
'id' => 'lockalliances',
'title' => 'Use predefined alliances',
),
array(
'id' => 'alliancecap',
'title' => 'Alliance capping %',
)
);
$ctfParams = array(
array(
'id' => 'initialcash',
'title' => 'Initial amount of money',
),
array(
'id' => 'v2time',
'title' => 'Time for victory',
),
array(
'id' => 'v2grace',
'title' => 'Grace period',
),
array(
'id' => 'v2points',
'title' => 'Points per victory',
)
);
?>
<h2>Step 6 / 6 : recap</h2>
<p>Please check the information below <b>CAREFULLY</b>.</p>
<?php
$gTypes = array(
'm' => 'Match',
'r' => 'Round',
'c' => 'Kings of the Hill'
);
__start("Main information");
__line("Game type", $gTypes[$_SESSION['lw_new_game']['game_type']]);
__line("Game name", $_SESSION['lw_new_game']['name']);
__line("Description", $_SESSION['lw_new_game']['descr']);
__end();
__start("Parameters");
if ($_SESSION['lw_new_game']['game_type'] == 'c') {
$map = $ctfMaps[$_SESSION['lw_new_game']['ctfmap']];
__line("Map name", $map['name']);
if ($map['description'] != '') {
__line("Description", $map['description']);
}
__line("Players", $map['players']);
__line("Teams", $map['alliances']);
__line("Size", $map['width'] . "x" . $map['height']);
foreach ($ctfParams as $p) {
__line($p['title'], $_SESSION['lw_new_game']['ctfparams'][$p['id']]);
}
} else {
foreach ($params as $p) {
__line($p['title'], $_SESSION['lw_new_game']['params'][$p['id']]);
}
}
__end();
$speeds = array("Normal", "2x", "3x", "4x");
__start("Ticks configuration");
__line("Speed", $speeds[$_SESSION['lw_new_game']['speed'] - 1]);
__line("First tick (YYYY-MM-DD)", $_SESSION['lw_new_game']['ft_y'] . "-" .
$_SESSION['lw_new_game']['ft_m'] . "-" . $_SESSION['lw_new_game']['ft_d']);
__end();
$ticks = __computeTicks($_SESSION['lw_new_game']['ft_y'],
$_SESSION['lw_new_game']['ft_m'], $_SESSION['lw_new_game']['ft_d'],
$_SESSION['lw_new_game']['speed'], $_SESSION['lw_new_game']['shift_ticks']);
__start("Ticks schedule");
foreach ($ticks as $tid => $data) {
__line("\"$tid\" / first tick", gmstrftime("%H:%M:%S on %Y-%m-%d", $data[0]));
$time = $data[1];
$time = ($time - ($secs = $time % 60)) / 60;
$time = ($time - ($mins = $time % 60)) / 60;
__line("\"$tid\" / interval", "{$time}h, {$mins}min, {$secs}s");
__line("\"$tid\" / numeric values", $data[0] . " / " . $data[1]);
}
__end();
__start("Silent admins");
foreach ($allAdmins as $id => $name) {
__line($name, in_array($id, $_SESSION['lw_new_game']['silent']) ? "YES" : "no");
}
__end();
__start("Server information");
__line("Maintenance mode", is_null($config['maintenance']) ? "No - will enable automatically (DANGEROUS)" : "yes");
__line("Ticks manager", __isManagerRunning() ? "running" : "stopped");
__end();
?>
<form method="GET" action="?">
<p>
<input type="submit" name="back" value="<< Back" />
<input type="submit" name="go" value="Proceed >>" />
</p>
</form>

23
admin/cg_user_dsp_7.inc Normal file
View file

@ -0,0 +1,23 @@
<?php
$_SESSION['lw_new_game']['do_it_now'] = true;
?>
<br/><br/><br/>
<hr/>
<br/><br/><br/>
<h1 style="text-align:center;font-size:32pt">LAST CHANCE</h1>
<br/><br/>
<form method="GET" action="?">
<p style="text-align:center;font-size:150%">
This is your last chance to get back.<br/>
You are about to create a new LegacyWorlds game, which is no small operation.</br>
<br/>
Please, be reasonable and stop now, while you can. Any client crash during the operation could cause the server to be unusable.<br/>
<br/>
<input type="submit" name="back" value="Yes, please, take me back, I want the server to live on!" /><br/>
<br/>
Ok, you're still reading. That's bad news.<br/>
Scroll down to access the next step.
</p>
</form>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
<p style="text-align:center"><a href="cg_step0.php">Alea jacta est.</a></p>

8
admin/cg_user_hdl_1.inc Normal file
View file

@ -0,0 +1,8 @@
<?php
if (in_array($_GET['gt'], array('m','r', 'c'))) {
$_SESSION['lw_new_game']['game_type'] = $_GET['gt'];
$_SESSION['lw_new_game']['step'] = 2;
}
?>

27
admin/cg_user_hdl_2.inc Normal file
View file

@ -0,0 +1,27 @@
<?php
function __checktext($text, $minLen, $okChars) {
if (strlen($text) < $minLen) {
return 1;
}
if (preg_match('/[^' . $okChars . ']/', $text)) {
return 2;
}
return 0;
}
if ($_POST['go']) {
$n = $_SESSION['lw_new_game']['name'] = stripslashes($_POST['gn']);
$d = $_SESSION['lw_new_game']['descr'] = stripslashes($_POST['gd']);
$err1 = __checktext($n, 5, 'A-Za-z0-9\.\-\ \,\#');
$err2 = __checktext($d, 15, 'A-Za-z0-9\\.\\- ,#!\'%');
if (!($err1 || $err2)) {
$_SESSION['lw_new_game']['step'] = 3;
}
} elseif ($_POST['back']) {
$_SESSION['lw_new_game']['name'] = stripslashes($_POST['gn']);
$_SESSION['lw_new_game']['descr'] = stripslashes($_POST['gd']);
$_SESSION['lw_new_game']['step'] = 1;
}
?>

73
admin/cg_user_hdl_3.inc Normal file
View file

@ -0,0 +1,73 @@
<?php
if ($_SESSION['lw_new_game']['game_type'] == 'c') {
include('cg_user_hdl_3ctf.inc');
return;
}
$pDefaults = array(
'm' => array(
'maxplayers' => -1,
'minsystems' => 30,
'maxsystems' => 30,
'norealloc' => 1,
'partialtechs' => 0,
'initialcash' => 40000,
'zonesize' => 1,
'nebulaprob' => 15,
'lockalliances' => 4,
'alliancecap' => 0,
'victory' => 1,
'novacation' => 1,
'prot_after' => 0,
'prot_duration' => 0,
),
'r' => array(
'maxplayers' => 0,
'minsystems' => 40,
'maxsystems' => 0,
'norealloc' => 0,
'partialtechs' => 1,
'initialcash' => 0,
'zonesize' => 1,
'nebulaprob' => -1,
'lockalliances' => 0,
'alliancecap' => 20,
'victory' => 0,
'novacation' => 0,
'prot_after' => 20,
'prot_duration' => 20,
)
);
$pList = array_keys($pDefaults['m']);
if (!is_array($_SESSION['lw_new_game']['params'])) {
$_SESSION['lw_new_game']['params'] = array();
}
if ($_POST['gtdef']) {
$_SESSION['lw_new_game']['params'] = $pDefaults[$_SESSION['lw_new_game']['game_type']];
} elseif ($_POST['go']) {
$errors = array();
foreach ($pList as $pid) {
$val = $_POST["p_$pid"];
if (strcmp($val, (string)(int)$val)) {
array_push($errors, $pid);
}
$_SESSION['lw_new_game']['params'][$pid] = $val;
}
if (! count($errors)) {
$_SESSION['lw_new_game']['step'] = 4;
}
} elseif ($_POST['back']) {
foreach ($pList as $pid) {
$_SESSION['lw_new_game']['params'][$pid] = $_POST["p_$pid"];
}
$_SESSION['lw_new_game']['step'] = 2;
}
?>

View file

@ -0,0 +1,66 @@
<?php
require_once("config.inc");
$cnx = __dbConnect();
if (!$cnx) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$query = pg_query("SELECT * FROM main.ctf_map_def ORDER BY name");
if (!$query) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
$ctfMaps = array();
while ($r = pg_fetch_assoc($query)) {
$ctfMaps[$r['id']] = $r;
$query2 = pg_query("SELECT COUNT(*) FROM main.ctf_map_layout WHERE map={$r['id']} AND spawn_here");
if (!$query2) {
print "<b>DATABASE ERROR</b>";
exit(1);
}
list($ctfMaps[$r['id']]['players']) = pg_fetch_array($query2);
pg_free_result($query2);
}
pg_free_result($query);
pg_close($cnx);
$pList = array('initialcash', 'v2time','v2grace','v2points');
if (!is_array($_SESSION['lw_new_game']['ctfparams'])) {
$_SESSION['lw_new_game']['ctfparams'] = array();
}
if ($_POST['go']) {
$errors = array();
$mapID = (int) $_POST['map'];
if (!array_key_exists($mapID, $ctfMaps)) {
$errors[0] = 'map';
} else {
$_SESSION['lw_new_game']['ctfmap'] = $mapID;
}
foreach ($pList as $pid) {
$val = $_POST["p_$pid"];
if (strcmp($val, (string)(int)$val)) {
array_push($errors, $pid);
}
$_SESSION['lw_new_game']['ctfparams'][$pid] = $val;
}
if (! count($errors)) {
$_SESSION['lw_new_game']['step'] = 4;
}
} elseif ($_POST['back']) {
foreach ($pList as $pid) {
$_SESSION['lw_new_game']['ctfparams'][$pid] = $_POST["p_$pid"];
}
$_SESSION['lw_new_game']['ctfmap'] = $_POST['map'];
$_SESSION['lw_new_game']['step'] = 2;
}
?>

30
admin/cg_user_hdl_4.inc Normal file
View file

@ -0,0 +1,30 @@
<?php
if ($_GET['back'] || $_GET['go']) {
$_SESSION['lw_new_game']['ft_y'] = $_GET['ft_y'];
$_SESSION['lw_new_game']['ft_m'] = $_GET['ft_m'];
$_SESSION['lw_new_game']['ft_d'] = $_GET['ft_d'];
$_SESSION['lw_new_game']['shift_ticks'] = (int) $_GET['st'];
$_SESSION['lw_new_game']['speed'] = $_GET['gs'];
}
if ($_GET['back']) {
$_SESSION['lw_new_game']['step'] = 3;
} elseif ($_GET['go']) {
$speedOk = in_array($_GET['gs'], array("1","2","3","4"));
$mkts = mktime(7, 0, 0, (int)$_GET['ft_m'], (int)$_GET['ft_d'], (int)$_GET['ft_y']);
if ($mkts === FALSE || $mkts <= time()) {
$ftError = 1;
}
if ($_SESSION['lw_new_game']['shift_ticks'] < 0) {
$_SESSION['lw_new_game']['shift_ticks'] = 0;
}
if ($speedOk && !$ftError) {
$_SESSION['lw_new_game']['step'] = 5;
}
}
?>

44
admin/cg_user_hdl_5.inc Normal file
View file

@ -0,0 +1,44 @@
<?php
require_once("config.inc");
$cnx = __dbConnect();
if (!$cnx) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$query = pg_query("SELECT id,name FROM main.account WHERE admin AND NOT name LIKE 'AI>%' ORDER BY name");
if (!$query) {
print "<b>DATABASE CONNECTION ERROR</b>";
exit(1);
}
$allAdmins = array();
while ($r = pg_fetch_row($query)) {
$allAdmins[$r[0]] = $r[1];
}
pg_close($cnx);
$sa = $_POST['sa'];
if (!is_array($sa)) {
$sa = array();
}
if ($_POST['go'] || $_POST['back']) {
$_SESSION['lw_new_game']['silent'] = array();
foreach ($sa as $saId) {
if (array_key_exists($saId, $allAdmins)) {
array_push($_SESSION['lw_new_game']['silent'], $saId);
}
}
} elseif (!is_array($_SESSION['lw_new_game']['silent'])) {
$_SESSION['lw_new_game']['silent'] = array();
}
if ( $_POST['back']) {
$_SESSION['lw_new_game']['step'] = 4;
} elseif ($_POST['go']) {
$_SESSION['lw_new_game']['step'] = 6;
}
?>

10
admin/cg_user_hdl_6.inc Normal file
View file

@ -0,0 +1,10 @@
<?php
$_SESSION['lw_new_game']['do_it_now'] = false;
if ($_GET['back']) {
$_SESSION['lw_new_game']['step'] = 5;
} elseif ($_GET['go']) {
$_SESSION['lw_new_game']['step'] = 7;
}
?>

8
admin/cg_user_hdl_7.inc Normal file
View file

@ -0,0 +1,8 @@
<?php
if ($_GET['back']) {
$_SESSION['lw_new_game']['step'] = 6;
$_SESSION['lw_new_game']['do_it_now'] = false;
}
?>

9
admin/cg_user_hdr.inc Normal file
View file

@ -0,0 +1,9 @@
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Create game</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Create game</h1>
<p>
This administrative tools allows you to create new LegacyWorlds games.
</p>

39
admin/config.inc Normal file
View file

@ -0,0 +1,39 @@
<?php
$aConfig = array(
"user" => 'legacyworlds',
"password" => 'password for the standard database user',
"adminUser" => 'legacyworlds_admin',
"adminPassword" => 'password for the administrative database user',
"ctrlFifo" =>'/tmp/.lwFifo',
"ctrlPath" =>'/tmp/.lwControl'
);
function __dbConnect($admin = false) {
global $aConfig;
$u = $aConfig[$admin ? 'adminUser' : 'user'];
$p = $aConfig[$admin ? 'adminPassword' : 'password'];
$cString = "dbname='legacyworlds' host='127.0.0.1' sslmode='prefer' user='$u' password='$p'";
return pg_connect($cString);
}
function __sendControl($command) {
global $aConfig;
$fName = $aConfig['ctrlFifo'];
if (!file_exists($fName)) {
return false;
}
$fifo = @fopen($fName, "w");
if ($fifo === false) {
return false;
}
fwrite($fifo, "$command\n");
fclose($fifo);
return true;
}
?>

19
admin/create.php Normal file
View file

@ -0,0 +1,19 @@
<?php
set_magic_quotes_runtime(false);
session_start();
if (!is_array($_SESSION['lw_new_game']) || $_GET['reset']) {
$_SESSION['lw_new_game'] = array(
"step" => 1
);
}
include("cg_user_hdl_" . $_SESSION['lw_new_game']['step'] . ".inc");
include("cg_user_hdr.inc");
include("cg_user_dsp_" . $_SESSION['lw_new_game']['step'] . ".inc");
?>
</body>
</html>

425
admin/ctf_map.inc Normal file
View file

@ -0,0 +1,425 @@
<?php
class ctf_map_sys {
private $x;
private $y;
private $type;
private $alloc;
private $spawn;
public function __construct($x, $y, $type = null, $alloc = null, $spawn = null) {
$this->x = $x;
$this->y = $y;
$this->type = $type;
$this->alloc = $alloc;
if (is_bool($spawn)) {
$this->spawn = $spawn;
} elseif (is_string($spawn)) {
$this->spawn = ($spawn == 't');
} else {
$this->spawn = null;
}
}
public function setType($type) {
if (is_null($type) || !in_array((string) $type, array('S', '1', '2', '3', '4'))) {
throw new Exception('Invalid type');
}
$this->type = $type;
if ($this->type != 'S') {
$this->alloc = $this->spawn = null;
} elseif (is_null($this->alloc)) {
$this->alloc = 0;
$this->spawn = null;
}
}
public function setAllocation($alloc) {
if ($alloc < 0 || $this->type != 'S') {
throw new Exception('Invalid allocation type');
}
$this->alloc = $alloc;
if ($this->alloc != 0 && is_null($this->spawn)) {
$this->spawn = false;
} elseif ($this->alloc = 0) {
$this->spawn = null;
}
}
public function setSpawn($spawn) {
if (is_null($this->alloc) || $this->alloc == 0 || !is_bool($spawn)) {
throw new Exception("Invalid spawning value");
}
$this->spawn = $spawn;
}
public function getType() {
return $this->type;
}
public function getAllocation() {
return $this->alloc;
}
public function getSpawn() {
return $this->spawn;
}
public function getX() {
return $this->x;
}
public function getY() {
return $this->y;
}
public function store($db, $map) {
$q = pg_query_params($db, "INSERT INTO main.ctf_map_layout(map,sys_x,sys_y,sys_type,alloc_for,spawn_here)"
. " VALUES ($map,$1,$2,$3,$4,$5)", array(
$this->x, $this->y, $this->type, $this->alloc,
($this->type == 'S' && $this->alloc > 0) ? ($this->spawn ? 't' : 'f') : null
));
if (!$q) {
throw new Exception("Failed to store system at {$this->x};{$this->y}");
}
}
}
class ctf_map {
private $dbID;
private $name;
private $description;
private $width;
private $height;
private $alliances;
private $map;
public static function allMaps() {
$db = __dbConnect();
if (! $db) {
throw new Exception('Unable to connect to the database');
}
$result = pg_query($db, "SELECT id FROM main.ctf_map_def ORDER BY id");
if (!$result) {
throw new Exception("Database error");
}
$IDs = array();
while ($row = pg_fetch_array($result)) {
array_push($IDs, $row[0]);
}
pg_free_result($result);
pg_close($db);
$maps = array();
foreach ($IDs as $id) {
$maps[$id] = new ctf_map($id);
}
return $maps;
}
public function __construct($dbID = null) {
if (is_null($dbID)) {
$this->dbID = $this->name = $this->description = null;
$this->alliances = 2;
$this->width = $this->height = 3;
} else {
$db = __dbConnect();
if (! $db) {
throw new Exception("Unable to connect to the database");
}
$result = pg_query($db, "SELECT * FROM main.ctf_map_def WHERE id = $dbID");
if (!($result && pg_num_rows($result) == 1)) {
pg_close($db);
throw new Exception("Definition '$dbID' not found");
}
$row = pg_fetch_assoc($result);
pg_free_result($result);
pg_close($db);
$this->dbID = $dbID;
$this->name = $row['name'];
$this->description = $row['description'];
$this->width = $row['width'];
$this->height = $row['height'];
$this->alliances = $row['alliances'];
}
$this->map = null;
}
public function getID() {
return $this->dbID;
}
public function getName() {
return $this->name;
}
public function getDescription() {
return $this->description;
}
public function getWidth() {
return $this->width;
}
public function getHeight() {
return $this->height;
}
public function getAlliances() {
return $this->alliances;
}
public function setName($value) {
$this->name = $value;
}
public function setDescription($value) {
$this->description = ($value == '') ? null : $value;
}
public function setAlliances($value) {
$this->alliances = $value;
}
public function setWidth($value) {
if (is_null($this->map) && !is_null($this->dbID)) {
$this->load();
}
$this->width = $value;
if (is_array($this->map)) {
$this->initBlankMap();
}
}
public function setHeight($value) {
if (is_null($this->map) && !is_null($this->dbID)) {
$this->load();
}
$this->height = $value;
if (is_array($this->map)) {
$this->initBlankMap();
}
}
public function getMapInfo($x, $y) {
if (! is_array($this->map)) {
if ($this->dbID) {
$this->load();
} else {
return null;
}
}
$offset = $this->getOffset($x, $y);
return $this->map[$offset];
}
public function setSystemType($x, $y, $t) {
if (! is_array($this->map)) {
if ($this->dbID) {
$this->load();
} else {
$this->initBlankMap();
}
}
$offset = $this->getOffset($x, $y);
$v = $this->map[$offset];
if (is_null($v)) {
$v = $this->map[$offset] = new ctf_map_sys($x, $y, $t);
} else {
$v->setType($t);
}
}
public function setSystemAlloc($x, $y, $a) {
if (! is_array($this->map)) {
if ($this->dbID) {
$this->load();
} else {
$this->initBlankMap();
}
}
$offset = $this->getOffset($x, $y);
$v = $this->map[$offset];
if (is_null($v)) {
$v = $this->map[$offset] = new ctf_map_sys($x, $y, 'S');
}
if ($v->getType() != 'S') {
throw new Exception("Can't set allocation type for a nebula");
}
if ($a < 0 || $a > $this->alliances) {
throw new Exception("Invalid allocation type $a");
}
$v->setAllocation($a);
}
public function setSystemSpawn($x, $y, $s) {
if (! is_array($this->map)) {
if ($this->dbID) {
$this->load();
} else {
$this->initBlankMap();
}
}
$offset = $this->getOffset($x, $y);
$v = $this->map[$offset];
if (is_null($v)) {
$v = $this->map[$offset] = new ctf_map_sys($x, $y, 'S', 1, $s);
} else {
if ($v->getType() != 'S' || $v->getAllocation() < 1) {
throw new Exception("Can't set spawning point");
}
$v->setSpawn($s);
}
}
public function jsDump() {
$parts = array();
if (is_null($this->map)) {
if ($this->dbID) {
$this->load();
} else {
$this->initBlankMap();
}
}
foreach ($this->map as $s) {
if (is_null($s)) {
continue;
}
$str = '[' . $s->getX() . ',' . $s->getY() . ',"' . $s->getType() . '",';
if ($s->getType() != 'S') {
$str .= 'null,null';
} else {
$str .= $s->getAllocation() . ',';
if ($s->getAllocation()) {
$str .= $s->getSpawn() ? 'true' : 'false';
} else {
$str .= 'null';
}
}
array_push($parts, "$str]");
}
return join(',', $parts);
}
public function save() {
$db = __dbConnect();
if (!$db) {
throw new Exception("Database error");
}
pg_query($db, "BEGIN TRANSACTION");
pg_query($db, "SET search_path = public, main");
if ($this->dbID) {
$id = $this->dbID;
pg_query_params($db, "UPDATE main.ctf_map_def SET name=$2, description=$3, alliances=$4, "
. "width=$5, height=$6 WHERE id=$1", array(
$id, $this->name, $this->description, $this->alliances,
$this->width, $this->height
));
pg_query($db, "DELETE FROM main.ctf_map_layout WHERE map=$id");
} else {
pg_query_params($db, "INSERT INTO main.ctf_map_def(name,description,alliances,width,height) "
. "VALUES ($1, $2, $3, $4, $5)", array(
$this->name, $this->description, $this->alliances,
$this->width, $this->height
));
$q = pg_query($db, "SELECT last_inserted('ctf_map_def')");
if (!($q && pg_num_rows($q))) {
throw new Exception("Database error");
}
list($id) = pg_fetch_array($q);
}
foreach ($this->map as $sys) {
$sys->store($db, $id);
}
pg_query($db, "COMMIT");
pg_close($db);
$this->dbID = $id;
}
public function destroy() {
if (! $this->dbID) {
return;
}
$db = __dbConnect();
if (!$db) {
throw new Exception("Database error");
}
pg_query($db, "DELETE FROM main.ctf_map_def WHERE id={$this->dbID}");
pg_close($db);
}
private function load() {
$db = __dbConnect();
if (!$db) {
throw new Exception("Database error");
}
$result = pg_query($db, "SELECT * FROM main.ctf_map_layout WHERE map = {$this->dbID}");
if (!($result && pg_num_rows($result) == $this->height * $this->width)) {
throw new Exception("Unable to load map");
}
$map = array();
while ($row = pg_fetch_assoc($result)) {
$offset = $this->getOffset($row['sys_x'], $row['sys_y']);
$map[$offset] = new ctf_map_sys($row['sys_x'], $row['sys_y'],
$row['sys_type'], $row['alloc_for'], $row['spawn_here']);
}
$this->map = $map;
pg_free_result($result);
pg_close($db);
}
private function initBlankMap() {
$map = array();
for ($i = 0; $i < $this->width * $this->height; $i ++) {
$map[$i] = null;
}
$this->map = $map;
}
private function getOffset($x, $y) {
return $this->width * (floor($this->height / 2) + $y) + floor($this->width / 2) + $x;
}
}
?>

494
admin/deathofrats.php Normal file
View file

@ -0,0 +1,494 @@
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Death of Rats</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Death of Rats</h1>
<p>
The Death of Rats is LegacyWorlds' experimental multi detection tool.<br/>
Select page:
<?
set_magic_quotes_runtime(false);
include('config.inc');
switch ($_GET['p']) {
case 'e': $page = 'execution'; break;
case 'sl': $page = 'singlelog'; break;
case 'sp': $page = 'signlepoints'; break;
case 'ml': $page = 'multilog'; break;
case 'mp': $page = 'multipoints'; break;
case 'al': $page = 'actions'; break;
case 'fp': $page = 'finalpoints'; break;
case 'il': $page = 'ingamelog'; break;
default: $page = "status"; break;
}
$pages = array(
'status' => array('s', 'Current status', 'showStatus'),
'actions' => array('al', 'Actions taken', 'showActionLog'),
'finalpoints' => array('fp', 'Decision points', 'showFinalPoints'),
'ingamelog' => array('il', 'In-game checks', 'showInGameChecks'),
'multipoints' => array('mp', 'Multiplayer points', 'showMultiPoints'),
'multilog' => array('ml', 'Multiplayer log', 'showMultiLog'),
'signlepoints' => array('sp', 'Single player points', 'showSinglePoints'),
'singlelog' => array('sl', 'Single player events', 'showSingleLog'),
'execution' => array('e', 'Execution log', 'showExecLog'),
);
foreach ($pages as $pName => $data) {
if ($pName == $page) {
echo "<b>";
} else {
echo "<a href='?p={$data[0]}'>";
}
echo $data[1];
if ($pName == $page) {
echo "</b> ";
} else {
echo "</a> ";
}
}
echo "</p>";
$func = $pages[$page][2];
$func();
function showStatus() {
?>
<h2>Current status</h2>
<p>
The Death of Rats is still in an <b><u>experimental</u></b> stage at this time, and no actual action is taken. What
it <i>would</i> do if it were fully enabled is logged on the "Actions taken" page nonetheless.<br/>
Most of the information it provides can be trusted, tho; however, if you suspect it sent a warning or "punished" a
player for no good reason, manual checks should be performed.
</p>
<p>
The following checks are performed:
</p>
<ul>
<li>use of open proxies</li>
<li>cookie deletion</li>
<li>trying to log on with a banned account</li>
<li>passwords shared between multiple accounts</li>
<li>simple multiing, as well as pass sharing</li>
<li>"vicious" multiing, implying that the cookies are cleared between each use</li>
<li>in-game checks for donations, tech exchanges, gifts and sales, and planet retake after abandon</li>
</ul>
<p>
Checks for concurrent session from the same IP as well as more in-game checks (alliance, posts, messages,
TA list, battles) are still missing.
</p>
<h2>About the different pages</h2>
<p>
This tool consists in a few different pages which give different information about the Death of Rats' current status.
These pages are:
</p>
<ul>
<li>
<b>Actions taken</b>: the log of all actions the Death of Rats performed. This includes sending
warnings and deciding to punish players.
</li>
<li>
<b>Decision points</b>: the current amount of points for each pair of players that has been investigated thoroughly
by the Death of Rats. Pairs with over 100 points will cause the Death of Rats to act.
</li>
<li>
<b>In-game checks log</b>: the latest 400 entries of the checks performed in-game on suspicious players as well
as the results of these checks.
</li>
<li>
<b>Multiplayer points</b>: the current amount of points for each pair of accounts that could be multiing or
abusing pass-sharing.
</li>
<li>
<b>Multiplayer log</b>: the latest 200 entries of the suspicious events detected between pairs of accounts.
</li>
<li>
<b>Single player points</b>: the current amount of points for each account that has performed suspicious actions.
While these points are normally not a problem, they influence multiplayer scores.
</li>
<li>
<b>Single player log</b>: the latest 200 suspicious events detected for single accounts.
</li>
<li>
<b>Execution log</b>: the latest 200 runs of the Death of Rats.
</li>
</ul>
<?
}
function showExecLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT * FROM main.dor_exec ORDER BY ts DESC LIMIT 200");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
<h2>Previous 200 runs of the Death of Rats</h2>
<p>
This page shows the log of the previous 200 executions of the Death of Rats tick. The <i>Changes</i> column indicates
the amount of changes (connection records, password updates) examined; the <i>Events</i> column indicates the amount
of entries added to either the single player log or the multiplayer log.
</p>
<table border="1">
<tr>
<th>Time &amp; date</th>
<th>Changes</th>
<th>Events</th>
</tr>
<?
foreach ($entries as $entry) {
?>
<tr>
<td align="center"><?=$entry['events'] ? "<b>" : ""?><?=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?><?=$entry['events'] ? "</b>" : ""?></td>
<td align="center"><?=$entry['events'] ? "<b>" : ""?><?=$entry['entries']?><?=$entry['events'] ? "</b>" : ""?></td>
<td align="center"><?=$entry['events'] ? "<b>" : ""?><?=$entry['events']?><?=$entry['events'] ? "</b>" : ""?></td>
</tr>
<?
}
?>
</table>
<?
}
function showSingleLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a.name,l.message,l.ts FROM main.dor_single l, main.account a WHERE a.id = l.account AND a.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.ts DESC,a.name ASC LIMIT 200");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
<h2>Previous 200 single player log entries</h2>
<p>
This page shows the log of the previous 200 log entries generated for single players.
</p>
<table border="1">
<tr>
<th>Time &amp; date</th>
<th>Account</th>
<th align="left">Message</th>
</tr>
<?
$messages = array(
"ASSHOLE" => "Tried to log on using a banned account",
"PROXY" => "Currently using an open proxy",
"CLCOOK-SIP" => "Cleared cookies from the same IP",
"CLCOOK-DIP" => "Cleared cookies from a different (but close) IP",
);
foreach ($entries as $entry) {
?>
<tr>
<td align="center"><?=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
<td align="center"><?=htmlentities($entry['name'])?></td>
<td><?=$messages[$entry['message']]?></td>
</tr>
<?
}
?>
</table>
<?
}
function showSinglePoints() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a.name,l.points FROM main.dor_single_points l, main.account a WHERE a.id = l.account AND a.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.points DESC,a.name ASC");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
<h2>Single player "badness points"</h2>
<p>
These points correspond to recent suspicious activities from active accounts.
</p>
<table border="1">
<tr>
<th>Account</th>
<th>Points</th>
</tr>
<?
foreach ($entries as $entry) {
?>
<tr>
<td align="center"><?=htmlentities($entry['name'])?></td>
<td align="center"><?=$entry['points']?></td>
</tr>
<?
}
?>
</table>
<?
}
function showInGameChecks() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a1.name as name1, a2.name as name2, l.message, l.ts, l.game FROM main.dor_ingame_check l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.ts DESC,a1.name ASC, a2.name ASC LIMIT 400");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
<h2>Latest 400 in-game checks log entries</h2>
<p>
This page shows the log of the latest 400 log entries generated by in-game checks on players. Events logged here
belong to different categories:
</p>
<ul>
<li><b>Somewhat suspicious events</b>: donations of less than &euro;100,000; rejected tech offers</li>
<li>
<b>Suspicious events</b>: donations of less than &euro;1,000,000; pending tech offers; accepted techs offer with
a price greater than &euro;1,000; planets taken by a player within 5 days of being abandonned by the other; sales
of planets or fleets.
</li>
<li>
<b>Highly suspicious events</b>: donations of less than &euro;10,000,000; gifts; tech offers with a price lower
than &euro;1,000.
</li>
<li>
<b>Extremely suspicious events</b>: donations of more than &euro;10,000,000.
</li>
</ul>
<table border="1">
<tr>
<th>Time &amp; date</th>
<th>Game ID</th>
<th>Account 1</th>
<th>Account 2</th>
<th align="left">Message</th>
<th>Count</th>
</tr>
<?
$messages = array(
"CHECK" => "Verifying accounts",
"VHSE" => "Extremely suspicious in-game events",
"HSE" => "Highly suspicious in-game events",
"SE" => "Suspicious in-game events",
"LSE" => "Somewhat suspicious in-game events"
);
foreach ($entries as $entry) {
list($message, $count) = explode('-', $entry['message']);
if ($message == 'CHECK') {
$count = "N/A";
}
?>
<tr>
<td align="center"><?=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
<td align="center"><?=$entry['game']?></td>
<td align="center"><?=htmlentities($entry['name1'])?></td>
<td align="center"><?=htmlentities($entry['name2'])?></td>
<td><?=$messages[$message]?></td>
<td align="center"><?=$count?></td>
</tr>
<?
}
?>
</table>
<?
}
function showMultiLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT (a1.id || ',' || a2.id) as id, a1.name as name1, a2.name as name2, l.message, l.ts FROM main.dor_multi l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.ts DESC,a1.name ASC, a2.name ASC LIMIT 400");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
$displayed = array();
?>
<h2>Previous 200 multiplayer log entries</h2>
<p>
This page shows the log of the previous 200 log entries generated for pairs of players.
</p>
<table border="1">
<tr>
<th>Time &amp; date</th>
<th>Account 1</th>
<th>Account 2</th>
<th align="left">Message</th>
</tr>
<?
$messages = array(
"SIMPLE" => "Simple multiing / open pass sharing detected",
"SIMPLE-10" => "Simple multiing / open pass sharing detected (within 10 seconds!)",
"PASS" => "Accounts are using the same password",
"NOPASS" => "Accounts are no longer using the same password",
"VICIOUS-LP" => "Potential attempt to conceal pass-sharing",
"VICIOUS-MP" => "Probable attempt to conceal pass-sharing",
"VICIOUS-HP" => "Highly probable attempt to conceal pass-sharing",
);
foreach ($entries as $entry) {
$id = explode(',', $entry['id']);
sort($id);
$id = join(',', $id) . "-" . $entry['ts'] . "-" . $entry['message'];
if (in_array($id, $displayed)) {
continue;
}
$displayed[] = $id;
?>
<tr>
<td align="center"><?=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
<td align="center"><?=htmlentities($entry['name1'])?></td>
<td align="center"><?=htmlentities($entry['name2'])?></td>
<td><?=$messages[$entry['message']]?></td>
</tr>
<?
}
?>
</table>
<?
}
function showFinalPoints() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT a1.name as name1, a2.name as name2, l.points FROM main.dor_final_points l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.points DESC,a1.name ASC, a2.name ASC");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
<h2>Final decision points</h2>
<p>
This page displays the current amount of points for each pair of players that has been investigated thoroughly
by the Death of Rats. Pairs will over 100 points will cause the Death of Rats to act.
</p>
<table border="1">
<tr>
<th>Account 1</th>
<th>Account 2</th>
<th>Points</th>
</tr>
<?
foreach ($entries as $entry) {
?>
<tr>
<td align="center"><?=htmlentities($entry['name1'])?></td>
<td align="center"><?=htmlentities($entry['name2'])?></td>
<td><?=$entry['points']?></td>
</tr>
<?
}
?>
</table>
<?
}
function showMultiPoints() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db, "SELECT (a1.id || ',' || a2.id) as id, a1.name as name1, a2.name as name2, l.points FROM main.dor_multi_points l, main.account a1, main.account a2 WHERE a1.id = l.account1 AND a2.id = l.account2 AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') ORDER BY l.points DESC,a1.name ASC, a2.name ASC");
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
$displayed = array();
?>
<h2>Multiplayer "badness points"</h2>
<p>
This page shows the list of "badness points" between pairs of accounts. The higher the badness points, the more likely
the accounts are multis.
</p>
<table border="1">
<tr>
<th>Account 1</th>
<th>Account 2</th>
<th>Points</th>
</tr>
<?
foreach ($entries as $entry) {
$id = explode(',', $entry['id']);
sort($id);
$id = join(',', $id);
if (in_array($id, $displayed)) {
continue;
}
$displayed[] = $id;
?>
<tr>
<td align="center"><?=htmlentities($entry['name1'])?></td>
<td align="center"><?=htmlentities($entry['name2'])?></td>
<td><?=$entry['points']?></td>
</tr>
<?
}
?>
</table>
<?
}
function showActionLog() {
$db = __dbConnect();
$entries = array();
$q = pg_query($db,
"SELECT * FROM ("
. "SELECT a1.name AS name1, a2.name AS name2, l.ts AS ts, 'WARN' AS atype "
. "FROM main.dor_warning l, main.account a1, main.account a2 "
. "WHERE a1.id = l.account1 AND a2.id = l.account2 "
. "AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') "
. "AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED') "
. "UNION SELECT a1.name AS name1, a2.name AS name2, l.ts AS ts, 'PUNISH' AS atype "
. "FROM main.dor_warning l, main.account a1, main.account a2 "
. "WHERE a1.id = l.account1 AND a2.id = l.account2 "
. "AND a1.status NOT IN ('QUIT', 'INAC', 'KICKED') "
. "AND a2.status NOT IN ('QUIT', 'INAC', 'KICKED')"
. ") AS t ORDER BY t.ts DESC, t.name1 ASC, t.name2 ASC"
);
while ($r = pg_fetch_assoc($q)) {
$entries[] = $r;
}
pg_close($db);
?>
<h2>Actions performed by the Death of Rats</h2>
<p>
This page lists all the actions the Death of Rats has performed.
</p>
<table border="1">
<tr>
<th>Time &amp; date</th>
<th>Account 1</th>
<th>Account 2</th>
<th align="left">Message</th>
</tr>
<?
$messages = array(
"WARN" => "Warned player",
"PUNISH" => "Slaughtered player with a rat-sized scythe"
);
foreach ($entries as $entry) {
?>
<tr>
<td align="center"><?=gmstrftime("%H:%M:%S / %Y-%m-%d", $entry['ts'])?>
<td align="center"><?=htmlentities($entry['name1'])?></td>
<td align="center"><?=htmlentities($entry['name2'])?></td>
<td><?=$messages[$entry['atype']]?></td>
</tr>
<?
}
?>
</table>
<?
}
?>
</body>
</html>

242
admin/game_status.php Normal file
View file

@ -0,0 +1,242 @@
<?php
set_magic_quotes_runtime(false);
include("config.inc");
include("as_log.inc");
function redirect() {
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Game status</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Game status</h1>
<h2>Operation in progress...</h2>
<p>
A system operation is in progress. Please wait, the page will update in 5 seconds.
</p>
<script language="JavaScript">
window.setTimeout('window.location="game_status.php"', 5000);
</script>
</body>
</html>
<?php
exit(0);
}
function printStatus($status) {
static $styles = array(
"PRE" => array('yellow', 'red'),
"READY" => array('red', 'yellow'),
"RUNNING" => array('white', 'green'),
"VICTORY" => array('yellow', 'blue'),
"ENDING" => array('black', 'yellow'),
"FINISHED" => array("white", "black")
);
print "<th style='color:" . $styles[$status][0] . ";background-color:"
. $styles[$status][1] . "'>$status</th>";
}
function sendFifo($command) {
global $aConfig;
$fName = $aConfig['ctrlFifo'];
if (!file_exists($fName)) {
return false;
}
$fifo = fopen($fName, "w");
fwrite($fifo, "$command\n");
fclose($fifo);
redirect();
}
function handleCommand($command, $game) {
if ($command == 'mv' && $game->status() == 'PRE') {
__logAdmin("is making game {$game->name} visible");
sendFifo("READY {$game->name}");
} elseif ($command == 'te' && $game->status() == 'READY' && $game->firstTick() - time() > 24 * 60 * 60 + 30) {
__logAdmin("made game {$game->name} start 24h earlier");
sendFifo("START {$game->name} EARLY");
} elseif ($command == 'tl' && $game->status() == 'READY') {
__logAdmin("made game {$game->name} start 24h later");
sendFifo("START {$game->name} LATE");
} elseif ($command == 'en' && ($game->status() == 'RUNNING' || $game->status() == "VICTORY")) {
__logAdmin("terminated game {$game->name}");
sendFifo("SETEND {$game->name} 0");
} elseif ($command == 'e24' && $game->status() == 'RUNNING') {
__logAdmin("set game {$game->name} to end in 24h");
sendFifo("SETEND {$game->name} 24");
} elseif ($command == 'kr' && $game->status() == 'ENDING') {
__logAdmin("prevented game {$game->name} from ending");
sendFifo("NOEND {$game->name}");
} elseif ($command == 'ee' && $game->status() == 'ENDING' && $game->lastTick() - time() > 24 * 60 * 60 + 30) {
__logAdmin("made game {$game->name} end 24h earlier");
sendFifo("END {$game->name} EARLY");
} elseif ($command == 'el' && $game->status() == 'ENDING') {
__logAdmin("made game {$game->name} end 24h later");
sendFifo("END {$game->name} LATE");
} elseif ($command == 'en' && $game->status() == 'ENDING') {
__logAdmin("terminated game {$game->name}");
sendFifo("END {$game->name} NOW");
}
}
// Load the list of games
$oldDir = getcwd();
chdir("../scripts");
$__logPrefix = "lwControl";
$__loader = array(
'log', 'classloader',
'version', 'game', 'tick', 'config',
'db_connection', 'db_accessor', 'db',
'library'
);
require_once("loader.inc");
chdir($oldDir);
$games = config::getGames();
dbConnect();
// Handle commands
if ($_GET['c'] != '') {
$cGame = $_GET['g'];
if (array_key_exists($cGame, $games) && $cGame != 'main') {
handleCommand($_GET['c'], $games[$cGame]);
}
}
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Game status</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Game status</h1>
<h2>Game list</h2>
<p>
<b>WARNING:</b> make sure you know what you're doing here - there are no second chances on this page;
if you click something, that "something" <i>will</i> happen <i>at once</i>.
</p>
<table border="1" width="100%">
<tr>
<th style="text-align:left; width:10%">ID</th>
<th style="width:10%">Status</th>
<th style="text-align:left;width:20%">Name</th>
<th style="text-align:left">Ticks</th>
<th style="text-align:left;width:30%">Commands</th>
</tr>
<?php
foreach ($games as $name => $game) {
if ($name == 'main') {
continue;
}
$status = $game->status();
$firstTick = $game->firstTick();
$lastTick = $game->lastTick();
print " <tr>\n <td><b>$name</b></td>\n";
printStatus($status);
print " <td>" . htmlentities($game->text) . "</td>\n";
print " <td>";
if ($firstTick > time()) {
print "Starting at " . gmstrftime('%H:%M:%S on %Y-%m-%d', $firstTick);
} elseif ($lastTick == 0) {
print "Running since " . gmstrftime('%H:%M:%S on %Y-%m-%d', $firstTick);
} elseif ($lastTick > time()) {
print "Running until " . gmstrftime('%H:%M:%S on %Y-%m-%d', $lastTick);
} else {
print "Stopped since " . gmstrftime('%H:%M:%S on %Y-%m-%d', $lastTick);
}
if ($status == 'PRE') {
$cmd = array(
array('mv', 'Make visible')
);
} elseif ($status == 'READY') {
$cmd = array(
array('tl', 'Start 24h later')
);
if ($firstTick - time() > 24 * 60 * 60 + 30) {
array_push($cmd, array('te', 'Start 24h earlier'));
}
} elseif ($status == 'RUNNING') {
$cmd = array(
array('e24', 'End in 24h'),
array('en', 'End now')
);
} elseif ($status == 'VICTORY') {
$cmd = array(
array('en', 'End game')
);
} elseif ($status == 'ENDING') {
$cmd = array(
array('el', 'Postpone by 24h')
);
if ($lastTick - time() > 24 * 60 * 60 + 30) {
array_push($cmd, array('ee', 'End 24h earlier'));
}
array_push($cmd, array('en', 'End now'));
array_push($cmd, array('kr', 'Keep running'));
} else {
$cmd = array();
}
print "</td>\n <td>";
if (count($cmd)) {
$lk = array();
foreach ($cmd as $c) {
array_push($lk, "<a href='?c=" . $c[0] . "&g=$name' onclick=\"return confirm('You selected \\'"
. $c[1] . "\\' on game \\'$name\\'. Please confirm.');\">" . $c[1] . "</a>");
}
print join(' - ', $lk);
} else {
print "&nbsp;";
}
print "</td>\n </tr>\n";
}
?>
</table>
<h3>About game status</h3>
<p>Games can have the following status:</p>
<table>
<tr>
<?printStatus('PRE');?>
<td>The game is configured, but is hidden for now</td>
</tr>
<tr>
<?printStatus('READY');?>
<td>The game is visible, but ticks have not started</td>
</tr>
<tr>
<?printStatus('RUNNING');?>
<td>The game is running normally</td>
</tr>
<tr>
<?printStatus('VICTORY');?>
<td>The game is still running but someone reached victory</td>
</tr>
<tr>
<?printStatus('ENDING');?>
<td>The game is still available but is about to end.</td>
</tr>
<tr>
<?printStatus('FINISHED');?>
<td>The game is no longer running and only visible through the rankings page</td>
</tr>
</table>
</body>
</html>

25
admin/index.html Normal file
View file

@ -0,0 +1,25 @@
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration</title>
</head>
<body>
<h1>LW Beta 5 administration tools</h1>
<h2>Game management</h2>
<ul>
<li><a href="game_status.php">Game status</a>: display and manage existing games</li>
<li><a href="create.php?reset=1">Game creation</a>: create new LegacyWorlds rounds or matches</li>
<li><a href="set_default.php">Default game</a> (game for which rankings are displayed)</li>
<li><a href="deathofrats.php">Death of Rats</a>: experimental multi detection tool</li>
</ul>
<h2>Server management</h2>
<ul>
<li><a href="ticks.php">Ticks</a>: enable / disable the tick manager, run ticks manually</li>
<li><a href="proxy.php">Proxy detector</a>: control the detector's status and manually check for open proxies</li>
<li><a href="maintenance.php">Maintenance</a>: activate / de-activate maintenance mode</li>
<li><a href="maps.php">Maps management</a>: manage maps used for <i>Kings of the Hill</i> games</li>
<li><a href="bot.php">IRC bot</a>: control the IRC bot</li>
</ul>
</body>
</html>

79
admin/maintenance.php Normal file
View file

@ -0,0 +1,79 @@
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Maintenance mode</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Maintenance mode</h1>
<?php
set_magic_quotes_runtime(false);
include('../scripts/config.inc');
include('as_log.inc');
$err = $reason = $duration = null;
if ($_GET['disable'] == '1' && !is_null($config['maintenance'])) {
unlink($config['cachedir'] . '/maintenance.ser');
include('../scripts/config.inc');
__logAdmin("put the server out of maintenance mode");
} elseif ($_POST['enable'] != '' && is_null($config['maintenance'])) {
$reason = $_POST['reason'];
$duration = (int) $_POST['duration'];
if (strlen($reason) < 10) {
$err = "Reason too short (min 10 characters).";
} elseif ($duration < 5) {
$err = "Duration too short (min 5 minutes).";
} else {
$maintenance = array(
"until" => time() + $duration * 60,
"reason" => $reason
);
$f = fopen($config['cachedir'] . '/maintenance.ser', "w");
fwrite($f, serialize($maintenance));
fclose($f);
include('../scripts/config.inc');
__logAdmin("put the server in maintenance mode for reason: $reason");
}
}
if (is_null($config['maintenance'])) {
?>
<p>
Maintenance mode is currently inactive. Please use the form below to activate it.
</p>
<form method="POST" action="?">
<p>
Reason for maintenance: <input type="text" maxlength="100" name="reason" size="40" value="<?=htmlentities($reason)?>" /><br/>
Maintenance mode duration: <input type="text" maxlength="3" name="duration" size="4" value="<?=$duration?>" /> minutes
</p>
<?php
if ($err) {
print "<p style='color:red'>$err</p>\n";
}
?>
<p>
<input type="submit" name="enable" value="Activate maintenance mode" />
</p>
</form>
<?php
} else {
?>
<p>
Maintenance mode is currently <b>active</b>.
</p>
<p>
<u>Reason:</u> <?=$config['maintenance']['reason']?><br/>
<u>Until:</u> <?=gmstrftime("%H:%M:%S on %m/%d/%Y", $config['maintenance']['until'])?>
(current: <?=gmstrftime("%H:%M:%S on %m/%d/%Y", time())?>).
</p>
<p><a href="?disable=1">Disable maintenance mode</a></p>
<?
}
?>
</body>
</html>

703
admin/map_edit.js Normal file
View file

@ -0,0 +1,703 @@
// Generic text input component
TextInput = function (id, title, multi, min, max, init) {
this.id = id;
this.title = title;
this.multi = multi;
var value = init;
this.min = min;
this.max = max;
this.valid = false;
this.onChange = null;
var readValue = function () {
var e = document.getElementById(id + '-input');
if (e) {
value = e.value;
}
};
this.getText = function () {
readValue();
return value;
};
this.draw = function () {
readValue();
var str = '<table style="width: 100%; border-style: none; padding: 2px; margin: 0px">'
+ '<tr><th style="text-align:right; padding: 0px 5px; width: 120px;vertical-align:top">'
+ this.title + ':</th><td style="text-align: center">';
var jsStr = '="TextInput.byId[\'' + this.id + '\'].__change(); return true"';
if (this.multi) {
str += '<textarea id="' + this.id + '-input" rows="5" style="width: 100%" onChange'
+ jsStr + ' onKeyUp' + jsStr + ' onClick' + jsStr + '></textarea>';
} else {
str += '<input type="text" id="' + this.id + '-input" style="width: 100%" onChange'
+ jsStr + ' onKeyUp' + jsStr + ' onClick' + jsStr + '/>';
}
str += '</td></tr></table>';
document.getElementById(this.id).innerHTML = str;
document.getElementById(this.id + '-input').value = value;
this.checkValidity();
};
this.checkValidity = function () {
this.valid = (this.min == 0 && this.max == 0);
if (!this.valid) {
this.valid = (this.min > 0 && value.length >= this.min || this.min == 0)
&& (this.max > 0 && value.length <= this.max || this.max == 0);
}
with (document.getElementById(this.id + '-input').style) {
color = this.valid ? 'black' : 'white';
backgroundColor = this.valid ? 'white' : 'red';
}
};
this.__change = function () {
readValue();
this.checkValidity();
if (this.onChange) {
this.onChange(value);
}
};
TextInput.byId[this.id] = this;
};
TextInput.byId = {};
// Generic numeric control for size and amount of alliances
NumericControl = function (id, title, min, max, init) {
this.id = id;
this.title = title;
this.min = min;
this.max = max;
this.value = init;
this.onChange = null;
this.draw = function () {
var str = '<table style="width: 100%; border-style: none; padding: 2px; margin: 0px">'
+ '<tr><th style="text-align:right; padding: 0px 5px">' + this.title
+ ':</th><td style="text-align: center; width: 20px">' + this.value
+ '</td><td style="width: 70px; text-align:center">'
+ '<input type="button" onClick="NumericControl.byId[\''
+ this.id + '\'].decrease()" value="-" style="width: 24px" /> '
+ '<input type="button" onClick="NumericControl.byId[\''
+ this.id + '\'].increase()" value="+" style="width: 24px" /></td>'
+ '</tr></table>';
document.getElementById(this.id).innerHTML = str;
};
this.increase = function () {
if (this.value == this.max) {
return;
}
this.value ++;
this.draw();
if (this.onChange) {
this.onChange(this.value);
}
};
this.decrease = function () {
if (this.value == this.min) {
return;
}
this.value --;
this.draw();
if (this.onChange) {
this.onChange(this.value);
}
};
NumericControl.byId[this.id] = this;
};
NumericControl.byId = {};
// A system on the map
MapLocation = function (type, alloc, spawn) {
this.type = type;
this.alloc = alloc;
this.spawn = spawn;
};
// The map itself
Map = function (initFrom) {
// Copy basic map information
this.name = initFrom.name;
this.description = initFrom.description;
this.alliances = initFrom.alliances;
this.width = initFrom.width;
this.height = initFrom.height;
// Copy the map
this.map = { };
for (var i in initFrom.map) {
var ma = initFrom.map[i];
this.map['x' + ma[0] + 'y' + ma[1]] = new MapLocation(ma[2], ma[3], ma[4]);
}
// Function that computes min/max x/y
this.updateCoordinates = function () {
this.minX = - Math.floor(this.width / 2);
this.maxX = this.minX + this.width - 1;
this.minY = - Math.floor(this.height / 2);
this.maxY = this.minY + this.height - 1;
};
// Creates a nebula area
this.setNebula = function (x, y, opacity) {
if (this.map['x' + x + 'y' + y]) {
this.map['x' + x + 'y' + y].type = opacity;
} else {
this.map['x' + x + 'y' + y] = new MapLocation(opacity, null, null);
}
};
// Creates a target system
this.setTarget = function (x, y) {
if (this.map['x' + x + 'y' + y]) {
this.map['x' + x + 'y' + y].type = 'S';
this.map['x' + x + 'y' + y].alloc = 0;
} else {
this.map['x' + x + 'y' + y] = new MapLocation('S', 0, null);
}
};
// Creates an alliance-controlled system
this.setAlliance = function (x, y, alliance) {
var sys = this.map['x' + x + 'y' + y];
if (sys) {
sys.type = 'S';
sys.alloc = alliance;
sys.spawn = false;
} else {
this.map['x' + x + 'y' + y] = new MapLocation('S', alliance, false);
}
};
// Switches spawning status for an alliance-controlled system
this.switchSpawnPoint = function (x, y) {
var sys = this.map['x' + x + 'y' + y];
if (sys && sys.type == 'S' && sys.alloc > 0) {
sys.spawn = !sys.spawn;
}
};
// Removes systems allocated to alliances which no longer exist
this.removeExtraAlliances = function () {
for (var i in this.map) {
var sys = this.map[i];
if (sys.type == 'S' && sys.alloc > this.alliances) {
this.map[i] = null;
}
}
};
this.updateCoordinates();
};
// The editor's grid
Grid = function (id, map) {
this.id = id;
this.map = map;
this.cX = 0;
this.cY = 0;
this.onClick = null;
// This function draws the grid in which the map is displayed
this.draw = function () {
var i, j;
var str = '<table style="border: 1px solid black; border-collapse: collapse; padding: 0px; margin: 0px">'
+ '<tr><td style="border: 1px solid black;width: 32px;height:32px">&nbsp;</td>'
+ '<td style="border: 1px solid black; width:416px" colspan="13" id="map-up">&nbsp;</td>'
+ '<td style="border: 1px solid black;width: 32px">&nbsp;</td></tr>'
+ '<tr><td style="border: 1px solid black; height:416px" rowspan="13" id="map-left">&nbsp;</td>'
+ '<td style="border: 1px solid black;width: 32px;height:32px">&nbsp;</td>';
for (i = 0; i < 11; i ++) {
str += '<td style="border: 1px solid black;width: 32px; height: 32px; text-align: center" '
+ 'id="top-x-' + i + '">&nbsp;</td>';
}
str += '<td style="border: 1px solid black;width: 32px;height:32px">&nbsp;</td>'
+ '<td style="border: 1px solid black; height:416px" rowspan="13" id="map-right">&nbsp;</td>'
+ '</tr>';
for (i = 0; i < 11; i ++) {
str += '<tr><td style="border: 1px solid black;width: 32px; height: 32px; text-align: center" '
+ 'id="left-y-' + i + '">&nbsp;</td>';
for (j = 0; j < 11; j ++) {
str += '<td style="border: 1px solid #7f7f7f; width: 32px; height: '
+ '32px; text-align:center" id="map-' + j + '-' + i
+ '" onclick="Editor.editor.mapClick(' + j + ',' + i +')">&nbsp;</td>';
}
str += '<td style="border: 1px solid black;width: 32px; height: 32px; text-align:center" '
+ 'id="right-y-' + i + '">&nbsp;</td></tr>';
}
str += '<tr><td style="border: 1px solid black;width: 32px;height:32px">&nbsp;</td>';
for (i = 0; i < 11; i ++) {
str += '<td style="border: 1px solid black;width: 32px; height: 32px;text-align:center" '
+ 'id="bottom-x-' + i + '">&nbsp;</td>';
}
str += '<td style="border: 1px solid black;width: 32px;height:32px">&nbsp;</td></tr>'
+ '<tr><td style="border: 1px solid black;width: 32px; height:32px">&nbsp;</td>'
+ '<td style="border: 1px solid black; width:416px" colspan="13" id="map-down">&nbsp;</td>'
+ '<td style="border: 1px solid black;width: 32px">&nbsp;</td></tr>'
+ '</table>';
document.getElementById(this.id).innerHTML = str;
this.drawMap();
};
// This function draws the map on the grid
this.drawMap = function () {
var i, j, str, x, y;
// Scroll buttons
if (this.cX - 5 > this.map.minX) {
str = '<input type="button" value="<" style="width:100%;height:100%;margin:0"'
+ ' onclick="Editor.editor.scroll(-1, 0)" />';
} else {
str = '&nbsp;';
}
document.getElementById('map-left').innerHTML = str;
if (this.cX + 5 < this.map.maxX) {
str = '<input type="button" value=">" style="width:100%;height:100%;margin:0"'
+ ' onclick="Editor.editor.scroll(1, 0)" />';
} else {
str = '&nbsp;';
}
document.getElementById('map-right').innerHTML = str;
if (this.cY - 5 > this.map.minY) {
str = '<input type="button" value="\\/" style="width:100%;height:100%;margin:0"'
+ ' onclick="Editor.editor.scroll(0, -1)" />';
} else {
str = '&nbsp;';
}
document.getElementById('map-down').innerHTML = str;
if (this.cY + 5 < this.map.maxY) {
str = '<input type="button" value="/\\" style="width:100%;height:100%;margin:0"'
+ ' onclick="Editor.editor.scroll(0, 1)" />';
} else {
str = '&nbsp;';
}
document.getElementById('map-up').innerHTML = str;
// Draw X coordinates
for (i = 0; i < 11; i ++) {
x = this.cX + i - 5;
if (x < this.map.minX || x > this.map.maxX) {
str = '&nbsp;';
} else {
str = '<b>' + x + '</b>';
}
document.getElementById('top-x-' + i).innerHTML =
document.getElementById('bottom-x-' + i).innerHTML = str;
}
// Draw Y coordinates
for (i = 0; i < 11; i ++) {
y = this.cY - i + 5;
if (y < this.map.minY || y > this.map.maxY) {
str = '&nbsp;';
} else {
str = '<b>' + y + '</b>';
}
document.getElementById('left-y-' + i).innerHTML =
document.getElementById('right-y-' + i).innerHTML = str;
}
// Draw contents
for (i = 0; i < 11; i ++) {
x = this.cX + i - 5;
for (j = 0; j < 11; j ++) {
y = this.cY - j + 5;
var cell = document.getElementById('map-' + i + '-' + j);
if (y < this.map.minY || y > this.map.maxY || x < this.map.minX || x > this.map.maxX) {
cell.innerHTML = '&nbsp;';
cell.style.backgroundColor = 'black';
continue;
}
var sys = this.map.map['x' + x + 'y' + y];
if (!sys) {
cell.innerHTML = '&nbsp;';
cell.style.backgroundColor = '#3f3f3f';
} else if (sys.type != 'S') {
cell.innerHTML = '<b>' + sys.type + '</b>';
cell.style.backgroundColor = '#afafaf';
cell.style.color = Grid.nebulaColours[parseInt(sys.type, 10) - 1];
} else if (sys.alloc == 0) {
cell.innerHTML = 'T';
cell.style.backgroundColor = 'black';
cell.style.color = 'white';
} else {
cell.style.color = 'black';
cell.style.backgroundColor = Grid.allianceColours[sys.alloc - 1];
cell.innerHTML = sys.spawn ? 'X' : '&nbsp;';
}
}
}
};
// This function handle clicks on the map
this.handleClick = function(i, j) {
x = this.cX + i - 5;
y = this.cY - j + 5;
if (x >= this.map.minX && x <= this.map.maxX
&& y >= this.map.minY && y <= this.map.maxY && this.onClick) {
this.onClick(x, y);
}
};
};
Grid.allianceColours = [
'ff0000', '00ff00', '0000ff', '007f7f', '7f007f', 'afaf00', 'ffaf3f', '003f7f'
];
Grid.nebulaColours = [
'#ff0000', '#ff2f00', '#ff5f00', '#ff7f00'
];
// Toolbox
Toolbox = function (id, map) {
this.id = id;
this.map = map;
this.currentTool = null;
var drawToolCell = function (id, title, ctxt, cbg, cfg) {
return str = '<tr><td><table style="width:100%;padding:6px;margin:0px" id="tool-' + id
+ '" onClick="Editor.editor.selectTool(\'' + id + '\');"><tr>'
+ '<td style="color:' + cfg + '; background-color: ' + cbg
+ '; text-align:center;width:32px;height:32px">' + ctxt + '</td>'
+ '<td style="text-align:center;font-weight:bold">' + title + '</td>'
+ '</tr></table></td></tr>';
};
this.draw = function () {
var i, str = '<table style="width: 200px; border-style: none">'
+ '<tr><th style="font-size: 120%">Map drawing tools</th></tr>'
+ '<tr><th>Nebulae</th></tr>';
for (i = 1; i < 5; i ++) {
str += drawToolCell('n' + i, 'Class ' + i + ' nebula', '<b>' + i + '</b>',
'#afafaf', Grid.nebulaColours[i - 1]);
}
str += '<tr><th>Misc</th></tr>'
+ drawToolCell('tg', 'Target system', 'T', 'black', 'white')
+ drawToolCell('sp', 'Spawing point', 'X', 'white', 'black')
+ '<tr><th>Alliances</th></tr>';
for (i = 1; i <= this.map.alliances; i ++) {
str += drawToolCell('a' + i, 'Alliance ' + i, '&nbsp;', Grid.allianceColours[i - 1], 'black');
}
str += '</table>';
document.getElementById(this.id).innerHTML = str;
if (this.currentTool) {
this.selectTool(this.currentTool);
}
};
this.selectTool = function(tool) {
if (this.currentTool && document.getElementById('tool-' + this.currentTool)) {
document.getElementById('tool-' + this.currentTool).style.borderStyle = 'none';
}
if (! document.getElementById('tool-' + tool)) {
this.currentTool = null;
return;
}
with (document.getElementById('tool-' + tool).style) {
borderColor = 'red';
borderWidth = '2px';
borderStyle = 'solid';
}
this.currentTool = tool;
};
};
// Validity check / submit button
CheckAndSubmit = function (id, map) {
this.id = id;
this.map = map;
this.error = "---";
var mapCheck = function (map) {
var ax = [];
var tgc = 0;
for (var i = 0; i < map.alliances; i ++) {
ax[i] = [0, 0];
}
for (var i = map.minX; i <= map.maxX; i ++) {
for (var j = map.minY; j <= map.maxY; j ++) {
var m = map.map['x' + i + 'y' + j];
if (! m) {
return 1;
}
if (m.type != 'S') {
continue;
}
if (m.alloc == 0) {
tgc ++;
continue;
}
ax[m.alloc - 1][0] ++;
if (m.spawn) {
ax[m.alloc - 1][1] ++;
}
}
}
if (tgc == 0) {
return 2;
}
var min = -1;
for (var i = 0; i < map.alliances; i ++) {
if (ax[i][0] == 0) {
return 3 + i;
}
if (min == -1) {
min = ax[i][0];
} else if (ax[i][0] < min) {
return 19;
} else if (ax[i][0] > min) {
return 19 + i;
}
}
min = -1;
for (var i = 0; i < map.alliances; i ++) {
if (ax[i][1] == 0) {
return 11 + i;
}
if (min == -1) {
min = ax[i][1];
} else if (ax[i][1] < min) {
return 27;
} else if (ax[i][1] > min) {
return 27 + i;
}
}
return 0;
};
this.draw = function () {
if (this.error == '---') {
this.check();
}
var str;
if (this.error == "") {
str = '<input type="button" value="Save map" onclick="Editor.editor.submit()" />';
} else {
str = '<span style="color:red;font-weight:bold">' + this.error + '</span>';
}
document.getElementById(this.id).innerHTML = str;
};
this.check = function () {
var error = "";
if (map.name.length < 4) {
error = "Name too short";
} else if (map.name.length > 32) {
error = "Name too long";
} else {
var i = mapCheck(this.map);
switch (i) {
case 0: break;
case 1: error = "Map has undefined areas"; break;
case 2: error = "Map has no target areas"; break;
default:
if (i < 11) {
i -= 2;
error = "Alliance " + i + " has no systems.";
} else if (i < 19) {
i -= 10;
error = "Alliance " + i + " has no spawning points.";
} else if (i < 27) {
i -= 18;
error = "Alliance " + i + " has too many systems.";
} else if (i < 35) {
i -= 26;
error = "Alliance " + i + " has too many spawning points.";
}
break;
}
}
if (this.error != error) {
this.error = error;
this.draw();
}
};
};
// Main editor object
Editor = function (initFrom) {
var map = new Map(initFrom);
var components = [];
var cSub = new CheckAndSubmit('check-and-send', map);
var tools = new Toolbox('tools', map);
components.push(tools);
var grid = new Grid('grid', map);
grid.onClick = function(x, y) {
var tool = tools.currentTool;
if (!tool) {
return;
}
if (tool.match(/^n[1-4]$/)) {
map.setNebula(x, y, tool.charAt(1));
} else if (tool == 'tg') {
map.setTarget(x, y);
} else if (tool.match(/^a[1-8]$/)) {
map.setAlliance(x, y, parseInt(tool.charAt(1), 10));
} else if (tool == 'sp') {
map.switchSpawnPoint(x, y);
}
grid.drawMap();
cSub.check();
};
components.push(grid);
var c;
c = new TextInput('name', 'Map name', false, 4, 32, map.name);
c.onChange = function (value) {
map.name = value;
cSub.check();
};
components.push(c);
c = new TextInput('desc', 'Description', true, 0, 0, map.description);
c.onChange = function (value) {
map.description = value;
};
components.push(c);
c = new NumericControl('n-alliances', 'Alliances', 2, 8, map.alliances);
c.onChange = function (value) {
var old = map.alliances;
map.alliances = value;
tools.draw();
if (value < old) {
map.removeExtraAlliances();
grid.drawMap();
}
cSub.check();
};
components.push(c);
c = new NumericControl('m-width', 'Map width', 3, 41, map.width);
c.onChange = function (value) {
map.width = value;
map.updateCoordinates();
grid.drawMap();
cSub.check();
};
components.push(c);
c = new NumericControl('m-height', 'Map height', 3, 41, map.height);
c.onChange = function (value) {
map.height = value;
map.updateCoordinates();
grid.drawMap();
cSub.check();
};
components.push(c);
components.push(cSub);
this.draw = function () {
var str = '<h3>Parameters</h3>'
+ '<table style="width: 100%; border-style: none; margin: 0px; padding: 0px">'
+ '<tr><td colspan="3" id="name">&nbsp;</td></tr>'
+ '<tr><td colspan="3" id="desc">&nbsp;</td></tr>'
+ '<tr><td style="width: 33%" id="n-alliances">&nbsp;</td>'
+ '<td style="width: 34%" id="m-width">&nbsp;</td>'
+ '<td style="width: 33%" id="m-height">&nbsp;</td></tr>'
+ '<tr><td colspan="3" id="check-and-send" style="text-align:center">&nbsp;</td></tr>'
+ '</table>'
+ '<h3>Map</h3>'
+ '<div><div id="tools" style="float:right">&nbsp;</div><div id="grid">&nbsp;</div></div>';
document.getElementById('mapedit').innerHTML = str;
for (var i in components) {
components[i].draw();
}
};
this.scroll = function (dx, dy) {
grid.cX += dx; grid.cY += dy;
grid.drawMap();
};
this.mapClick = function(x,y) {
grid.handleClick(x, y);
};
this.selectTool = function(tool) {
tools.selectTool(tool);
};
this.submit = function () {
document.getElementById('sf-name').value = map.name;
document.getElementById('sf-desc').value = map.description;
document.getElementById('sf-width').value = map.width;
document.getElementById('sf-height').value = map.height;
document.getElementById('sf-alliances').value = map.alliances;
var ma = [];
for (var j = map.minY; j <= map.maxY; j ++) {
var str = '';
for (var i = map.minX; i <= map.maxX; i ++) {
var m = map.map['x' + i + 'y' + j];
str += m.type;
if (m.type != 'S') {
continue;
}
str += m.alloc;
if (m.alloc == 0) {
continue;
}
str += m.spawn ? '1' : '0';
}
ma.push(str);
}
document.getElementById('sf-map').value = ma.join('#');
document.getElementById('sendform').submit();
};
};
Editor.editor = new Editor(initMap);
Editor.editor.draw();

189
admin/maps.php Normal file
View file

@ -0,0 +1,189 @@
<?php
include('config.inc');
include('ctf_map.inc');
session_start();
function handleInput() {
if ($_GET['c'] == 'n') {
$op = 'e';
$_SESSION['edit_map'] = new ctf_map();
} elseif ($_GET['c'] == 'e') {
$op = 'e';
$_SESSION['edit_map'] = new ctf_map($_GET['id']);
} elseif ($_GET['c'] == 'd') {
if ($_GET['ok']) {
$map = new ctf_map($_GET['id']);
$map->destroy();
$op = '';
} else if ($_GET['cancel']) {
$op = "";
} else {
$op = 'd';
}
} elseif ($_POST['c'] == 'ms' && $_SESSION['edit_map'] instanceof ctf_map) {
$map = $_SESSION['edit_map'];
$map->setName(stripslashes($_POST['name']));
$map->setDescription(stripslashes($_POST['desc']));
$map->setWidth((int) $_POST['width']);
$map->setHeight((int) $_POST['height']);
$map->setAlliances((int) $_POST['alliances']);
$minY = -floor($map->getHeight() / 2); $maxY = $minY + $map->getHeight() - 1;
$minX = -floor($map->getWidth() / 2); $maxX = $minX + $map->getWidth() - 1;
$layout = explode('#', $_POST['map']);
for ($y = $minY; $y <= $maxY; $y ++) {
$str = array_shift($layout);
for ($x = $minX; $x <= $maxX; $x ++) {
$type = $str{0};
$map->setSystemType($x, $y, $type);
if ($type != 'S') {
$str = substr($str, 1);
continue;
}
$alloc = (int) $str{1};
$map->setSystemAlloc($x, $y, $alloc);
if ($alloc == 0) {
$str = substr($str, 2);
continue;
}
$map->setSystemSpawn($x, $y, $str{2} == '1');
$str = substr($str, 3);
}
}
$map->save();
$_SESSION['edit_map'] = null;
$op = '';
} else {
$op = '';
}
return $op;
}
function listMaps() {
?>
<h2>Available maps</h2>
<?php
$maps = ctf_map::allMaps();
if (count($maps) == 0) {
?>
<p>
There are no maps on the server at this time.
</p>
<?php
} else {
?>
<table border="1">
<tr>
<th align="left">Name &amp; description</th>
<th align="center">Size</th>
<th align="center">Alliances</th>
<th align="left">&nbsp;</th>
</tr>
<?php
foreach ($maps as $map) {
?>
<tr>
<td style='vertical-align:top'><?="<u>" . htmlentities($map->getName()) . "</u>"
. (is_null($map->getDescription()) ? "" : ("<br/>" . htmlentities($map->getDescription())))?></td>
<td style='text-align:center'><?=$map->getWidth()?>x<?=$map->getHeight()?></td>
<td style='text-align:center'><?=$map->getAlliances()?></td>
<td><a href="?c=e&id=<?=$map->getID()?>">Edit</a> - <a href="?c=d&id=<?=$map->getID()?>">Delete</a></td>
</tr>
<?php
}
?>
</table>
<?
}
?>
<p>
<a href='?c=n'>Create a map</a>
</p>
<?php
}
function editMap() {
?>
<h2>Map editor</h2>
<form method="POST" action="?" onSubmit="return false;">
<div id="mapedit"><p>Loading, please wait ...</p></div>
</form>
<form method="POST" action="?" id="sendform" style="display: none">
<input type="hidden" name="c" value="ms" />
<input type="hidden" id="sf-name" name="name" value="" />
<input type="hidden" id="sf-desc" name="desc" value="" />
<input type="hidden" id="sf-width" name="width" value="" />
<input type="hidden" id="sf-height" name="height" value="" />
<input type="hidden" id="sf-alliances" name="alliances" value="" />
<input type="hidden" id="sf-map" name="map" value="" />
</form>
<script language="JavaScript"><!--
var initMap = {
name: '<?=addslashes($_SESSION['edit_map']->getName())?>',
description: '<?=preg_replace(array('/\\n/', '/\\r/'), array('\\n', '\\r'), addslashes($_SESSION['edit_map']->getDescription()))?>',
alliances: <?=$_SESSION['edit_map']->getAlliances()?>,
width: <?=$_SESSION['edit_map']->getWidth()?>,
height: <?=$_SESSION['edit_map']->getHeight()?>,
map: [ <?=$_SESSION['edit_map']->jsDump()?> ]
};
//--></script>
<script language="JavaScript" src="map_edit.js"></script>
<?
}
function confirmDelete() {
$map = new ctf_map((int)$_GET['id']);
?>
<h2>Map deletion</h2>
<p>
You are about to delete the map called <b><?=htmlentities($map->getName())?></b>.<br/>
Please confirm.
</p>
<form method="GET" action="?">
<input type="hidden" name="c" value="d" />
<input type="hidden" name="id" value="<?=$map->getID()?>" />
<input type="submit" name="ok" value="Confirm" />
<input type="submit" name="cancel" value="Cancel" />
</form>
<?
}
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Maps management</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Maps management</h1>
<p>
The purpose of this tool is to create new maps, edit existing ones or delete unused ones.
</p>
<?php
$h = handleInput();
switch($h) :
case 'e':
editMap();
break;
case 'd':
confirmDelete();
break;
default:
listMaps();
break;
endswitch;
?>
</body>
</html>

128
admin/proxy.php Normal file
View file

@ -0,0 +1,128 @@
<?php
set_magic_quotes_runtime(false);
include('config.inc');
include('../scripts/config.inc');
include('as_manager.inc');
include('as_log.inc');
function redirect() {
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Proxy detector</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Proxy detector</h1>
<h2>Operation in progress...</h2>
<p>
A system operation is in progress. Please wait, the page will update in 5 seconds.
</p>
<script language="JavaScript">
window.setTimeout('window.location="proxy.php"', 5000);
</script>
</body>
</html>
<?php
exit(0);
}
function startDetector() {
__logAdmin("is starting the proxy detector");
__sendControl("PCON");
redirect();
}
function stopDetector() {
__logAdmin("is stopping the proxy detector");
__sendControl("PCOFF");
redirect();
}
$oldDir = getcwd();
chdir("../scripts");
$__loader = array(
'log', 'classloader',
'version', 'game', 'tick',
'config', 'pcheck'
);
require_once("loader.inc");
chdir($oldDir);
$isRunning = pcheck::isRunning();
if ($_GET['c'] == 'sd') {
startDetector();
} elseif ($_GET['c'] == 'kd') {
stopDetector();
} elseif ($_GET['ip'] != '') {
$ip = $_GET['ip'];
$status = "";
if (preg_match('/^\d{1,3}(\.\d{1,3}){3}$/', $ip)) {
if ($ip == "127.0.0.1") {
$status = "Host not allowed";
} else {
$addr = explode('.', $ip);
foreach ($addr as $piece) {
if ($piece > 254) {
$status = "Invalid IP address";
break;
}
}
if ($status == "") {
try {
$result = pcheck::check(array($ip));
$status = "$ip - ";
switch ($result[$ip]) {
case -1: $status .= "detection failed"; break;
case 0: $status .= "no proxy detected"; break;
case 1: $status .= "OPEN PROXY DETECTED!"; break;
}
} catch (Exception $e) {
$status = $e->getMessage();
}
}
}
} else {
$status = "Invalid IP address";
}
} else {
$status = $ip = "";
}
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Proxy detector</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Proxy detector</h1>
<?php
if ($isRunning) {
?>
<p>
Proxy detector is <b>running</b>; process ID #<?=$isRunning?>. <a href="?c=kd">Stop detector</a>
</p>
<form action="?" method="GET">
<p>
Manually check address <input type="text" size="16" maxlength="15" name="ip" value="<?=htmlentities($ip, ENT_QUOTES)?>" />
<input type="submit" value="Scan" />
<?=($status != '') ? ('<br/><b>' . $status . '</b>') : ''?>
</p>
</form>
<?php
} else {
?>
<p>
Proxy detector is <b>not running</b>. <a href="?c=sd">Start detector</a>
</p>
<?php
}
?>
</body>
</html>

104
admin/set_default.php Normal file
View file

@ -0,0 +1,104 @@
<?php
set_magic_quotes_runtime(false);
include('config.inc');
include('as_log.inc');
function redirect() {
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Default game</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Default game</h1>
<h2>Operation in progress...</h2>
<p>
A system operation is in progress. Please wait, the page will update in 2 seconds.
</p>
<script language="JavaScript">
window.setTimeout('window.location="set_default.php"', 2000);
</script>
</body>
</html>
<?php
exit(0);
}
function sendFifo($command) {
global $aConfig;
$fName = $aConfig['ctrlFifo'];
if (!file_exists($fName)) {
return false;
}
$fifo = fopen($fName, "w");
fwrite($fifo, "$command\n");
fclose($fifo);
}
// Load the list of games
$oldDir = getcwd();
chdir("../scripts");
$__logPrefix = "lwControl";
$__loader = array(
'log', 'classloader',
'version', 'game', 'tick', 'config',
'db_connection', 'db_accessor', 'db',
'library'
);
require_once("loader.inc");
chdir($oldDir);
dbConnect();
if ($_GET['d'] != '') {
$cDef = config::getDefaultGame();
$games = config::getGames();
if ($cDef->name != $_GET['d'] && array_key_exists($_GET['d'], $games) && $_GET['d'] != 'main') {
sendFifo("SETDEF {$_GET['d']}");
redirect();
}
}
$games = config::getGames();
$defGame = config::getDefaultGame();
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Default game</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Default game</h1>
<p>
The <b>default game</b> is the game for which overall round rankings are displayed on the site's
main page.
</p>
<form action="?" method="GET">
<p>
Current default game:
<select name="d">
<?php
foreach ($games as $id => $game) {
if ($id == "main" || $game->status() == 'PRE') {
continue;
}
print " <option value='$id'";
if ($defGame->name == $id) {
echo " selected='selected'";
}
echo ">" . htmlentities($game->text) . "</option>\n";
}
?>
</select>
<input type="submit" value="Change" />
</p>
</form>
</body>
</html>

221
admin/ticks.php Normal file
View file

@ -0,0 +1,221 @@
<?php
set_magic_quotes_runtime(false);
include('config.inc');
include('../scripts/config.inc');
include('as_manager.inc');
include('as_log.inc');
function redirect() {
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Ticks</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Ticks</h1>
<h2>Operation in progress...</h2>
<p>
A system operation is in progress. Please wait, the page will update in 5 seconds.
</p>
<script language="JavaScript">
window.setTimeout('window.location="ticks.php"', 5000);
</script>
</body>
</html>
<?php
exit(0);
}
function ticksActive() {
global $config;
$stopped = $config['cachedir'] . '/ticks_stopped';
$stop = $config['cachedir'] . '/stop_ticks';
$start = $config['cachedir'] . '/start_ticks';
return (file_exists($start) || file_exists($stop)) ? 'pending' : !file_exists($stopped);
}
function startManager() {
global $aConfig;
__logAdmin("is starting the ticks manager");
$fName = $aConfig['ctrlFifo'];
if (!file_exists($fName)) {
return false;
}
$fifo = fopen($fName, "w");
fwrite($fifo, "TMINIT\n");
fclose($fifo);
redirect();
}
function killManager() {
global $aConfig;
__logAdmin("is stopping the ticks manager");
$fName = $aConfig['ctrlFifo'];
if (!file_exists($fName)) {
return false;
}
$fifo = fopen($fName, "w");
fwrite($fifo, "TMSTOP\n");
fclose($fifo);
redirect();
}
function enableTicks() {
global $config;
touch($config['cachedir'] . "/start_ticks");
__logAdmin("is enabling the ticks");
}
function disableTicks() {
global $config;
touch($config['cachedir'] . "/stop_ticks");
__logAdmin("is disabling the ticks");
}
$statusMessage = "";
// Start / stop manager
if ($_GET['c'] == 'sm') {
startManager();
} elseif ($_GET['c'] == 'km') {
killManager();
} else {
$mRunning = __isManagerRunning();
$tActive = ($mRunning !== false) ? ticksActive() : false;
// Run tick manually
if ($_GET['c'] == 'rt' && $_GET['g'] != '' && $_GET['t'] != '') {
$__runFromAdmin = true;
$__adminParams = array($_GET['g'], $_GET['t']);
__logAdmin("is running tick " . join("::", $__adminParams));
include("../scripts/ticks.php");
$statusMessage = is_null($argh)
? ("Tick <b>" . join("::", $__adminParams) . "</b> run successfully")
: ("<b>Error while running tick " . join("::", $__adminParams) . ":</b><br/>$argh");
} else {
// Enable / disable ticks
if ($tActive === true && $_GET['c'] == 'dt') {
disableTicks();
$tActive = 'pending';
} elseif ($mRunning !== false && $tActive === false && $_GET['c'] == 'et') {
enableTicks();
$tActive = 'pending';
}
}
}
// Load the list of games if no ticks were run
if (!class_exists('config')) {
$oldDir = getcwd();
chdir("../scripts");
$__logPrefix = "lwControl";
$__loader = array(
'log', 'classloader',
'version', 'game', 'tick', 'config'
);
require_once("loader.inc");
chdir($oldDir);
}
?>
<html>
<head>
<title>LegacyWorlds Beta 5 > Administration > Ticks</title>
</head>
<body>
<h1><a href="index.html">LWB5 > Administration</a> > Ticks</h1>
<h2>Manager status</h2>
<p>Tick manager status: <?
if ($mRunning === false) {
?>
<b>not running</b> - <a href="?c=sm">Start manager</a>
<?
} else {
?> <b>running</b>, process ID #<?=$mRunning?> - <a href="?c=km">Kill manager</a><br/>
<?
if ($tActive === 'pending') {
?> Ticks status change pending; please <a href="?">reload</a> the page.<br/>
This can take up to 20 seconds, be patient.
<?
} elseif ($tActive) {
?> Ticks are <b>active</b> - <a href="?c=dt">Disable ticks</a>
<?
} else {
?> Ticks are <b>inactive</b> - <a href="?c=et">Enable ticks</a>
<?
}
}
?>
</p>
<h2>Manual controls</h2>
<?php
if ($statusMessage != '') {
echo " <p>$statusMessage</p>\n";
}
?>
<form action="?" method="GET">
<input type="hidden" name="c" value="rt" />
<input type="hidden" name="g" value="main" />
<p>
Engine tick:
<select name="t">
<option value="">-- select --</option>
<option value="day">day</option>
<option value="deathofrats">deathofrats</option>
<option value="vacation">vacation</option>
<option value="session">session</option>
</select>
<input type="submit" value="Run" />
</p>
</form>
<form action="?" method="GET">
<input type="hidden" name="c" value="rt" />
<p>
Tick
<select name="t">
<option value="">-- select --</option>
<option>battle</option>
<option>cash</option>
<option>day</option>
<option>hour</option>
<option>move</option>
<option>quit</option>
<option>sales</option>
<option>universe</option>
<option>punishment</option>
</select>
for game
<select name="g">
<option value="">-- select --</option>
<?
$games = config::getGames();
foreach (array_keys($games) as $game) {
if ($game == 'main') {
continue;
}
print " <option>$game</option>\n";
}
?>
</select>
<input type="submit" value="Run" />
</p>
</form>
</body>
</html>

147
ircbot/bot.conf Normal file
View file

@ -0,0 +1,147 @@
;+---------------------------------------------------------------------------
;| PHP-IRC v2.2.1 Service Release
;| =======================================================
;| by Manick
;| (c) 2001-2006 by http://www.phpbots.org/
;| Contact: manick@manekian.com
;| irc: #manekian@irc.rizon.net
;| ========================================
;| Special Contributions were made by:
;| cortex
;+---------------------------------------------------------------------------
;| > Configuration File
;+---------------------------------------------------------------------------
;| > 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.
;+---------------------------------------------------------------------------
;| Changes
;| =======-------
;| > If you wish to suggest or submit an update/change to the source
;| > code, email me at manick@manekian.com with the change, and I
;| > will look to adding it in as soon as I can.
;+---------------------------------------------------------------------------
;====Bot config file
;====Contains the nickname of the Bot
nick LW-Bot
;====The nickserv password, if any (autoident)..
password ...
;====Real name..
realname Legacy Worlds Bot
;====The server you are going to connect to
server localhost
;====The server port
port 6667
;====The server password you are going to connect to
;serverpassword test
;====NAT IP
;natip 192.168.1.101
;===BIND IP
;Specify the IP this bot should bind to when connecting to a server
;bind 127.0.0.1
;====DCC Range start for chats/files
;dccrangestart 6081
;====DCC Reverse Protocl
;This follows the mIRC DCC Server Protocol
;When this is set, you will connect to this port
;on the users machine, and send them the file, similar to
;sysreset's firewall workaround.
;This function is EXPERIMENTAL
;====
;mircdccreverse 4000
;====Who on join?
;After joining a channel, populate the host lists
;with /WHO information? This probably isn't so good
;for larger channels...
;This function populates host/ident information for
;all users in a channel. Useful for running channel protection
;scripts and such. The DCC Reverse setting above using a WHOIS
;command to get user hosts, so this doesn't have to be set
;to use the above setting.
;====
;populatewho
;====Populate ban list?
;This will make php-irc run MODE #chan +b upon joining, populating
;the ban list. This is useful for running channel protection or ban
;rotating scripts.
;====
;populatebans
;====Flood lines
;when someone types text that is a trigger for the bot, how many times can they type
;different triggers (within a 10 second period) before the bot ignores them for spamming the bot
floodlines 500
;====Time to ban user in seconds for abusing the bots triggers
floodtime 60
;====Channels.. unlimited
;====i.e., channel #channel key
;====but you don't have to specify a key
channel #testing meeeh
;====Your ident
ident lwbot
;====Log file
logfile __CFG:cachedir__/ircbot.log
;====uncomment the following lines to use a database
;either 'usedatabase mysql' or 'usedatabase postgre'
;usedatabase mysql
;dbuser root
;dbpass none
;db question
;dbprefix bot_
;dbhost localhost
;dbport
;====Send queue timeout
;How often to send more text to the irc server. This handles the 'notice'
;and 'privMsg' commands sent from modules and such (in seconds)
queuetimeout 1
;====Send queue buffer
;How many bytes of text to send to the server every 'queuetimeout' period.
queuebuffer 225
;====Perm. Ignore (These hosts will always be ignored, forever)
;example:
;ignore *!*@*
;====DCC Admin password //default is 'mypass'
;dccadminpass a029d0df84eb5549c641e04a9ef389e5
;====set this to your function file
functionfile function.conf
;====whether this bot accepts sends from other people
upload no
;====The place where uploaded files are put.
;uploaddir /home/my/dir/

476
ircbot/bot.php Normal file
View file

@ -0,0 +1,476 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > Main module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
error_reporting(E_ALL);
set_time_limit(0);
$oldDir = getcwd();
chdir("../scripts");
$__logPrefix = "lwBot";
$__loader = array(
'log', 'classloader', 'version', 'game', 'tick', 'config',
'db_connection', 'db_accessor', 'db', 'library'
);
require_once('loader.inc');
chdir($oldDir);
require('./defines.php');
require('./queue.php');
require('./module.php');
require('./irc.php');
require('./socket.php');
require('./timers.php');
require('./dcc.php');
require('./chat.php');
require('./file.php');
require('./parser.php');
require('./databases/ini.php');
require('./error.php');
require('./connection.php');
require('./remote.php');
final class bot {
/* Global socket class used by all bots */
private $socketClass;
/* Global process Queue used by all bots, timers, dcc classes */
private $procQueue;
/* Whether we are running in background mode or not. (not sure if this is used anymore */
private $background = 0;
//contain all the bots
private $bots = array();
// save the only one instance of bot (singleton)
private static $_instance;
public static function getInstance()
{
if (!isset (self :: $_instance))
{
self :: $_instance = new bot();
}
return self :: $_instance;
}
//Main Method
private function __construct()
{
$this->socketClass = new socket();
$this->procQueue = new processQueue();
$this->socketClass->setProcQueue($this->procQueue);
$this->readConfig();
}
public function launch(){
foreach($this->bots as $bot)
{
$this->createBot($bot);
}
try
{
/* Main program loop */
while (1)
{
//Get data from sockets, and trigger procQueue's for new data to be read
$this->socketClass->handle();
//The bots main process loop. Run everything we need to!
$timeout = $this->procQueue->handle();
//Okay, set the socketclass timeout based on the next applicable process
if ($timeout !== true)
{
$this->socketClass->setTimeout($timeout);
}
//echo $this->procQueue->getNumQueued() . "\n";
//$this->procQueue->displayQueue();
//Aight, if we don't have any sockets open/in use, and
//we have no processes in the process queue, then there are
//obviously no bots running, so just exit!
if ($this->socketClass->getNumSockets() == 0 && $this->procQueue->getNumQueued() == 0)
{
break;
}
}
}
catch (Exception $e)
{
$this->ircClass->log($e->_toString());
}
}
public static function addBot($filename){
$bot = bot::getInstance();
$config = bot::parseConfig($filename);
if ($config == false)
{
return false;
}
$newBot = new botClass();
$newBot->config = $config;
$newBot->configFilename = $filename;
$bot->bots[] = $newBot;
$bot->createBot($newBot);
return true;
}
private function createBot($bot)
{
$this->connectToDatabase($bot);
$bot->socketClass = $this->socketClass;
$bot->timerClass = new timers();
$bot->parserClass = new parser();
$bot->dccClass = new dcc();
$bot->ircClass = new irc();
$bot->ircClass->setConfig($bot->config, $bot->configFilename);
$bot->ircClass->setSocketClass($this->socketClass);
$bot->ircClass->setParserClass($bot->parserClass);
$bot->ircClass->setDccClass($bot->dccClass);
$bot->ircClass->setTimerClass($bot->timerClass);
$bot->ircClass->setProcQueue($this->procQueue);
$bot->dccClass->setSocketClass($this->socketClass);
$bot->dccClass->setTimerClass($bot->timerClass);
$bot->dccClass->setParserClass($bot->parserClass);
$bot->dccClass->setProcQueue($this->procQueue);
$bot->parserClass->setTimerClass($bot->timerClass);
$bot->parserClass->setSocketClass($this->socketClass);
$bot->parserClass->setDatabase($bot->db);
$bot->timerClass->setIrcClass($bot->ircClass);
$bot->timerClass->setSocketClass($this->socketClass);
$bot->timerClass->setProcQueue($this->procQueue);
$bot->parserClass->init();
//Okay, this function adds the connect timer and starts up this bot class.
$bot->ircClass->init();
bot::createChannelArray($bot->ircClass);
}
private function readConfig()
{
global $argc, $argv;
if ($argc < 2) {
$args = array(config::$main['scriptdir'] . "/../ircbot/bot.conf");
} else {
$args = $argv;
array_shift($args);
}
$isPasswordEncrypt = false;
foreach ($args AS $filename)
{
if ($filename == "")
{
continue;
}
if ($isPasswordEncrypt == true)
{
die("Encrypted Password: " . md5($filename) . "\nReplace this as 'dccadminpass' in bot.conf!");
}
if ($filename == "-c")
{
$isPasswordEncrypt = true;
continue;
}
if ($filename == "-b" && $this->background != 1)
{
$this->background = 1;
$this->doBackground();
continue;
}
$config = bot::parseConfig($filename);
if ($config == false)
{
echo "Could not spawn bot $filename";
die();
}
$bot = new botClass();
$bot->config = $config;
$bot->configFilename = $filename;
$this->bots[] = $bot;
}
if ($isPasswordEncrypt == true) {
die("No password submitted on command line! Syntax: bot.php -c <new admin password>\n");
}
if (! $this->background && PID != '') {
$file = fopen(PID, "w+");
fwrite($file, getmypid());
fclose($file);
}
}
private function connectToDatabase($bot)
{
if (isset($bot->config['usedatabase']))
{
if (!file_exists("./databases/" . $bot->config['usedatabase']. ".php"))
{
die("Couldn't find the database file! Make sure it exists!");
}
require_once("./databases/" . $bot->config['usedatabase']. ".php");
$dbType = $bot->config['usedatabase'];
if (!isset($bot->config['dbhost']))
$bot->config['dbhost'] = "localhost";
if (!isset($bot->config['dbuser']))
$bot->config['dbuser'] = "root";
if (!isset($bot->config['dbpass']))
$bot->config['dbpass'] = "";
if (!isset($bot->config['db']))
$bot->config['db'] = "test";
if (!isset($bot->config['dbprefix']))
$bot->config['dbprefix'] = "";
if (!isset($bot->config['dbport']))
{
$bot->db = new $dbType($bot->config['dbhost'],
$bot->config['db'],
$bot->config['dbuser'],
$bot->config['dbpass'],
$bot->config['dbprefix']);
}
else
{
$bot->db = new $dbType($bot->config['dbhost'],
$bot->config['db'],
$bot->config['dbuser'],
$bot->config['dbpass'],
$bot->config['dbprefix'],
$bot->config['dbport']);
}
if (!$bot->db->isConnected())
{
die("Couldn't connect to database...");
}
}
}
public static function createChannelArray($ircClass)
{
$channels = $ircClass->getClientConf('channel');
if ($channels != "")
{
if (!is_array($channels))
{
$channels = array($channels);
}
foreach ($channels AS $channel)
{
$chan = $channel;
$key = "";
if (strpos($channel, chr(32)) !== false)
{
$channelVars = explode(chr(32), $channel);
$chan = $channelVars[0];
$key = $channelVars[1];
}
$ircClass->maintainChannel($chan, $key);
}
}
}
public static function parseConfig($filename)
{
$configFPtr = @fopen($filename, "rt");
if ($configFPtr == null)
{
// echo "Could not find config file '".$filename."'\n";
return false;
}
$configRaw = "";
try
{
while (!feof($configFPtr))
{
$configRaw .= fgets($configFPtr, 1024);
}
fclose($configFPtr);
}
catch (Exception $e)
{
// echo "A fatal IO Exception occured.";
return false;
}
$config = array();
$configRaw = str_replace("\r", "", $configRaw);
$confLines = explode("\n", $configRaw);
foreach ($confLines AS $line)
{
$line = trim($line);
if ($line == "" || substr($line, 0, 1) == ";")
{
continue;
}
$offsetA = strpos($line, chr(32));
if ($offsetA != false)
{
$confVar = substr($line, 0, $offsetA);
$confParams = substr($line, $offsetA + 1);
}
else
{
$confVar = $line;
$confParams = "";
}
if (preg_match('/__CFG:([a-zA-Z_]+)__/', $confParams, $matches)) {
$src = array(); $dst = array();
array_shift($matches);
foreach ($matches as $cfgSubst) {
array_push($src, "/__CFG:{$cfgSubst}__/");
array_push($dst, config::$main[$cfgSubst]);
}
$confParams = preg_replace($src, $dst, $confParams);
}
if (isset($config[$confVar]))
{
if (!is_array($config[$confVar]))
{
$prevParam = $config[$confVar];
$config[$confVar] = array();
$config[$confVar][] = $prevParam;
}
$config[$confVar][] = $confParams;
}
else
{
$config[$confVar] = $confParams;
}
}
return $config;
}
private function doBackground()
{
$pid = pcntl_fork();
if ($pid == -1) {
die("Error: could not fork\n");
} else if ($pid) {
if (PID != "") {
$file = fopen(PID, "w+");
fwrite($file, $pid);
fclose($file);
}
exit(); // Parent
}
if (!posix_setsid()) {
die("Error: Could not detach from terminal\n");
}
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
}
}
$ircBot = bot::getInstance();
$ircBot->launch();
?>

364
ircbot/chat.php Normal file
View file

@ -0,0 +1,364 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2004 by http://www.phpbots.org/
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > dcc chat module
| > Module written by Manick
| > Module Version Number: 2.2.1 beta
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class chat {
/* Chat specific Data */
public $id;
public $status;
public $sockInt;
public $isAdmin;
public $timeConnected;
public $verified;
public $readQueue;
public $floodQueue;
public $floodQueueTime;
public $port;
public $type;
public $nick;
public $timeOutLevel;
public $removed;
public $connection;
public $handShakeSent;
public $handShakeTime;
public $reverse;
public $connectHost;
/* Classes */
private $dccClass;
private $parserClass;
private $ircClass;
private $socketClass;
private $timerClass;
//class handler
private $handler;
/* Constructor */
public function __construct($id, $nick, $admin, $sockInt, $host, $port, $handler, $reverse)
{
$this->id = $id;
$this->handler = $handler;
$this->nick = $nick;
$this->isAdmin = $admin;
$this->sockInt = $sockInt;
$this->port = $port;
$this->connectHost = $host;
$this->reverse = $reverse;
$this->handShakeSent = false;
$this->sendQueue = array();
$this->sendQueueCount = 0;
}
public function setIrcClass($class)
{
$this->ircClass = $class;
}
public function setDccClass($class)
{
$this->dccClass = $class;
}
public function setSocketClass($class)
{
$this->socketClass = $class;
}
public function setParserClass($class)
{
$this->parserClass = $class;
}
public function setTimerClass($class)
{
$this->timerClass = $class;
}
private function sendUserGreeting()
{
if ($this->verified == true)
{
return;
}
$this->dccSend("Welcome to " . $this->ircClass->getNick());
$this->dccSend("PHP-iRC v". VERSION ." [". VERSION_DATE ."]");
$time = $this->ircClass->timeFormat($this->ircClass->getRunTime(), "%d days, %h hrs, %m min, %s sec");
$this->dccSend("running " . $time);
$this->dccSend("You are currently in the dcc chat interface. Type 'help' to begin.");
}
private function sendAdminGreeting()
{
if ($this->verified == true)
{
return;
}
$this->dccSend("Welcome to " . $this->ircClass->getNick());
$this->dccSend("PHP-iRC v". VERSION ." [". VERSION_DATE ."]");
$time = $this->ircClass->timeFormat($this->ircClass->getRunTime(), "%d days, %h hrs, %m min, %s sec");
$this->dccSend("running " . $time);
$this->dccSend("Enter Your Password:");
}
public function dccSend($data, $to = null)
{
if ($this->status != DCC_CONNECTED)
{
return;
}
if ($to == null)
{
$to = $this;
}
$this->dccClass->dccSend($to, "--> " . $data . "\n");
}
public function dccSendRaw($data, $to = null)
{
if ($this->status != DCC_CONNECTED)
{
return;
}
if ($to == null)
{
$to = $this;
}
$this->dccClass->dccSend($to, $data);
}
public function disconnect($msg = "")
{
$msg = str_replace("\r", "", $msg);
$msg = str_replace("\n", "", $msg);
if (is_object($this->handler) && $this->status == DCC_CONNECTED)
{
$this->handler->disconnected($this);
}
$this->status = false;
if ($msg != "")
{
$this->dccClass->dccInform("DCC: " . $this->nick . " closed DCC Chat (" . $msg . ")", $this);
$this->ircClass->notice($this->nick, "DCC session ended: " . $msg, 1);
}
else
{
$this->dccClass->dccInform("DCC: " . $this->nick . " closed DCC Chat", $this);
}
$this->dccClass->disconnect($this);
$this->connection = null;
return true;
}
private function doHandShake()
{
$this->dccSendRaw("100 ".$this->ircClass->getNick()."\n");
$this->handShakeSent = true;
$this->timerClass->addTimer(irc::randomHash(), $this, "handShakeTimeout", "", 8);
}
private function processHandShake()
{
if ($this->readQueue == "")
{
return;
}
$response = $this->readQueue;
$this->readQueue = "";
$responseArray = explode(chr(32), $response);
if ($responseArray[0] == "101")
{
$this->reverse = false;
$this->onConnect($this->connection);
return;
}
$this->disconnect("DCC Client Server reported error on attempt to start chat");
}
public function handShakeTimeout()
{
if ($this->status != false)
{
if ($this->reverse == true)
{
$this->disconnect("DCC Reverse handshake timed out");
}
}
return false;
}
/* Main events */
public function onTimeout($conn)
{
$this->disconnect("Connection transfer timed out");
}
public function onDead($conn)
{
$this->disconnect($this->connection->getErrorMsg());
}
public function onRead($conn)
{
if ($this->socketClass->hasLine($this->sockInt))
{
$this->readQueue .= $this->socketClass->getQueueLine($this->sockInt);
}
if ($this->status == DCC_CONNECTED)
{
if ($this->reverse != false)
{
if ($this->handShakeSent != false)
{
$this->processHandShake();
}
}
else
{
if ($this->readQueue != "")
{
$this->parserClass->parseDcc($this, $this->handler);
}
}
}
if ($this->socketClass->hasLine($this->sockInt))
{
return true;
}
}
public function onWrite($conn)
{
//do nothing
}
public function onAccept($oldConn, $newConn)
{
$this->dccClass->accepted($oldConn, $newConn);
$this->connection = $newConn;
$oldConn->disconnect();
$this->sockInt = $newConn->getSockInt();
$this->onConnect($newConn);
}
public function onConnectTimeout($conn)
{
$this->disconnect("Connection attempt timed out");
}
public function onConnect($conn)
{
$this->status = DCC_CONNECTED;
if ($this->reverse != false)
{
$this->dccClass->dccInform("DCC CHAT: " . $this->nick . " handling dcc server request");
$this->doHandShake();
return;
}
$this->dccClass->dccInform("DCC CHAT: " . $this->nick . " connection established");
if ($this->handler === false || $this->handler == null)
{
if ($this->isAdmin == true)
{
$this->sendAdminGreeting();
}
else
{
$this->sendUserGreeting();
}
}
else
{
if (is_object($this->handler))
{
$this->handler->connected($this);
}
}
}
public function initialize()
{
$this->dccClass->dccInform("DCC: " . $this->nick . " is attempting to login");
if ($this->status == DCC_LISTENING)
{
$this->ircClass->privMsg($this->nick, "\1DCC CHAT chat " . $this->ircClass->getClientIP(1) . " " . $this->port . "\1", 0);
$this->ircClass->notice($this->nick, "DCC Chat (" . $this->ircClass->getClientIP(0) . ")", 0);
}
$this->timeConnected = time();
$this->timeOutLevel = 0;
$this->verified = 0;
$this->readQueue = "";
$this->floodQueue = "";
$this->floodQueueTime = 0;
$this->type = CHAT;
}
}
?>

View file

@ -0,0 +1,870 @@
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2006 by http://www.phpbots.org/
| Contact: manick@manekian.net
| irc: #manekian@irc.rizon.net
| ========================================================
+---------------------------------------------------------------------------
| > Module Command Reference
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
The following file is a quickly put together command reference of all the functions that you can use to complement the php scripting language while writing your modules.
===============
Quick Reference (See below the quick reference for function descriptions)
===============
irc.php (Accessed with $this->ircClass->)
-----------------------------------------
array parseModes($modeString)
array getMaintainedChannels()
string getClientConf($var = "")
string getNick()
string getServerConf($var)
string getStatusString($status)
string getClientIP($long = 1)
class getChannelData($channel)
class getUserData($user, $channel = "")
void disconnect()
void setClientConfigVar($var, $value)
void joinChannel($chan)
void sendRaw($text, $force = false)
void privMsg($who, $msg, $queue = 1)
void action($who, $msg, $queue = 1)
void notice($who, $msg, $queue = 1)
void log($text)
void maintainChannel($channel, $key = "")
void removeMaintain($channel)
void addQuery($host, $port, $query, $line, $class, $function)
int getStatusRaw()
bool changeMode($chan, $act, $mode, $user)
bool isOnline($nick, $chan)
bool isMode($nick, $channel, $mode)
bool isChanMode($channel, $mode, $extra = "")
bool hasModeSet($chan, $user, $modes);
bool hostMasksMatch($mask1, $mask2)
bool checkIgnore($mask)
socket.php (Accessed with $this->socketClass->)
-----------------------------------------------
string getHost($sockInt)
string getQueue($sockInt)
string getQueueLine($sockInt)
int sendSocket($sockInt, $data)
int getSockStatus($sockInt)
object getSockData($sockInt)
bool hasWriteQueue($sockInt)
bool hasLine($sockInt)
timers.php (Accessed with $this->timerClass->)
----------------------------------------------
class addTimer($name, $class, $function, $args, $interval, $runRightAway = false)
class getTimers()
void removeTimer($timer) (MUST be name)
mysql/postgre.php (Accessed with $this->db->)
---------------------------------------------
array queryFetch($query)
array fetchArray($object)
array fetchRow($object)
string getError()
bool isConnected()
int lastID()
int numRows($toFetch)
int numQueries()
void close()
object query($query)
dcc.php (Accessed with $this->dccClass->)
-----------------------------------------
array getDccList()
int getDownloadCount()
int getUploadCount()
int getChatCount()
int getBytesDown()
int getBytesUp()
int addChat($nick, $host, $port, $admin, $handler)
int addFile($nick, $host, $port, $type, $filename, $size)
int sendFile($nick, $file)
class getDcc($dcc)
void dccInform($text, $from = null)
chat.php
----------
void disconnect($msg = "")
void dccSend($msg)
file.php
----------
void disconnect($msg = "")
ini.php
----------
bool getError()
bool sectionExists($section)
bool deleteSection($section)
bool deleteVar($section, $var)
bool setIniVal($section, $var, $val)
bool writeIni()
array getSections()
array getVars($section)
array getSection($section)
array randomSection($num = 1)
array searchSections($search, $type = EXACT_MATCH)
array searchVars($section, $search, $type = EXACT_MATCH)
array searchSectionsByVar($var, $search, $type = EXACT_MATCH)
array searchVals($section, $search, $type = EXACT_MATCH)
mixed randomVar($section, $num = 1)
mixed getIniVal($section, $var)
int numSections()
int numVars($section)
Useful Static Routines
-----------------------
string socket::generatePostQuery($query, $host, $path, $httpVersion)
string socket::generateGetQuery($query, $host, $path, $httpVersion)
string irc::intToSizeString($size)
string irc::myStrToLower($text)
string irc::myStrToUpper($text)
string irc::timeFormat($time, $format)
string irc::randomHash()
array irc::multiLine($text)
=========================
Full Function Definitions
=========================
irc.php (Accessed with $this->ircClass->)
-----------------------------------------
-------------------------------
array parseModes($modeString)
-------------------------------
Mode strings usually come from the $line['params'] variable. However, they look like this:
+o-b Manick blah!*@*
This is a real mess to parse. Thus, this function takes the line and returns an array of each mode being operated. The format is as follows:
$modesArray = array(
[0] = array( 'ACTION' => '+',
'MODE' => 'o',
'EXTRA' => 'Manick',
'TYPE' => USER_MODE,
)
[1] = array( 'ACTION' => '-',
'MODE' => 'b',
'EXTRA' => 'blah!*@*',
'TYPE' => CHANNEL_MODE,
)
)
--------------------------------
array getMaintainedChannels()
--------------------------------
This will return an array of all the channels that php-irc will attempt to stay in. Every sixty seconds or so, the bot will attempt to join these channels if it is not currently in them. See 'maintainChannel()' and 'removeMaintain()' for more information.
--------------------------------
string getClientConf($var = "")
--------------------------------
Will return the corresponding value for the setting of $var in bot.conf. If $var == "", the full configuration array is returned as an array. Also, if the setting does not exist in the configuration, this function will return an empty string, "".
--------------------------------
string getNick()
--------------------------------
Returns the bots current, IRC recognized nick.
--------------------------------
string getServerConf($var)
--------------------------------
When connecting to a server, it will send these lines upon connection:
NETWORK=Rizon STATUSMSG=@%+ MODES=4 CHANLIMIT=#:30 MAXCHANNELS=30 MAXLIST=beI:100 MAXBANS=100 MAXTARGETS=4 NICKLEN=30 TOPICLEN=400 KICKLEN=400 CHANNELLEN=50 AWAYLEN=90 are supported by this server
CHANTYPES=# KNOCK EXCEPTS INVEX PREFIX=(ohv)@%+ CHANMODES=eIb,k,l,cimnpstMNORZ CASEMAPPING=rfc1459 CALLERID WALLCHOPS FNC PENALTY ETRACE are supported by this server
(These are just samples). So, you can retrieve the value for say, CHANMODES by doing this:
getServerConf("CHANMODES");
This will return a string, "eIb,k,l,cimnpstMNORZ".
----------------------------------
string getStatusString($status)
----------------------------------
After using getStatusRaw(), you can feed its value to this function, and it'll send back what it means, like "Connecting to Server..."
----------------------------------
string getClientIP($long = 1)
----------------------------------
This function returns the IP that the bot is using. if you specify $long as 1, then the ip address converted to long integer form is returned.
----------------------------------
class getChannelData($channel)
----------------------------------
This will search the channel database for the channel $channel, and then if it finds it, it will return that channels object. See the "channelLink" class in defines.php for member information.
----------------------------------
class getUserData($user, $channel = "")
----------------------------------
If a channel is specified, this will search the channel for the specified user's data. If it is found, it will return it as an object. See the "memberLink" class in defines.php for member information. If no channel is specified, this will search the entire channel database until the member is found, and then return that object.
----------------------------------
void disconnect()
----------------------------------
Disconnect the bot from the server...
----------------------------------
void setClientConfigVar($var, $value)
----------------------------------
This will overwrite a configuration setting from bot.conf that the bot is currently using. Self-explanitory.
----------------------------------
void joinChannel($chan)
----------------------------------
Join the channel $chan
----------------------------------
void sendRaw($text, $force = false)
----------------------------------
Send the raw text $text to the server. If $force is true, then the data is sent RIGHT away, it totally bypasses the queue, everything. It goes right to the send function, even through the socket class. Use this if you need lightning fast responses, such as writing a channel guard script.
----------------------------------
void privMsg($who, $msg, $queue = 1)
----------------------------------
$who = nick of user/name of channel
Send text to a channel or user. If $queue is 1, then the data will be put at the end of the text queue, if it is 0, it'll be pushed onto the beginning of the queue.
----------------------------------
void action($who, $msg, $queue = 1)
----------------------------------
Same as privMsg... emulates the /me command from mIRC
----------------------------------
void notice($who, $msg, $queue = 1)
----------------------------------
Same as privMsg, except a notice.
----------------------------------
void log($text)
----------------------------------
Write something to the log file.
----------------------------------
void maintainChannel($channel, $key = "")
----------------------------------
Attempt to stay in channel $channel. The bot will attempt rejoining every 60 seconds. You may specify a $key or leave it blank.
----------------------------------
void removeMaintain($channel)
----------------------------------
No longer attempt to say in channel $channel.
----------------------------------
void addQuery($host, $port, $query, $line, $class, $function)
----------------------------------
Also make sure you read the text about this function in the readme.txt, "Querying remote servers". This function takes 6 arguments.
$host = the host machine you want to connect to
$port = the port you want to connect to
$query = the raw data that will be sent to the server upon connection
$line = the $line argument that was passed to your module's function (just pass this right along with addQuery)
$class = usually '$this'..
$function = the function to run after the query is complete.
See sections 8 and 9 of readme.txt for information related to writing 'query' function types.
----------------------------------
int getStatusRaw()
----------------------------------
Returns an integer corresponding to current server status. See defines.php for meanings
----------------------------------
bool changeMode($chan, $act, $mode, $user)
----------------------------------
Changes the mode of $user on $chan
$act = either "+" or "-"
$mode = some mode, like "o" (ops), or "b" (ban), or something else.
$user = whatever the mode is being applied to
----------------------------------
bool isOnline($nick, $chan)
----------------------------------
Send back whether the nick is on the channel $chan (true or false)
----------------------------------
bool isMode($nick, $channel, $mode)
----------------------------------
See if some $user has some $mode activated on him in $channel
$user = nick of user
$mode = any mode, such as "o", "h", "v"
----------------------------------
bool isChanMode($channel, $mode, $extra = "")
----------------------------------
Sends back whether a specific mode is set in a channel
$mode = "b" or "s" or any other chan mode
$extra = (if you're using "b" for $mode, specify mask here)
----------------------------------
bool hasModeSet($chan, $nick, $modes)
----------------------------------
If any of the modes specified in "$modes" are set on a user in a channel, this will return true.
For instance:
If Manick is +vo in channel #manekian,
hasModeSet("#manekian", "Manick", "oh")
will return true. I'm asking php-irc if Manick is either mode o or mode h. Which he's mode o, so it returns true.
----------------------------------
bool hostMasksMatch($mask1, $mask2)
----------------------------------
Use this to determine whether two host masks match
----------------------------------
bool checkIgnore($mask)
----------------------------------
Check whether a hostmask is on the bot.conf ignore list.
socket.php (Accessed with $this->socketClass->)
-----------------------------------------------
----------------------------------
string getHost($sockInt)
----------------------------------
Return the IP address of the current socket integer of a connection. You can use connection::getSockInt() to get the sock int.
----------------------------------
string getQueue($sockInt)
----------------------------------
Retrieve the current read queue for a socket. The queue is then purged.
----------------------------------
string getQueueLine($sockInt)
----------------------------------
Get the next line in the queue, purging it from the read buffer and returning it (without crlf)
----------------------------------
int sendSocket($sockInt, $data)
----------------------------------
Send data to a socket
----------------------------------
int getSockStatus($sockInt)
----------------------------------
Get the status of a socket. See defines.php for list of constants.
----------------------------------
object getSockData($sockInt)
----------------------------------
Return the object that retains all data about socket "$sockInt". This is a php-irc maintained list.
----------------------------------
bool hasWriteQueue($sockInt)
----------------------------------
Return true or false depending on whether the bot has data to write to the socket. If this is true, you should restrain yourself from sending more data to the socket. An onWrite() call will be sent every time data is written, and each time "hasWriteQueue()" should be called to see if the queue is empty before sending data.
----------------------------------
bool hasLine($sockInt)
----------------------------------
Return true or false depending on if there is a newline in the buffer.
timers.php (Accessed with $this->timerClass->)
----------------------------------------------
----------------------------------
class addTimer($name, $class, $function, $args, $interval, $runRightAway = false)
----------------------------------
Add a timer. Please view the readme.txt documentation on this.
----------------------------------
class getTimers()
----------------------------------
This function will return a pointer to all the active timers. See the class "timer" in defines.php for member information.
----------------------------------
void removeTimer($timer) (MUST be timer name)
----------------------------------
Remove a timer $timer <-- can only be the name of timer, unlike in 2.1.1 where it could be the object itself.
mysql/postgre.php (Accessed with $this->db->)
---------------------------------------------
Some items for postgre aren't fully implemented or work yet... most notably queryFetch(), and some others. See postgre.php for more details.
----------------------------------
array queryFetch($query)
----------------------------------
Runs a query and returns the first row. Basically does query() and then mysql_fetch_array()
----------------------------------
array fetchArray($object)
----------------------------------
Does mysql_fetch_array() (see php.net for help)
----------------------------------
array fetchRow($object)
----------------------------------
Does mysql_fetch_row()
----------------------------------
string getError()
----------------------------------
Does mysql_error();
----------------------------------
bool isConnected()
----------------------------------
Returns whether the database is connected
----------------------------------
int lastID()
----------------------------------
Gets the last inserted 'id' row from the database.
----------------------------------
int numRows($toFetch)
----------------------------------
Does mysql_num_rows()
----------------------------------
int numQueries()
----------------------------------
sends back an integer of all the queries since the database class was spawned.
----------------------------------
void close()
----------------------------------
Closes the database connection
----------------------------------
object query($query)
----------------------------------
Runs a query, and returns the result as an object.
dcc.php (Accessed with $this->dccClass->)
-----------------------------------------
----------------------------------
array getDccList()
----------------------------------
Returns an array of all current dcc's in progress (chat and file)
----------------------------------
int getDownloadCount()
----------------------------------
Number of all current downloads
----------------------------------
int getUploadCount()
----------------------------------
Number of all current uploads
----------------------------------
int getChatCount()
----------------------------------
Number of all current dcc chat sessions
----------------------------------
int getBytesDown()
----------------------------------
Returns number of bytes downloaded since bot was started
----------------------------------
int getBytesUp()
----------------------------------
Returns number of bytes uploaded since bot was started
----------------------------------
int addChat($nick, $host, $port, $admin, $handler)
----------------------------------
Use this to create a dcc chat session.
$nick = nick of user to chat with
$host = host of user to chat with
$port = port to connect to
$admin = whether the user is admin (use admin dcc chat administration)
$handler = null, usually, unless you are creating a custom dcc chat handler. See readme.txt for more information.
If $host or $port is null, then addChat will think you are setting up a listening connection, otherwise it will try to connect to the host/port specified.
----------------------------------
int addFile($nick, $host, $port, $type, $filename, $size)
----------------------------------
Send a file to someone, or recieve a file.
$nick = nick of person sending/receiving file
$host = host of person sending/receiving file
$port = port of transfer
$type = either UPLOAD or DOWNLOAD
$filename = full filename with full path to file
$size = size of the file, can be null if its an UPLOAD type.
See readme.txt for more information regarding file transfers.
----------------------------------
int sendFile($nick, $file)
----------------------------------
Alias for addFile($nick, null, null, UPLOAD, $file, null)... basically just an easier way of sending files.
----------------------------------
class getDcc($dcc)
----------------------------------
$dcc = sockInt of the transfer
Returns dcc object for some sockInt, see fileserver.php for example.
----------------------------------
void dccInform($text)
----------------------------------
Send a message to all administrators
chat.php
----------
----------------------------------
void disconnect($msg = "")
----------------------------------
End the chat session
----------------------------------
void dccSend($msg)
----------------------------------
Send text to the user
file.php
----------
----------------------------------
void disconnect($msg = "")
----------------------------------
End the dcc file transfer session
ini.php
----------
Please see readme.txt for more information on create ini objects.
----------------------------------
bool getError()
----------------------------------
An ini object will not operate after a fatal error. You can use this to retrieve whether a fatal error has happened.
----------------------------------
bool sectionExists($section)
----------------------------------
Return true if the section exists, or false if it doesn't.
----------------------------------
bool deleteSection($section)
----------------------------------
Delete a section.
----------------------------------
bool deleteVar($section, $var)
----------------------------------
Delete a var in a section.
----------------------------------
bool setIniVal($section, $var, $val)
----------------------------------
Set the '$var' value '$val' in section $section.
----------------------------------
bool writeIni()
----------------------------------
Write all of the ini changes to a file
----------------------------------
array getSections()
----------------------------------
Return an array of all the section names.
----------------------------------
array getVars($section)
----------------------------------
Return all the vars/vals in an associative array for $section.
----------------------------------
array getSection($section)
----------------------------------
Alias for getVars()
----------------------------------
array randomSection($num = 1)
----------------------------------
Does same as getVars(), but returns random section. $num is the number of random sections to return. Default 1.
----------------------------------
array searchSections($search, $type = EXACT_MATCH)
----------------------------------
Search section names for $search, can do 4 types of searches: Exact, and, or, contains:
Exact: the section and search match completely
And: the section name contains all componants of search (separated by space)
Or: the section name contains at least one of the componants of search (separated by space)
Contains: the section contains the search string within it
----------------------------------
array searchVars($section, $search, $type = EXACT_MATCH)
----------------------------------
Search the variable names of a section for $search, same as searchSections() except with vars.
----------------------------------
array searchSectionsByVar($var, $search, $type = EXACT_MATCH)
----------------------------------
In every section that has '$var' as a varaible, see if the var's value matches $search.
----------------------------------
array searchVals($section, $search, $type = EXACT_MATCH)
----------------------------------
Search all the values of a section for '$search'. Return list of vars.
----------------------------------
mixed randomVar($section, $num = 1)
----------------------------------
Return a random var in a section.
----------------------------------
mixed getIniVal($section, $var)
----------------------------------
Retrieve an ini value '$var' in section '$section'. False if non-existant.
----------------------------------
int numSections()
----------------------------------
Return number of sections.
----------------------------------
int numVars($section)
----------------------------------
Return number of vars in a section.
Useful Static Routines
-----------------------
----------------------------------
string socket::generatePostQuery($query, $host, $path, $httpVersion = "")
----------------------------------
Takes a query, like so:
$query = "search=blah&somesetting=5";
And turns it into a POST query you can send off to addQuery
$host = host of server you will be accessing, like "www.manekian.com"
$path = script + path of script you will be accessing, like "/search.php" or "/index.php", or just "/"
$httpVersion, you can ignore this, but sometimes you might want to set this to "1.0"
----------------------------------
string socket::generateGetQuery($query, $host, $path, $httpVersion)
----------------------------------
Same as generatePostQuery except with Get String
----------------------------------
string irc::intToSizeString($size)
----------------------------------
Takes a large size, and then changes it into MB, GB, KB, depending on the size.
----------------------------------
string irc::myStrToLower($text)
----------------------------------
RFC1459 complient strtolower()
----------------------------------
string irc::myStrToUpper($text)
----------------------------------
RFC1459 complient strtoupper()
----------------------------------
string irc::timeFormat($time, $format)
----------------------------------
Feed this thing a timestring, and a format, and it'll send back a user friendly representation of the timestamp.
for example:
timeFormat(5, "%d days, %h hours, %m minutes, %s seconds")
This will return a string, "0 days, 0 hours, 0 minutes, 5 seconds".
----------------------------------
string irc::randomHash()
----------------------------------
Generates a 32 char random md5 hash
----------------------------------
array irc::multiLine($text)
----------------------------------
Feed this a huge text string, and it will split it up into 255 max char increment lines you can send to the irc server. It returns an array of all of these.

432
ircbot/connection.php Normal file
View file

@ -0,0 +1,432 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.1.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2004 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > connection class module
| > Module written by Manick
| > Module Version Number: 2.1.2
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
/* Connection class. A Layer between dcc/irc class and socket class. */
/* To use, simply create an object, call the calls listed under the constructor in order. */
/* Damn I'm hungry... */
class connection {
//External Classes
private $socketClass;
private $ircClass;
private $timerClass;
//Internal variables
private $callbackClass;
private $host;
private $port;
private $connTimeout;
private $transTimeout;
private $sockInt;
//Function specific
private $connected;
private $connStartTime;
private $lastTransTime;
//If this is set to true, this connection class will no longer function.
private $error;
private $errorMsg;
//Called first
function __construct($host, $port, $connTimeout)
{
$this->error = true;
$this->errorMsg = "Connection not initialized";
$this->host = $host;
$this->port = $port;
$this->connTimeout = $connTimeout;
$this->transTimeout = 0;
$this->connected = false;
$this->sockInt = false;
}
//Called second
public function setSocketClass($class)
{
$this->socketClass = $class;
}
//Called third
public function setIrcClass($class)
{
$this->ircClass = $class;
}
//Called fourth
public function setCallbackClass($class)
{
$this->callbackClass = $class;
}
//Called fifth
public function setTimerClass($class)
{
$this->timerClass = $class;
}
//Called sixth
public function init()
{
$this->error = false;
if ($this->host != null)
{
if ($this->connTimeout <= 0)
{
$this->setError("Must set connection timeout > 0 for non-listening sockets");
return;
}
}
else
{
if ($this->connTimeout < 0)
{
$this->setError("Must set connection timeout >= 0 for listening sockets");
return;
}
}
if (!is_object($this->callbackClass))
{
$this->setError("Specified callback class is not an object");
return;
}
if (!is_object($this->socketClass))
{
$this->setError("Specified socket class is not an object");
return;
}
if (!is_object($this->ircClass))
{
$this->setError("Specified irc class is not an object");
return;
}
$sockInt = $this->socketClass->addSocket($this->host, $this->port); // add socket
if ($sockInt == false)
{
$this->setError("Could not create socket");
return;
}
$sockData = $this->socketClass->getSockData($sockInt);
$this->socketClass->setHandler($sockInt, $this->ircClass, $this, "handle");
//Set internal variables
if ($this->port == NULL)
{
$this->port = $sockData->port;
}
$this->sockInt = $sockInt;
return $this->port;
}
public function bind($ip)
{
if ($this->error != false || $this->sockInt == false)
{
return;
}
if ($this->connected == true)
{
return;
}
$this->socketClass->bindIP($this->sockInt, $ip);
}
//Called to listen, only called by onAccept() function in this class
public function listen()
{
$this->error = false;
$this->connected = true;
}
//Called last, and only to start connection to another server
public function connect()
{
if ($this->error == true)
{
return false;
}
if ($this->connTimeout > 0)
{
$this->timerClass->addTimer(irc::randomHash(), $this, "connTimeout", "", $this->connTimeout);
}
$this->timerClass->addTimer(irc::randomHash(), $this->socketClass, "connectSocketTimer", $this->sockInt, 1);
/* $this->socketClass->beginConnect($this->sockInt); */
$this->connStartTime = time();
}
public function disconnect()
{
unset($this->callbackClass);
$this->socketClass->killSocket($this->sockInt);
$this->socketClass->removeSocket($this->sockInt);
$this->setError("Disconnected from server");
}
public function getSockInt()
{
return $this->sockInt;
}
public function setSockInt($sockInt)
{
$this->sockInt = $sockInt;
}
public function setTransTimeout($time)
{
$this->transTimeout = ($time < 0 ? 0 : $time);
}
/* Timers */
public function connTimeout()
{
if ($this->connected == false)
{
$this->handle(CONN_CONNECT_TIMEOUT);
}
}
public function transTimeout()
{
if ($this->error == true)
{
return false;
}
if ($this->connected == false)
{
return true;
}
if ($this->transTimeout > 0)
{
if (time() > $this->transTimeout + $this->lastTransTime)
{
$this->handle(CONN_TRANSFER_TIMEOUT);
}
}
return true;
}
//handle function, handles all calls from socket class, and calls appropriate
//functions in the callback class
public function handle($msg)
{
if ($this->socketClass->getSockStatus($this->sockInt) === false)
{
return false;
}
$stat = false;
if ($this->error == true)
{
return false;
}
switch ($msg)
{
case CONN_CONNECT:
$stat = $this->onConnect();
break;
case CONN_READ:
$stat = $this->onRead();
break;
case CONN_WRITE:
$stat = $this->onWrite();
break;
case CONN_ACCEPT:
$stat = $this->onAccept();
break;
case CONN_DEAD:
$stat = $this->onDead();
break;
case CONN_TRANSFER_TIMEOUT:
$stat = $this->onTransferTimeout();
break;
case CONN_CONNECT_TIMEOUT:
$stat = $this->onConnectTimeout();
break;
default:
return false;
break;
}
return $stat;
}
/* Specific handling functions */
private function onTransferTimeout()
{
$this->callbackClass->onTransferTimeout($this);
}
private function onConnectTimeout()
{
$this->callbackClass->onConnectTimeout($this);
}
private function onConnect()
{
$this->connected = true;
if ($this->transTimeout > 0)
{
$this->timerClass->addTimer(irc::randomHash(), $this, "transTimeout", "", $this->transTimeout);
}
$this->callbackClass->onConnect($this);
return false;
}
//For this function, true can be returned from onRead() to input more data.
private function onRead()
{
$this->lastTransTime = time();
$stat = $this->callbackClass->onRead($this);
if ($stat !== true)
{
$this->socketClass->clearReadSchedule($this->sockInt);
}
return $stat;
}
private function onWrite()
{
$this->socketClass->clearWriteSchedule($this->sockInt);
$this->lastTransTime = time();
$this->callbackClass->onWrite($this);
return false;
}
private function onAccept()
{
//Get the sockInt from the socketClass
$newSockInt = $this->socketClass->hasAccepted($this->sockInt);
if ($newSockInt === false)
{
//False alarm.. just ignore it.
return false;
}
//Create a new connection object for the new socket connection, then return it to onAccept
//We must assume that onAccept will handle the connection object. Otherwise it'll die, and the
//connection will be orphaned.
$newConn = new connection(null, null, 0);
$newConn->setSocketClass($this->socketClass);
$newConn->setIrcClass($this->ircClass);
$newConn->setCallbackClass($this->callbackClass); //Can be overwritten in the onAccept function
$newConn->setTimerClass($this->timerClass);
$newConn->listen();
//We don't need to call init(), we're already setup.
//Setup our connection transmission timeout thing.
if ($this->transTimeout > 0)
{
$this->timerClass->addTimer(irc::randomHash(), $newConn, "transTimeout", "", $this->transTimeout);
}
$newConn->setTransTimeout($this->transTimeout);
//Set handler for our new sockInt to new connection class
$this->socketClass->setHandler($newSockInt, $this->ircClass, $newConn, "handle");
//Set our new sockInt
$newConn->setSockInt($newSockInt);
//Call our callback function for accepting with old object, and new object.
$this->callbackClass->onAccept($this, $newConn);
return false;
}
private function onDead()
{
if ($this->connected == true)
{
$this->setError("Connection is dead");
}
else
{
$this->setError("Could not connect: " . $this->socketClass->getSockStringError($this->sockInt));
}
$this->callbackClass->onDead($this);
return false;
}
/* Error handling routines */
private function setError($msg)
{
$this->error = true;
$this->errorMsg = $msg;
}
public function getError()
{
return $this->error;
}
public function getErrorMsg()
{
return $this->errorMsg;
}
}
?>

515
ircbot/databases/ini.php Normal file
View file

@ -0,0 +1,515 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://phpbots.sf.net/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > ini-file database module
| > Module written by Manick
| > Module Version Number: 2.2.1 alpha
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class ini {
private $filename;
private $error;
private $ini = array();
private $numSections;
//used in isMatched()
private $search;
private $searchParts;
//Load ini into memory
public function __construct($filename)
{
$this->error = false;
$this->filename = $filename;
$filePtr = @fopen($filename, "r");
if ($filePtr === false)
{
$filePtr = @fopen($filename, "a");
if ($filePtr === false)
{
$this->error = true;
return;
}
else
{
fclose($filePtr);
return;
}
}
$fileData = "";
while (!feof($filePtr))
{
$fileData .= fread($filePtr, 4096);
}
fclose($filePtr);
$fileData = str_replace("\r", "", $fileData);
$lines = explode("\n", $fileData);
$currSection = "";
$this->numSections = 0;
foreach($lines AS $line)
{
$line = trim($line);
$offsetA = strpos($line, "[");
$offsetB = strpos($line, "]");
if ($offsetA === 0)
{
$currSection = substr($line, 1, $offsetB - 1);
$this->numSections++;
$this->ini[$currSection] = array();
}
else
{
if ($currSection != "")
{
$offsetC = strpos($line, "=");
if ($offsetC !== false)
{
$var = trim(substr($line, 0, $offsetC));
$val = substr($line, $offsetC + 1);
if ($var != "")
{
$this->ini[$currSection][$var] = $val;
}
}
else
{
$this->ini[$currSection][$line] = true;
}
}
}
}
}
public function getError()
{
return $this->error;
}
public function getSections()
{
$sections = array();
if ($this->numSections == 0)
{
return $sections;
}
foreach ($this->ini AS $section => $vals)
{
$sections[] = $section;
}
return $sections;
}
public function getVars($section)
{
if (!isset($this->ini[$section]))
{
return false;
}
return $this->ini[$section];
}
public function sectionExists($section)
{
if (isset($this->ini[$section]) && is_array($this->ini[$section]))
{
return true;
}
return false;
}
public function getSection($section)
{
return $this->getVars($section);
}
public function randomSection($num = 1)
{
if ($this->numSections == 0 || $num < 1 || $num > $this->numSections)
{
return false;
}
return array_rand($this->ini, $num);
}
public function randomVar($section, $num = 1)
{
if (!isset($this->ini[$section]))
{
return false;
}
$count = count($this->ini[$section]);
if ($count == 0 || $num < 1 || $num > $count)
{
return false;
}
return array_rand($this->ini[$section], $num);
}
public function searchSections($search, $type = EXACT_MATCH)
{
$results = array();
if (trim($search) == "")
{
return $results;
}
if ($this->numSections == 0)
{
return;
}
foreach($this->ini AS $section => $vars)
{
if ($this->isMatched($search, $section, $type))
{
$results[] = $section;
}
}
return $results;
}
public function searchVars($section, $search, $type = EXACT_MATCH)
{
$results = array();
if (trim($search) == "")
{
return $results;
}
if (!isset($this->ini[$section]))
{
return $results;
}
if ($this->numSections == 0)
{
return;
}
if (count($this->ini[$section]) == 0)
{
return $results;
}
foreach($this->ini[$section] AS $var => $val)
{
if ($this->isMatched($search, $var, $type))
{
$results[] = $var;
}
}
return $results;
}
public function searchSectionsByVar($var, $search, $type = EXACT_MATCH)
{
$results = array();
if ($this->numSections == 0)
{
return $results;
}
foreach($this->ini AS $section => $vars)
{
if (isset($vars[$var]))
{
if ($this->isMatched($search, $vars[$var], $type))
{
$results[] = $section;
}
}
}
return $results;
}
public function searchVals($section, $search, $type = EXACT_MATCH)
{
$results = array();
if (trim($search) == "")
{
return $results;
}
if (!isset($this->ini[$section]))
{
return $results;
}
if ($this->numSections == 0)
{
return;
}
if (count($this->ini[$section]) == 0)
{
return $results;
}
foreach($this->ini[$section] AS $var => $val)
{
if ($this->isMatched($search, $val, $type))
{
$results[] = $var;
}
}
return $results;
}
private function isMatched(&$needle, &$haystack, $type = EXACT_MATCH)
{
if ($type == EXACT_MATCH)
{
if ($haystack == $needle)
{
return true;
}
}
if ($type == CONTAINS_MATCH)
{
if (strpos(strtolower($haystack), strtolower($needle)) !== false)
{
return true;
}
}
if ($search != $this->search)
{
$this->searchParts = explode(chr(32), $search);
$this->search = $search;
}
if ($type == AND_MATCH)
{
$foundAll = true;
foreach($this->searchParts AS $part)
{
if (strpos($val, $part) === false)
{
$foundAll = false;
break;
}
}
if ($foundAll == true)
{
return true;
}
}
else if ($type == OR_MATCH)
{
foreach($this->searchParts AS $part)
{
if (strpos($val, $part) !== false)
{
return true;
break;
}
}
}
return false;
}
public function deleteSection($section)
{
if (isset($this->ini[$section]))
{
unset($this->ini[$section]);
return true;
}
return false;
}
public function deleteVar($section, $var)
{
if (isset($this->ini[$section]))
{
if (isset($this->ini[$section][$var]))
{
unset($this->ini[$section][$var]);
return true;
}
}
return false;
}
public function numSections()
{
return $this->numSections;
}
public function numVars($section)
{
if (isset($this->ini[$section]))
{
return count($this->ini[$section]);
}
return 0;
}
public function setIniVal($section, $var, $val)
{
if ($this->error == true)
{
return;
}
if (!isset($this->ini[$section]))
{
$this->numSections++;
$this->ini[$section] = array();
}
if (strpos($var, "=") !== false)
{
return false;
}
$this->ini[$section][$var] = $val;
return true;
}
public function getIniVal($section, $var)
{
if ($this->error == true)
{
return;
}
if (isset($this->ini[$section])
&& isset($this->ini[$section][$var]))
{
return $this->ini[$section][$var];
}
else
{
return false;
}
}
//Update and write ini to file
public function writeIni()
{
if ($this->error == true)
{
return;
}
if ($this->numSections == 0)
{
return;
}
$output = "";
foreach ($this->ini AS $section => $vars)
{
$output .= "[" . $section . "]\n";
if (count($vars))
{
foreach ($vars AS $var => $val)
{
$output .= $var . "=" . $val . "\n";
}
}
}
$filePtr = fopen($this->filename, "at");
if ($filePtr === false)
{
$this->error = true;
return false;
}
flock($filePtr, LOCK_EX);
ftruncate($filePtr, 0);
if (fwrite($filePtr, $output) === FALSE)
{
$this->error = true;
}
flock($filePtr, LOCK_UN);
fclose($filePtr);
return !$this->error;
}
}
?>

169
ircbot/databases/mysql.php Normal file
View file

@ -0,0 +1,169 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://phpbots.sf.net/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > database module
| > Module written by Manick
| > Module Version Number: 2.2.0 alpha1
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class mysql {
private $dbIndex;
private $prefix;
private $queries = 0;
private $isConnected = false;
private $user;
private $pass;
private $database;
private $host;
private $port;
public function __construct($host, $database, $user, $pass, $prefix, $port = 3306)
{
$this->user = $user;
$this->pass = $pass;
$this->host = $host;
$this->database = $database;
$this->port = $port;
$db = mysql_connect($host . ":" . $port, $user, $pass);
if (!$db)
{
return;
}
$dBase = mysql_select_db($database, $db);
if (!$dBase)
{
return;
}
$this->prefix = $prefix;
$this->dbIndex = $db;
$this->isConnected = true;
}
public function getError()
{
return (@mysql_error($this->dbIndex));
}
public function isConnected()
{
return $this->isConnected;
}
//Call by reference switched to function declaration, 05/13/05
private function fixVar($id, &$values)
{
return mysql_real_escape_string($values[intval($id)-1], $this->dbIndex);
}
public function query($query, $values = array())
{
if (!is_array($values))
$values = array($values);
$query = preg_replace('/\[([0-9]+)]/e', "\$this->fixVar(\\1, \$values)", $query);
$this->queries++;
$data = mysql_query($query, $this->dbIndex);
if (!$data)
{
return false;
}
return $data;
}
public function queryFetch($query, $values = array())
{
if (!is_array($values))
$values = array($values);
$query = preg_replace('/\[([0-9]+)]/e', "\$this->fixVar(\\1, &\$values)", $query);
$this->queries++;
$data= mysql_query($query, $this->dbIndex);
if (!$data)
{
return false;
}
return mysql_fetch_array($data);
}
public function fetchArray($toFetch)
{
return mysql_fetch_array($toFetch);
}
public function fetchRow($toFetch)
{
return mysql_fetch_row($toFetch);
}
public function close()
{
@mysql_close($this->dbIndex);
}
public function lastID()
{
return mysql_insert_id();
}
public function numRows($toFetch)
{
return mysql_num_rows($toFetch);
}
public function numQueries()
{
return $this->queries;
}
}
?>

View file

@ -0,0 +1,162 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://phpbots.sf.net/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > database module
| > Module written by Manick
| > Module Version Number: 2.1.1
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class postgre {
private $dbIndex;
private $prefix;
private $queries = 0;
private $isConnected = false;
private $error;
public function __construct($host, $database, $user, $pass, $prefix, $port = 5432)
{
$this->error = true;
$connect = "host=" . $host . " ".
"port=" . $port . " ".
"dbname=" . $database . " ".
"user=" . $user . " ".
"password=" . $pass;
$this->error = pg_connect($connect);
if (!$this->error)
{
return;
}
$this->prefix = $prefix;
$this->dbIndex = $this->error;
$this->isConnected = true;
}
public function getError()
{
return $this->error === false ? true : false;
//return (@mysql_error($this->dbIndex));
}
public function isConnected()
{
return $this->isConnected;
}
private function fixVar($id, $values)
{
return pg_escape_string($values[intval($id)-1]);
}
public function query($query, $values = array())
{
if (!is_array($values))
$values = array($values);
$query = preg_replace('/\[([0-9]+)]/e', "\$this->fixVar(\\1, &\$values)", $query);
$this->queries++;
$data = pg_query($this->dbIndex, $query);
if (!$data)
{
$this->error = $data;
return false;
}
return $data;
}
public function queryFetch($query, $values = array())
{
if (!is_array($values))
$values = array($values);
$query = preg_replace('/\[([0-9]+)]/e', "\$this->fixVar(\\1, &\$values)", $query);
$this->queries++;
$data = pg_query($query, $this->dbIndex);
if (!$data)
{
$this->error = false;
return false;
}
return pg_fetch_array($data);
}
public function fetchArray($toFetch)
{
return pg_fetch_array($toFetch);
}
public function fetchRow($toFetch)
{
return pg_fetch_row($toFetch);
}
public function close()
{
@pg_close($this->dbIndex);
}
public function lastID()
{
//ehhh. don't use this.
return null;
}
public function numRows($toFetch)
{
return pg_num_rows($toFetch);
}
public function numQueries()
{
return $this->queries;
}
}
?>

View file

@ -0,0 +1,148 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://phpbots.sf.net/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > database module
| > Module written by Manick
| > Module Version Number: 2.1.1
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
// *** Modified by Nemesis128_at_atarax_dot_org
class postgresql {
private $dbRes;
private $prefix;
private $numQueries = 0;
private $isConnected = false;
private $error = false;
private $user;
private $pswd;
private $dbase;
private $host;
private $port;
public function __construct ($user,$pswd,$dbase,$prefix,$host = null,$port = 5432) {
$this->user = $user;
$this->pswd = $pswd;
$this->dbase = $dbase;
$this->prefix = $prefix;
$this->host = $host;
$this->port = $port;
$conn_str = '';
if (!is_null($host)) { // connect thru TCP/IP
$conn_str .= 'host='.$host;
$conn_str .= ' port='.$port;
} // else thru intern sockets
$conn_str .= ' user='.$user;
$conn_str .= ' password='.$pswd;
$conn_str .= ' dbname='.$dbase;
$this->dbRes = pg_connect($conn_str);
if (!is_resource($this->dbRes)) {
$this->error = 'PgSQL Connection error';
return;
}
$this->isConnected = true;
}
public function getError () {
if ($this->error) {
$err = $this->error."\n\n";
return ($err.@pg_last_error($this->dbIndex));
} else {
return null;
}
}
public function isConnected () {
return $this->isConnected;
}
public static function esc ( $var ) {
return pg_escape_string ( $var );
}
public function query ( $query_str ) {
if (pg_connection_status($this->dbRes) === PGSQL_CONNECTION_BAD) {
if (!pg_connection_reset($this->dbRes)) {
$this->error = 'Connection lost';
$this->isConnected = false;
return false;
}
}
$this->numQueries++;
$res = @pg_query($this->dbRes,$query_str);
if (!$res) {
$this->error = 'Query failed: '.pg_last_error().' ('.$query_str.')';
return false;
}
return $res;
}
public function fetchArray ( $toFetch ) {
return pg_fetch_assoc($toFetch);
}
public function fetchObject ( $toFetch ) {
return pg_fetch_object($toFetch);
}
public function fetchRow ( $toFetch ) {
return pg_fetch_row($toFetch);
}
public function numRows ( $toFetch ) {
return pg_num_rows($toFetch);
}
public function numQueries () {
return $this->numQueries;
}
public function close () {
@pg_close($this->dbRes);
}
}
?>

579
ircbot/dcc.php Normal file
View file

@ -0,0 +1,579 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > dcc module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class dcc {
private $dccList = array(); //holds all connected sockets
private $dccChangedList = array();
private $dccChangedCount = 0;
private $fileDlCount = 0;
private $fileUlCount = 0;
private $chatCount = 0;
//Classes
private $timerClass;
private $socketClass;
private $ircClass;
private $parserClass;
//Bytes Transferred
private $bytesUp = 0;
private $bytesDown = 0;
//Process Queue
private $procQueue;
public function __construct()
{
// do nothing...
}
public function setProcQueue($class)
{
$this->procQueue = $class;
}
public function setIrcClass($class)
{
$this->ircClass = $class;
}
public function setParserClass($class)
{
$this->parserClass = $class;
$this->parserClass->setDccClass($this);
}
public function setSocketClass($class)
{
$this->socketClass = $class;
}
public function setTimerClass($class)
{
$this->timerClass = $class;
}
public function getDownloadCount()
{
return $this->fileDlCount;
}
public function getUploadCount()
{
return $this->fileUlCount;
}
public function getChatCount()
{
return $this->chatCount;
}
public function closeAll()
{
foreach ($this->dccList AS $dcc)
{
$dcc->disconnect("Owner Requsted Close");
}
}
public function addBytesUp($num)
{
$this->bytesUp += $num;
}
public function addBytesDown($num)
{
$this->bytesDown += $num;
}
public function getBytesDown()
{
return $this->bytesDown;
}
public function getBytesUp()
{
return $this->bytesUp;
}
public function getDcc($someDcc)
{
if (isset($this->dccList[$someDcc]))
{
return $this->dccList[$someDcc];
}
return false;
}
public function dccInform($data, $from = null)
{
foreach ($this->dccList AS $dcc)
{
if ($dcc->type == CHAT && $dcc->verified == true && $dcc->isAdmin == true)
{
if ($from != null)
{
if ($dcc->sockInt != $from->sockInt)
{
$dcc->dccSend($data);
}
}
else
{
$dcc->dccSend($data);
}
}
}
}
//Works in conjunction with $oldConn->connected
public function accepted($oldConn, $newConn)
{
$sockInt = $oldConn->getSockInt();
$hasAccepted = $newConn->getSockInt();
$dcc = $this->dccList[$sockInt];
$this->dccList[$hasAccepted] = $dcc;
$dcc->status = DCC_CONNECTED;
$dcc->sockInt = $hasAccepted;
unset($this->dccList[$sockInt]);
}
//CheckDccTimeout function
public function checkDccTimeout($dcc)
{
if (!is_object($dcc) || $dcc->removed == true)
{
return false;
}
if ($dcc->status != DCC_LISTENING)
{
return false;
}
switch ($dcc->timeOutLevel)
{
case 0:
$dcc->timeOutLevel++;
break;
case 1:
$dcc->timeOutLevel++;
$this->ircClass->notice($dcc->nick, "You have a DCC session pending. Set your client to connect. 60 seconds before timeout.", 1);
break;
case 2:
$dcc->timeOutLevel++;
$this->ircClass->notice($dcc->nick, "You have a DCC session pending. Set your client to connect. 30 seconds before timeout.", 1);
break;
case 3:
$dcc->timeOutLevel = 0;
$dcc->disconnect("DCC Session timed out (90 Seconds)");
return false;
break;
default:
break;
}
return true;
}
public function getDccList()
{
return $this->dccList;
}
private function removeDcc($dcc)
{
$sockInt = $dcc->sockInt;
unset($this->dccList[$sockInt]);
}
public function dccSend($to, $data)
{
if (($len = $this->socketClass->sendSocket($to->sockInt, $data)) === false)
{
$to->disconnect();
}
return $len;
}
private function highestId()
{
$highest = 0;
foreach ($this->dccList AS $index => $dcc)
{
$highest = ($dcc->id > $highest ? $dcc->id : $highest);
}
return $highest + 1;
}
public function addChat($nick, $host, $port, $admin, $handler, $fromTimer = false)
{
$lnick = irc::myStrToLower($nick);
foreach ($this->dccList AS $index => $dcc)
{
if ($dcc->type == CHAT)
{
if (irc::myStrToLower($dcc->nick) == $lnick)
{
$dcc->disconnect();
break;
}
}
}
$reverse = false;
if ($this->ircClass->getClientConf("mircdccreverse") != "" && $fromTimer == false)
{
$port = intval($this->ircClass->getClientConf("mircdccreverse"));
if ($port == 0)
{
return NULL;
}
$args = new argClass;
$args->arg1 = $nick;
$args->arg2 = $host;
$args->arg3 = $port;
$args->arg4 = $admin;
$args->arg5 = $handler;
$args->arg7 = time();
$args->arg8 = CHAT;
$this->ircClass->notice($nick, "DCC: NOTICE: This server is using the mIRC Chat Server Protocol. Please use ' /dccserver +c on " . $this->ircClass->getClientConf("mircdccreverse") . " ' to chat with me! Starting 6 second delay...", 0);
$this->ircClass->sendRaw("WHOIS " . $nick);
$this->timerClass->addTimer(irc::randomHash(), $this, "reverseTimer", $args, 6, false);
return;
}
if ($fromTimer == true)
{
$reverse = DCC_REVERSE; // using mIRC dcc reverse protocol
}
if ($host == NULL || $port == NULL)
{
$conn = new connection(null, null, 0);
$listening = true;
$status = DCC_LISTENING;
}
else
{
$conn = new connection($host, $port, CONNECT_TIMEOUT);
$listening = false;
$status = DCC_CONNECTING;
}
$conn->setSocketClass($this->socketClass);
$conn->setIrcClass($this->ircClass);
$conn->setCallbackClass($this);
$conn->setTimerClass($this->timerClass);
$port = $conn->init();
if ($conn->getError())
{
$this->ircClass->log("Start Chat Error: " . $conn->getErrorMsg());
return false;
}
$sockInt = $conn->getSockInt();
$this->chatCount++;
$id = $this->highestId();
$chat = new chat($id, $nick, $admin, $sockInt, $host, $port, $handler, $reverse);
$chat->setIrcClass($this->ircClass);
$chat->setDccClass($this);
$chat->setParserClass($this->parserClass);
$chat->setSocketClass($this->socketClass);
$chat->setTimerClass($this->timerClass);
$chat->connection = $conn;
$chat->status = $status;
$chat->removed = false;
$this->dccList[$sockInt] = $chat;
$chat->initialize();
$conn->setCallbackClass($chat);
if ($listening == true)
{
$this->timerClass->addTimer(irc::randomHash(), $this, "checkDccTimeout", $chat, 30, true);
}
else
{
$conn->connect();
}
return $port;
}
public function addFile($nick, $host, $port, $type, $filename, $size, $fromTimer = false) // <-- ignore fromTimer, it is sent by reverseTimer() above
{
$reverse = false;
if ($this->ircClass->getClientConf("mircdccreverse") != "" && $fromTimer == false && $type != DOWNLOAD)
{
$port = intval($this->ircClass->getClientConf("mircdccreverse"));
if ($port == 0)
{
return NULL;
}
$args = new argClass;
$args->arg1 = $nick;
$args->arg2 = $host;
$args->arg3 = $port;
$args->arg4 = $type;
$args->arg5 = $filename;
$args->arg6 = $size;
$args->arg7 = time();
$args->arg8 = FILE;
$this->ircClass->notice($nick, "DCC: NOTICE: This server is using the mIRC File Server Protocol. Please use ' /dccserver +s on " . $this->ircClass->getClientConf("mircdccreverse") . " ' to recieve files from me! Starting 6 second delay...", 0);
$this->ircClass->sendRaw("WHOIS " . $nick);
$this->timerClass->addTimer(irc::randomHash(), $this, "reverseTimer", $args, 6);
return;
}
if ($fromTimer == true)
{
$reverse = DCC_REVERSE; // using mIRC dcc reverse protocol
}
if ($host == NULL || $port == NULL)
{
$conn = new connection(null, null, 0);
$listening = true;
$status = DCC_LISTENING;
}
else
{
$conn = new connection($host, $port, CONNECT_TIMEOUT);
$listening = false;
$status = DCC_CONNECTING;
}
$conn->setSocketClass($this->socketClass);
$conn->setIrcClass($this->ircClass);
$conn->setCallbackClass($this);
$conn->setTransTimeout(30);
$conn->setTimerClass($this->timerClass);
$port = $conn->init();
if ($conn->getError())
{
$this->ircClass->log("File transfer start error: " . $conn->getErrorMsg());
return false;
}
$sockInt = $conn->getSockInt();
$id = $this->highestId();
$file = new file($id, $nick, $sockInt, $host, $port, $type, $reverse);
if ($file->transferType == UPLOAD)
{
$this->fileUlCount++;
}
else
{
$this->fileDlCount++;
}
$file->setIrcClass($this->ircClass);
$file->setDccClass($this);
$file->setSocketClass($this->socketClass);
$file->setProcQueue($this->procQueue);
$file->setTimerClass($this->timerClass);
$file->connection = $conn;
$file->status = $status;
$file->removed = false;
$this->dccList[$sockInt] = $file;
$file->initialize($filename, $size);
$conn->setCallbackClass($file);
if ($listening == true)
{
$this->timerClass->addTimer(irc::randomHash(), $this, "checkDccTimeout", $file, 30, true);
}
if ($reverse == true)
{
$conn->connect();
}
return $port;
}
public function alterSocket($sockInt, $level, $opt, $val)
{
return $this->socketClass->alterSocket($sockInt, $level, $opt, $val);
}
public function reverseTimer($args)
{
$memData = $this->ircClass->getUserData($args->arg1);
if ($memData == NULL || ($memData->host == "" || $memData->host == NULL))
{
$this->ircClass->notice($args->arg1, "DCC: ERROR: Couldn't resolve your hostname. Try again?");
}
else
{
if ($args->arg8 == FILE)
{
$this->addFile( $args->arg1,
$memData->host,
$this->ircClass->getClientConf("mircdccreverse"),
$args->arg4,
$args->arg5,
$args->arg6,
true);
}
else
{
$this->addChat( $args->arg1,
$memData->host,
$this->ircClass->getClientConf("mircdccreverse"),
$args->arg4,
$args->arg5,
true);
}
}
return false;
}
public function sendFile($nick, $file)
{
return $this->addFile($nick, null, null, UPLOAD, $file, NULL);
}
public function dccResume($port, $size)
{
foreach ($this->dccList AS $dcc)
{
if ($dcc->type == FILE)
{
if ($dcc->port == $port)
{
$dcc->resume($size);
break;
}
}
}
}
public function dccAccept($port)
{
foreach ($this->dccList AS $dcc)
{
if ($dcc->type == FILE)
{
if ($dcc->port == $port)
{
$dcc->accepted();
break;
}
}
}
}
public function disconnect($dcc)
{
switch ($dcc->type)
{
case CHAT:
$this->chatCount--;
break;
case FILE:
switch($dcc->transferType)
{
case UPLOAD:
$this->fileUlCount--;
break;
case DOWNLOAD:
$this->fileDlCount--;
break;
}
break;
default:
break;
}
$dcc->removed = true;
$dcc->connection->disconnect();
$this->removeDcc($dcc);
return true;
}
}
?>

314
ircbot/defines.php Normal file
View file

@ -0,0 +1,314 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > defines module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
// Debug Mode
define('DEBUG', 1);
// PID file
define('PID', config::$main['cs_path'] . "/ircbot.pid");
// OS Type (windows/unix/linux/freebsd/unknown/auto)
define('OS', 'auto');
//YOU SHOULD NOT HAVE TO EDIT BELOW THIS POINT UNLESS YOU SPECIFY "unknown" AS OS!
if (OS == "auto")
{
switch (PHP_OS)
{
case "Windows NT":
$OS = "windows";
break;
case "Linux":
$OS = "linux";
break;
case "FreeBSD":
$OS = "freebsd";
break;
case "Unix":
$OS = "unix";
break;
//Thx OrochiTux for below
case "Darwin":
$OS = "freebsd";
break;
default:
$OS = "windows";
break;
}
}
else
{
$OS = OS;
}
if ($OS == 'unknown')
{
define('EAGAIN', 0); /* Try again */
define('EISCONN', 0); /* Transport endpoint is already connected */
define('EALREADY', 0); /* Operation already in progress */
define('EINPROGRESS', 0); /* Operation now in progress */
}
else if ($OS == 'windows')
{
//http://developer.novell.com/support/winsock/doc/appenda.htm
define('EAGAIN', 10035); //EWOULDBLOCK.. kinda like EAGAIN in windows?
define('EISCONN', 10056); /* Transport endpoint is already connected */
define('EALREADY', 10037); /* Operation already in progress */
define('EINPROGRESS', 10036); /* Operation now in progress */
}
else if ($OS == 'freebsd')
{
//Thanks to ryguy@efnet
///usr/include/errno.h (freebsd)
define('EAGAIN', 35); /* Try again */
define('EISCONN', 56); /* Transport endpoint is already connected */
define('EALREADY', 37); /* Operation already in progress */
define('EINPROGRESS', 36); /* Operation now in progress */
}
else if ($OS == 'linux')
{
///usr/include/sys/errno.h (sparc)
define('EAGAIN', 11); /* Try again */
define('EISCONN', 106); /* Transport endpoint is already connected */
define('EALREADY', 114); /* Operation already in progress */
define('EINPROGRESS', 115); /* Operation now in progress */
}
else if ($OS == 'unix')
{
///usr/include/asm/errno.h (mandrake 9.0)
define('EAGAIN', 11); /* Try again */
define('EISCONN', 133); /* Transport endpoint is already connected */
define('EALREADY', 149); /* Operation already in progress */
define('EINPROGRESS', 150); /* Operation now in progress */
}
// Version Definition
define('VERSION', '2.2.1');
define('VERSION_DATE', '04/08/06');
// Timer declarations
define('NICK_CHECK_TIMEOUT', 120); //seconds
define('CHAN_CHECK_TIMEOUT', 60); //seconds
define('PING_TIMEOUT', 130); //seconds (check every 130 seconds if we're still connected)
// Parser definitions
define('MAX_ARGS', 4);
// Status definitions
define('STATUS_IDLE', 0);
define('STATUS_ERROR', 1);
define('STATUS_CONNECTING', 2);
define('STATUS_CONNECTED', 3);
define('STATUS_CONNECTED_SENTREGDATA', 4);
define('STATUS_CONNECTED_REGISTERED', 5);
// Constant Definitions
define('ERROR_TIMEOUT', 60);
define('CONNECT_TIMEOUT', 45);
define('REGISTRATION_TIMEOUT', 60);
define('TIMEOUT_CHECK_TIME', 85); //85
//Constants for Channel Modes
define('BY_MASK', 0);
define('BY_STRING', 1);
define('BY_INT', 2);
define('BY_NONE', 3);
//Used with $ircClass->parseMode
define('USER_MODE', 0);
define('CHANNEL_MODE', 1);
//Random Vars
define('STATUS_JUST_BANNED', 1);
define('STATUS_ALREADY_BANNED', 2);
define('STATUS_NOT_BANNED', 3);
//Socket Class defines
define('SOCK_DEAD', 1);
define('SOCK_CONNECTING', 2);
define('SOCK_LISTENING', 3);
define('SOCK_ACCEPTED', 4);
define('SOCK_ACCEPTING', 5);
define('SOCK_CONNECTED', 6);
define('HIGHEST_PORT', 1000); // this is tcpRangeStart + HIGHEST_PORT
//DCC Class defines
define('FILE', 0);
define('CHAT', 1);
define('DCC_WAITING', 3);
define('DCC_REVERSE', 4);
define('DCC_CONNECTING', 0);
define('DCC_CONNECTED', 1);
define('DCC_LISTENING', 2);
//Connection class defines
define('CONN_READ', 0);
define('CONN_WRITE', 1);
define('CONN_ACCEPT', 2);
define('CONN_CONNECT', 3);
define('CONN_DEAD', 4);
define('CONN_CONNECT_TIMEOUT', 5);
define('CONN_TRANSFER_TIMEOUT', 6);
//Parser Class defines
define('BRIGHT', chr(3) . "13");
define('DARK', chr(3) . "03");
define('NORMAL', chr(16));
define('BOLD', chr(2));
define('UNDERLINE', chr(31));
define('PRIV', 1);
define('DCC', 2);
//File Class defines
define('UPLOAD', 0);
define('DOWNLOAD', 1);
//Used with $ircClass->addQuery
define('QUERY_SUCCESS', 0);
define('QUERY_ERROR', 1);
//Used in ini
define('EXACT_MATCH', 0);
define('AND_MATCH', 1);
define('OR_MATCH', 2);
define('CONTAINS_MATCH', 3);
//Used in socket class to keep track of sockets
class socketInfo {
public $socket;
public $status;
public $readQueue;
public $readLength;
public $writeQueue;
public $writeLength;
public $host;
public $port;
public $newSockInt;
public $listener;
public $owner;
public $class;
public $func;
public $readScheduled; //Used so we don't add infinite queues to the process queue.
public $writeScheduled;
}
//Channel and Username Linked List (Links) Definitions
class channelLink {
public $name;
public $count;
public $memberList = array();
public $banList = array();
public $whoComplete;
public $banComplete;
public $modes;
public $created;
public $topic;
public $topicBy;
}
class memberLink {
public $nick;
public $realNick;
public $host;
public $ident;
public $banned;
public $bantime;
public $status;
public $ignored;
}
// Used in timer class
class timer {
public $name;
public $class;
public $args;
public $interval;
public $lastTimeRun;
public $nextRunTime;
public $func;
}
class usageLink {
public $isBanned;
public $timeBanned;
public $lastTimeUsed;
public $timesUsed;
}
// Useful for sending arguments with timers
class argClass
{
public $arg1;
public $arg2;
public $arg3;
public $arg4;
public $arg5;
public $arg6;
public $arg7;
public $arg8;
public $timer;
}
// Used to instantiate a bot
class botClass {
public $timerClass;
public $ircClass;
public $dccClass;
public $parserClass;
public $socketClass;
public $configFilename;
public $db;
public $config;
}
// Used with processQueue
class queueItem {
public $owner; //IRC Class of owner
public $callBack_class; //CALL BACK class/function to use
public $callBack_function;
public $nextRunTime; //The next getMicroTime() time to run
public $removed;
public $next;
public $prev;
}
?>

107
ircbot/error.php Normal file
View file

@ -0,0 +1,107 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > error module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class ConnectException extends Exception {
private $exceptionTime = 0;
function __construct($message)
{
parent::__construct($message);
$this->exceptionTime = time();
}
function getTime()
{
return $this->exceptionTime;
}
}
class SendDataException extends Exception {
private $exceptionTime = 0;
function __construct($message)
{
parent::__construct($message);
$this->exceptionTime = time();
}
function getTime()
{
return $this->exceptionTime;
}
}
class ConnectionTimeout extends Exception {
private $exceptionTime = 0;
function __construct($message)
{
parent::__construct($message);
$this->exceptionTime = time();
}
function getTime()
{
return $this->exceptionTime;
}
}
class ReadException extends Exception {
private $exceptionTime = 0;
function __construct($message)
{
parent::__construct($message);
$this->exceptionTime = time();
}
function getTime()
{
return $this->exceptionTime;
}
}
?>

663
ircbot/file.php Normal file
View file

@ -0,0 +1,663 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > dcc chat module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class file {
/* Chat specific Data */
public $id;
public $status;
public $sockInt;
public $timeConnected;
public $readQueue;
public $port;
public $dccString;
public $type;
public $transferType;
public $nick;
public $timeOutLevel;
public $removed;
public $connection;
public $reverse; // reverse dcc?
private $handShakeSent;
private $handShakeTime;
public $filename;
public $filenameNoDir;
public $filePointer;
public $filesize;
public $bytesTransfered;
public $resumedSize;
public $completed;
public $reportedRecieved;
public $connectHost;
//private $resumed;
private $started;
private $sendQueue;
private $sendQueueCount;
//keep track of speed;
private $speed_sec_add;
public $speed_lastavg;
private $speed_starttime;
/* Classes */
private $dccClass;
private $ircClass;
private $socketClass;
private $procQueue;
private $timerClass;
/* Constructor */
public function __construct($id, $nick, $sockInt, $host, $port, $type, $reverse)
{
$this->id = $id;
$this->nick = $nick;
$this->sockInt = $sockInt;
$this->connectHost = $host;
$this->port = $port;
$this->transferType = $type;
$this->filesize = 0;
$this->bytesTransfered = 0;
$this->resumedSize = 0;
$this->started = false;
$this->status = DCC_WAITING;
$this->reverse = $reverse;
$this->handShakeSent = false;
$this->speed_sec_add = 0;
$this->speed_lastavg = 0;
$this->speed_starttime = 0;
if ($type == UPLOAD)
{
$this->dccString = "DCC UPLOAD[".$this->id."]: ";
}
else
{
$this->dccString = "DCC DOWNLOAD[".$this->id."]: ";
}
}
public function setProcQueue($class)
{
$this->procQueue = $class;
}
public function setSocketClass($class)
{
$this->socketClass = $class;
}
public function setIrcClass($class)
{
$this->ircClass = $class;
}
public function setTimerClass($class)
{
$this->timerClass = $class;
}
public function setDccClass($class)
{
$this->dccClass = $class;
}
public function dccSend($data)
{
return $this->dccClass->dccSend($this, $data);
}
public function disconnect($msg = "")
{
$msg = str_replace("\r", "", $msg);
$msg = str_replace("\n", "", $msg);
if ($this->started == true)
{
fclose($this->filePointer);
}
if ($msg != "")
{
$this->dccClass->dccInform($this->dccString . "DCC session ended with " . $this->nick . " (" . $msg . ")", $this);
$this->ircClass->notice($this->nick, "DCC session ended: " . $msg, 1);
}
else
{
$this->dccClass->dccInform($this->dccString . "DCC session ended with " . $this->nick, $this);
}
$this->status = false;
$this->dccClass->disconnect($this);
$this->connection = null;
return true;
}
function xferUpload()
{
while ($this->readQueue != "")
{
$unsignedLong = substr($this->readQueue, 0, 4);
if (strlen($unsignedLong) < 4)
{
break;
}
$sizeArray = unpack("N", $unsignedLong);
$this->reportedRecieved = $sizeArray[1];
$this->readQueue = substr($this->readQueue, 4);
}
if ($this->completed == 1)
{
if ($this->reportedRecieved >= $this->filesize)
{
$avgspeed = "";
if ($this->speed_lastavg != 0)
{
$size = irc::intToSizeString($this->speed_lastavg);
$avgspeed = " (" . $size . "/s)";
}
$totalTime = $this->ircClass->timeFormat(time() - $this->timeConnected, "%h hrs, %m min, %s sec");
$size = irc::intToSizeString($this->bytesTransfered - $this->resumedSize);
$this->disconnect("Transfer Completed, Sent " . $size . " in " . $totalTime . $avgspeed);
}
return;
}
if ($this->status != DCC_CONNECTED)
{
return;
}
if ($this->socketClass->hasWriteQueue($this->sockInt))
{
return;
}
if ($this->bytesTransfered >= $this->filesize)
{
$this->completed = 1;
return;
}
if (time() >= $this->speed_starttime + 3)
{
$this->speed_lastavg = $this->speed_sec_add / 3.0;
$this->speed_sec_add = 0;
$this->speed_starttime = time();
}
if (!is_resource($this->filePointer))
{
$this->disconnect("File pointer is not a resource");
return;
}
for ($i = 0; $i < 30; $i++)
{
if (($data = fread($this->filePointer, 4096)) === false)
{
$this->disconnect("Read error: Could not access file");
return;
}
$this->dccSend($data);
$dataSize = strlen($data);
$this->bytesTransfered += $dataSize;
$this->dccClass->addBytesUp($dataSize);
$this->speed_sec_add += $dataSize;
if ($this->socketClass->hasWriteQueue($this->sockInt))
{
break;
}
}
}
function xferDownload()
{
if ($this->status != DCC_CONNECTED)
{
return;
}
$readQueueSize = strlen($this->readQueue);
if ($readQueueSize <= 0)
{
return;
}
if (fwrite($this->filePointer, $this->readQueue, $readQueueSize) === false)
{
$this->disconnect("Write error: Could not access file");
}
$this->speed_sec_add += $readQueueSize;
$this->dccClass->addBytesDown($readQueueSize);
$this->bytesTransfered += $readQueueSize;
$this->readQueue = "";
$this->dccSend(pack("N", $this->bytesTransfered));
if ($this->bytesTransfered >= $this->filesize)
{
$avgspeed = "";
if ($this->speed_lastavg != 0)
{
$size = irc::intToSizeString($this->speed_lastavg);
$avgspeed = " (" . $size . "/s)";
}
$totalTime = $this->ircClass->timeFormat(time() - $this->timeConnected, "%h hrs, %m min, %s sec");
$size = irc::intToSizeString($this->bytesTransfered - $this->resumedSize);
$this->disconnect("Transfer Completed, Recieved " . $size . " in " . $totalTime . $avgspeed);
}
if (time() >= $this->speed_starttime + 3)
{
$this->speed_lastavg = $this->speed_sec_add / 3.0;
$this->speed_sec_add = 0;
$this->speed_starttime = time();
}
}
private function doHandShake()
{
$this->dccSend("120 ".$this->ircClass->getNick()." ".$this->filesize." ".$this->filenameNoDir."\n");
$this->handShakeSent = true;
$this->timerClass->addTimer(irc::randomHash(), $this, "handShakeTimeout", "", 8);
}
private function processHandShake()
{
if ($this->readQueue == "")
{
return;
}
$response = $this->readQueue;
$this->readQueue = "";
$responseArray = explode(chr(32), $response);
if ($responseArray[0] == "121")
{
$this->resumedSize = intval($responseArray[2]);
$this->reverse = false;
$this->onConnect($conn);
return;
}
$this->disconnect("DCC Client Server reported error on attempt to send file");
}
public function handShakeTimeout()
{
if ($this->status != false)
{
if ($this->reverse == true)
{
$this->disconnect("DCC Reverse handshake timed out");
}
}
return false;
}
/* Main events */
public function onDead($conn)
{
if ($this->completed == 1)
{
$avgspeed = "";
if ($this->speed_lastavg != 0)
{
$size = irc::intToSizeString($this->speed_lastavg);
$avgspeed = " (" . $size . "/s)";
}
$totalTime = $this->ircClass->timeFormat(time() - $this->timeConnected, "%h hrs, %m min, %s sec");
$size = irc::intToSizeString($this->bytesTransfered - $this->resumedSize);
$this->disconnect("Transfer Completed, Sent " . $size . " in " . $totalTime . $avgspeed);
}
else
{
$this->disconnect($this->connection->getErrorMsg());
}
}
public function onRead($conn)
{
$this->readQueue .= $this->socketClass->getQueue($this->sockInt);
if ($this->status == DCC_CONNECTED)
{
if ($this->transferType == UPLOAD)
{
if ($this->reverse != false)
{
if ($this->handShakeSent != false)
{
$this->processHandShake();
}
}
}
else
{
$this->xferDownload();
}
}
return false;
}
public function onWrite($conn)
{
if ($this->status == DCC_CONNECTED && $this->reverse == false)
{
$this->xferUpload();
}
}
public function onAccept($oldConn, $newConn)
{
$this->dccClass->accepted($oldConn, $newConn);
$this->connection = $newConn;
$oldConn->disconnect();
$this->sockInt = $newConn->getSockInt();
$this->onConnect($newConn);
}
public function onTransferTimeout($conn)
{
$this->disconnect("Transfer timed out");
}
public function onConnectTimeout($conn)
{
$this->disconnect("Connection attempt timed out");
}
public function onConnect($conn)
{
$this->status = DCC_CONNECTED;
$this->dccClass->dccInform($this->dccString . $this->nick . " connection established");
if ($this->reverse != false)
{
$this->doHandShake();
return;
}
if ($this->transferType == UPLOAD)
{
$this->dccClass->alterSocket($this->sockInt, SOL_SOCKET, SO_SNDBUF, 32768);
$this->filePointer = fopen($this->filename, "rb");
if ($this->filePointer === false)
{
$this->disconnect("Error opening local file for reading");
return;
}
if ($this->resumedSize > 0)
{
if (fseek($this->filePointer, $this->resumedSize, SEEK_SET) == -1)
{
$this->disconnect("Error seeking to resumed file position in file");
return;
}
}
$this->xferUpload();
}
else
{
$this->dccClass->alterSocket($this->sockInt, SOL_SOCKET, SO_RCVBUF, 32768);
$this->filePointer = fopen($this->filename, "ab");
$this->ircClass->notice($this->nick, "DCC: Upload connection established", 0);
if ($this->filePointer === false)
{
$this->disconnect("Error opening local file for writing");
return;
}
}
$this->started = true;
$this->speed_starttime = time();
}
public function initialize($filename, $size = 0)
{
$this->reportedRecieved = 0;
$this->completed = 0;
$this->filesize = $size;
$this->timeConnected = time();
$this->timeOutLevel = 0;
$this->readQueue = "";
$this->type = FILE;
if ($this->transferType == UPLOAD)
{
$this->filename = $filename;
if (strpos($filename, "/") !== false)
{
$filenameArray = explode("/", $filename);
$this->filenameNoDir = $filenameArray[count($filenameArray) - 1];
}
else if (strpos($filename, "\\") !== false)
{
$filenameArray = explode("\\", $filename);
$this->filenameNoDir = $filenameArray[count($filenameArray) - 1];
}
else
{
$this->filenameNoDir = $filename;
}
$this->filenameNoDir = $this->cleanFilename($this->filenameNoDir);
$this->dccClass->dccInform($this->dccString . "Initiating file transfer of (".$this->filenameNoDir.") to " . $this->nick);
if (!$this->file_exists($this->filename))
{
$this->disconnect("File does not exist");
return;
}
$fileSize = $this->filesize($this->filename);
if ($fileSize === false)
{
$this->disconnect("File does not exist");
return;
}
$this->filesize = $fileSize;
$kbSize = irc::intToSizeString($fileSize);
if ($this->reverse == false)
{
$this->ircClass->privMsg($this->nick, "\1DCC SEND " . $this->filenameNoDir . " " . $this->ircClass->getClientIP(1) . " " . $this->port . " " . $fileSize . "\1", 0);
}
$this->ircClass->notice($this->nick, "DCC: Sending you (\"" . $this->filenameNoDir . "\") which is " . $kbSize . " (resume supported)", 0);
}
else
{
$uldir = $this->ircClass->getClientConf('uploaddir');
$lastChar = substr($uldir, strlen($uldir) - 1, 1);
if ($lastChar != "\\" || $lastChar != "/")
{
$uldir .= "/";
}
$filename = $this->cleanFilename($filename);
$this->filename = $uldir . $filename;
$this->dccClass->dccInform($this->dccString . "Initiating file transfer of (".$filename.") from " . $this->nick);
if ($this->file_exists($this->filename))
{
$bytesFinished = $this->filesize($this->filename);
if ($bytesFinished >= $this->filesize)
{
$this->disconnect("Connection aborted. I already have that file.");
return;
}
else
{
$this->status = DCC_WAITING;
$this->bytesTransfered = $bytesFinished;
$this->resumedSize = $bytesFinished;
$this->ircClass->privMsg($this->nick, "\1DCC RESUME file.ext " . $this->port . " " . $bytesFinished . "\1", 0);
}
return;
}
$this->ircClass->notice($this->nick, "DCC: Upload accepted, connecting to you (" . $this->connectHost . ") on port " . $this->port . ".",0);
$this->status = DCC_CONNECTING;
$this->connection->connect();
}
}
public function accepted()
{
$this->status = DCC_CONNECTING;
$this->connection->connect();
}
public function resume($size)
{
$this->resumedSize = $size;
$this->bytesTransfered = $size;
$resumePlace = round($size / 1000, 0);
$this->dccClass->dccInform($this->dccString . "Resumed at " . $resumePlace . "K");
$this->ircClass->privMsg($this->nick, "\1DCC ACCEPT file.ext " . $this->port . " " . $size . "\1", 0);
}
public static function cleanFilename($filename)
{
$filename = str_replace("..", "__", $filename);
$filename = str_replace(chr(47), "_", $filename);
$filename = str_replace(chr(92), "_", $filename);
$filename = str_replace(chr(58), "_", $filename);
$filename = str_replace(chr(63), "_", $filename);
$filename = str_replace(chr(34), "_", $filename);
$filename = str_replace(chr(62), "_", $filename);
$filename = str_replace(chr(60), "_", $filename);
$filename = str_replace(chr(124), "_", $filename);
$filename = str_replace(chr(32), "_", $filename);
return $filename;
}
private function file_exists($filename)
{
$fp = @fopen($filename, "rb");
if ($fp === false)
{
return false;
}
else
{
fclose($fp);
return true;
}
}
private function filesize($filename)
{
$fp = @fopen($filename, "rb");
if ($fp === false)
{
return false;
}
else
{
$fstat = fstat($fp);
fclose($fp);
return $fstat['size'];
}
}
}
?>

58
ircbot/function.conf Normal file
View file

@ -0,0 +1,58 @@
;+---------------------------------------------------------------------------
;| PHP-IRC v2.2.1 Service Release
;| =======================================================
;| by Manick
;| (c) 2001-2006 by http://www.phpbots.org/
;| Contact: manick@manekian.com
;| irc: #manekian@irc.rizon.net
;| ========================================
;| Special Contributions were made by:
;| cortex
;+---------------------------------------------------------------------------
;| > Function File
;+---------------------------------------------------------------------------
;| > 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.
;+---------------------------------------------------------------------------
;| Changes
;| =======-------
;| > If you wish to suggest or submit an update/change to the source
;| > code, email me at manick@manekian.com with the change, and I
;| > will look to adding it in as soon as I can.
;+---------------------------------------------------------------------------
; some notes:
; the ~ operater spans definitions over multiple lines. the ; operator
; denotes a comment. it can be placed anywhere. you must escape
; your single quotes in quoted entries with a backslash \. the first
; type of every statement is explained
; NOTE: as of 2.2.0, all function configuration was moved to specific files using
; the 'include' function. General type definitions can be found in typedefs.conf
include typedefs.conf
include modules/lw/lw_mod.conf
;include modules/default/priv_mod.conf
;include modules/default/dcc_mod.conf
;include modules/bad_words/bad_words.conf
;include modules/peak_mod/peak_mod.conf
;include modules/seen/seen_mod.conf
;include modules/news/news_mod.conf
;include modules/imdb/imdb_mod.conf
;include modules/quotes_ini/quote_mod.conf
;include modules/quotes_sql/quote_mod.conf
;include modules/httpd/httpd_mod.conf
;include modules/fileserver/fileserver.conf
;include modules/bash/bash_mod.conf

2501
ircbot/irc.php Normal file

File diff suppressed because it is too large Load diff

126
ircbot/module.php Normal file
View file

@ -0,0 +1,126 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > module class
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
abstract class module {
public $title = "<title>";
public $author = "<author>";
public $version = "<version>";
public $dontShow = false;
public $ircClass;
public $dccClass;
public $timerClass;
public $parserClass;
public $socketClass;
public $db;
public function __construct()
{
//Nothing here...
}
public function __destruct()
{
$this->ircClass = null;
$this->dccClass = null;
$this->timerClass = null;
$this->parserClass = null;
$this->socketClass = null;
$this->db = null;
//Nothing here
}
public final function __setClasses($ircClass, $dccClass, $timerClass, $parserClass,
$socketClass, $db)
{
$this->ircClass = $ircClass;
$this->dccClass = $dccClass;
$this->timerClass = $timerClass;
$this->parserClass = $parserClass;
$this->socketClass = $socketClass;
$this->db = $db;
}
public final function getModule($modName)
{
$mods = $this->parserClass->getCmdList("file");
if ($mods === false)
{
return false;
}
if (isset($mods[$modName]))
{
return $mods[$modName]['class'];
}
return false;
}
public function handle($chat, $args)
{
}
public function connected($chat)
{
}
public function main($line, $args)
{
$port = $this->dccClass->addChat($line['fromNick'], null, null, false, $this);
if ($port === false)
{
$this->ircClass->notice($line['fromNick'], "Error starting chat, please try again.", 1);
}
}
public function init()
{
//Global.. this needs to be overwritten
}
public function destroy()
{
//Global.. this needs to be overwritten
}
}
?>

View file

View file

@ -0,0 +1,81 @@
;+---------------------------------------------------------------------------
;| PHP-IRC Internal DCC Function Configuration File
;| ========================================================
;| by Manick
;| (c) 2001-2004 by http://phpbots.sf.net
;| Contact: manick@manekian.com
;| irc: #manekian@irc.rizon.net
;| ========================================
;+---------------------------------------------------------------------------
;| > 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.
;+---------------------------------------------------------------------------
file dcc_mod modules/default/dcc_mod.php
privmsg dcc_mod monitor_check
mode dcc_mod monitor_check
join dcc_mod monitor_check
kick dcc_mod monitor_check
part dcc_mod monitor_check
;new feature in 2.2.0, section definitions
section standard "Standard Functions"
section channel "Channel Functions"
section dcc "DCC Functions"
section info "Information Functions"
section admin "Administrative Functions"
section comm "IRC/Communication Functions"
dcc monitor ~; command text (typed in dcc iface)
0 ~; number of required arguments
"<channel>" ~; argument descriptions <arg1> <arg2> (or however you damn well please to do it hehe ;)
"Show messages from channel in dcc chat interface" ~; description of command
true ~; must be admin to use this command?
dcc_mod ~; class name (see file import section above)
dcc_monitor ~; function name
channel ; section name
dcc exit 0 "" "Exits the DCC interface" false dcc_mod dcc_exit standard
dcc raw 1 "<raw query>" "Sends raw query to server" true dcc_mod dcc_raw comm
dcc who 0 "" "See who\'s online" false dcc_mod dcc_who standard
dcc ignore 0 "" "View ignore list" true dcc_mod dcc_ignore admin
dcc rignore 1 "<host>" "Remove ignore for a specified host" true dcc_mod dcc_rignore admin
dcc clearqueue 0 "<user>" "Removes all text queues, or queues for a specified user." true dcc_mod dcc_clearqueue admin
dcc server 1 "<server> <port>" "Change server to specified server" true dcc_mod dcc_server admin
dcc chat 1 "<text>" "Sends message to all admin users using the DCC interface" true dcc_mod dcc_chat comm
dcc restart 0 "" "Reconnect to the current server" true dcc_mod dcc_restart admin
dcc say 2 "<channel> <text>" "Sends text to some channel" true dcc_mod dcc_say comm
dcc action 2 "<channel> <text>" "Sends text to some channel in /me format" true dcc_mod dcc_action comm
dcc users 0 "" "Shows users in all channels" true dcc_mod dcc_users info
dcc maintain 0 "<channel> <key>" "Shows maintained channels, and adds or removes one" true dcc_mod dcc_maintain channel
dcc help 0 "" "Get information about command(s)" false dcc_mod dcc_help standard
dcc join 1 "<channel>" "Join a channel" true dcc_mod dcc_join channel
dcc part 1 "<channel>" "Part a channel" true dcc_mod dcc_part channel
dcc rejoin 1 "<channel>" "Rejoin a channel" true dcc_mod dcc_rejoin channel
dcc status 0 "" "Get status of bot, same as 5 minute status update" true dcc_mod dcc_status info
dcc function 0 "<activate/deactivate> <function>" "See which functions are activated, or activate/deactivate a function" true dcc_mod dcc_function admin
dcc reloadfunc 0 "" "Reloads function definition file" true dcc_mod dcc_reloadfunc admin
dcc shutdown 0 "" "Shuts the bot down" true dcc_mod dcc_shutdown admin
dcc connect 0 "" "Force connection to server when disconnected" true dcc_mod dcc_connect admin
dcc rehash 0 "" "Reload the configuration file" true dcc_mod dcc_rehash admin
dcc send 2 "<nick> <file>" "Send a user a file" true dcc_mod dcc_send dcc
dcc dcc 0 "" "Check current dcc status" true dcc_mod dcc_dccs dcc
dcc close 1 "<id>" "Close a download, upload, or chat window" true dcc_mod dcc_close dcc
dcc upload 1 "<yes/no>" "Allow files to be sent to this bot" true dcc_mod dcc_upload dcc
dcc botinfo 0 "" "View information about the bot" true dcc_mod dcc_botinfo info
dcc timers 0 "" "View active timer information" true dcc_mod dcc_timers info
dcc listul 0 "" "List upload directory contents" true dcc_mod dcc_listul dcc
dcc modules 0 "" "List installed modules" true dcc_mod dcc_modules info
dcc spawn 1 "<config file>" "Spawn a new bot in this process" true dcc_mod dcc_spawn admin

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
;+---------------------------------------------------------------------------
;| PHP-IRC Internal PRIVMSG Function Configuration File
;| ========================================================
;| by Manick
;| (c) 2001-2004 by http://phpbots.sf.net
;| Contact: manick@manekian.com
;| irc: #manekian@irc.rizon.net
;| ========================================
;+---------------------------------------------------------------------------
;| > 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.
;+---------------------------------------------------------------------------
file priv_mod modules/default/priv_mod.php
priv admin ~; text typed in the channel/pm (admin)
true ~; active command on statup?
false ~; inform admins in dcc chat iface if this command is used
false ~; can be deactivated with 'function' dcc command
0 ~; times used.. just leave this 0 (its for stats).
priv_mod ~; class name (see file import section above)
priv_admin ; function name
priv !ad true true true 0 priv_mod priv_ad

View file

@ -0,0 +1,315 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.0
| ========================================================
| by Manick
| (c) 2001-2005 by http://phpbots.sf.net/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > priv_mod module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class priv_mod extends module {
public $title = "Privmsg Utils";
public $author = "Manick";
public $version = "2.1.1";
public $dontShow = true;
private $ads;
public function init()
{
$this->loadAds();
}
public function destroy()
{
$this->destroyAds();
}
private function loadAds()
{
$ads = new ini("./modules/default/ads.ini");
if ($ads->getError())
{
return;
}
$sections = $ads->getSections();
foreach ($sections AS $ad)
{
$int = $ads->getIniVal($ad, "int");
$channel = $ads->getIniVal($ad, "chan");
$msg = $ads->getIniVal($ad, "msg");
$argArray = array('msg' => $msg, 'channel' => $channel);
$this->timerClass->addTimer($ad, $this, "misc_adTimer", $argArray, $int);
}
$this->ads = $ads;
}
private function destroyAds()
{
$sections = $this->ads->getSections();
foreach ($sections AS $ad)
{
$this->timerClass->removeTimer($ad);
}
}
// Misc Timer
public function misc_adTimer($msg)
{
$ad = DARK . "[" . BRIGHT . "Request" . DARK . "] - [" . BRIGHT .
$msg['msg'] . DARK .
"] - PHP-IRC v" . VERSION;
$raw = "PRIVMSG " . $msg['channel'] . " :" . $ad;
$this->ircClass->sendRaw($raw);
return true;
}
/* public Message/Channel Functions */
// This function is an example, it will display an add with timer
public function priv_ad($line, $args)
{
$channel = irc::myStrToLower($line['to']);
if ($channel == $this->ircClass->getNick())
{
return;
}
if (!$this->ircClass->isMode($line['fromNick'], $channel, "o"))
{
return;
}
if ($args['nargs'] == 0)
{
$timerString = "";
$timers = $this->timerClass->getTimers();
foreach ($timers AS $timer)
{
if (substr($timer->name, 0, 2) == "ad")
{
if ($timer->args['channel'] == $channel)
{
$timerString .= $timer->name . " ";
}
}
}
if ($timerString == "")
{
$this->ircClass->notice($line['fromNick'], "No ads currently for " . $channel . ".");
}
else
{
$this->ircClass->notice($line['fromNick'], "Current ads for " . $channel .":");
$this->ircClass->notice($line['fromNick'], $timerString);
}
$this->ircClass->notice($line['fromNick'], "Type !ad <interval(seconds)> <msg> to add an ad, or !ad <ad[id]> to view an ad.");
}
else if ($args['nargs'] >= 1)
{
if (substr($args['arg1'], 0, 2) == "ad" && strlen($args['arg1']) > 2)
{
$id = $args['arg1'];
$timers = $this->timerClass->getTimers();
foreach ($timers AS $timer)
{
if ($timer->name == $id)
{
break;
}
}
if ($timer == null || $channel != $timer->args['channel'])
{
$this->ircClass->notice($line['fromNick'], "There is no ad by that id.");
}
else
{
if ($args['nargs'] >= 2)
{
if (irc::myStrToLower($args['arg2']) == "delete")
{
$this->ads->deleteSection($timer->name);
$this->ads->writeIni();
$this->timerClass->removeTimer($timer->name);
$this->ircClass->notice($line['fromNick'], "Ad successfully deleted.");
}
else
{
$this->ircClass->notice($line['fromNick'], "Invalid option. Valid options: delete");
}
}
else
{
$this->ircClass->notice($line['fromNick'], "Ad: " . $timer->name);
$this->ircClass->notice($line['fromNick'], $timer->args['msg']);
$this->ircClass->notice($line['fromNick'], "Use '!ad " . $timer->name . " delete' to delete this ad.");
}
}
}
else
{
if ($args['nargs'] == 1)
{
$this->ircClass->notice($line['fromNick'], "You must specify a message!");
}
else
{
$int = intval($args['arg1']);
if ($int <= 5)
{
$this->ircClass->notice($line['fromNick'], "Invalid Interval. Interval must be greater than 5 seconds.");
}
else
{
$ad = substr($args['query'], strlen($args['arg1']) + 1);
$argArray = array('msg' => $ad, 'channel' => $channel);
//Find next id
$highest = 0;
$timers = $this->timerClass->getTimers();
foreach ($timers AS $timer)
{
if (substr($timer->name, 0, 2) == "ad")
{
$id = intval(substr($timer->name, 2));
if ($id > $highest)
{
$highest = $id;
}
}
}
$highest++;
$this->timerClass->addTimer('ad' . $highest, $this, "misc_adTimer", $argArray, $int, true);
$this->ircClass->notice($line['fromNick'], "The ad was successfully added.");
$this->ads->setIniVal('ad' . $highest, "int", $int);
$this->ads->setIniVal('ad' . $highest, "chan", $channel);
$this->ads->setIniVal('ad' . $highest, "msg", $ad);
$this->ads->writeIni();
}
}
}
}
}
public function priv_admin($line, $args)
{
if ($args['nargs'] < 2)
{
return;
}
if ($this->ircClass->getClientConf('dccadminpass') == "")
{
return;
}
if (md5($args['arg1']) != $this->ircClass->getClientConf('dccadminpass'))
{
return;
}
$query = substr($args['query'], strlen($args['arg1']) + 1);
$myArgs = parser::createLine($query);
switch ($args['arg2'])
{
case "chatme":
$port = $this->dccClass->addChat($line['fromNick'], null, null, true, null);
if ($port === false)
{
$this->ircClass->notice($line['fromNick'], "Error starting chat, please try again.", 1);
}
break;
default:
$chat = new chat_wrapper($line['fromNick'], $this->ircClass);
$cmdList = $this->parserClass->getCmdList();
$cmdLower = $myArgs['cmd'];
if (isset($cmdList['dcc'][$cmdLower]))
{
if ($myArgs['nargs'] < $cmdList['dcc'][$cmdLower]['numArgs'])
{
$chat->dccSend("Usage: " . $cmdLower . " " . $cmdList['dcc'][$cmdLower]['usage']);
break;
}
$module = $cmdList['dcc'][$cmdLower]['module'];
$class = $cmdList['file'][$module]['class'];
$func = $cmdList['dcc'][$cmdLower]['function'];
$class->$func($chat, $myArgs);
$chat->dccSend("ADMIN " . irc::myStrToUpper($cmdLower) . " Requested");
}
else
{
$chat->dccSend("Invalid Command: " . $myArgs['cmd']);
}
break;
}
}
}
?>

View file

@ -0,0 +1,21 @@
file lw_mod modules/lw/lw_mod.php
priv !r true false false 0 lw_mod getRank
priv !rank true false false 0 lw_mod getRank
priv !civ true false false 0 lw_mod getCivRank
priv !mil true false false 0 lw_mod getMilRank
priv !fin true false false 0 lw_mod getFinRank
priv !idr true false false 0 lw_mod getIDR
priv !a true false false 0 lw_mod getAllianceRank
priv !arank true false false 0 lw_mod getAllianceRank
priv !t true false false 0 lw_mod nextTick
priv !tick true false false 0 lw_mod nextTick
priv !g true false false 0 lw_mod listGames
priv !games true false false 0 lw_mod listGames
priv !h true false false 0 lw_mod help
priv !help true false false 0 lw_mod help

View file

@ -0,0 +1,438 @@
<?php
class lw_mod extends module {
public function init() {
}
public function destroy() {
}
public function nextTick($line, $args) {
$gameID = $args['nargs'] == 1 ? $args['query'] : null;
// Get the game
$game = is_null($gameID) ? config::getDefaultGame() : config::getGame($gameID);
if (is_null($game)) {
$msg = "Game ID '" . BOLD . $gameID . BOLD . "' not found";
} else {
// Try finding public ticks
$minTick = null;
foreach ($game->ticks as $tick) {
if (! $tick->definition->public) {
continue;
}
$tick->computeNext();
if (is_null($tick->next)) {
continue;
}
if (is_null($minTick) || $minTick->next > $tick->next) {
$minTick = $tick;
}
}
if (is_null($minTick)) {
$msg = "[" . BOLD . $game->text . BOLD . "] No more ticks on this game";
} else {
$msg = "[" . BOLD . $game->text . BOLD . "] Next tick: " . BOLD
. $minTick->definition->getName('en') . BOLD . " at " . BOLD
. gmstrftime("%H:%M:%S", $minTick->next) . BOLD;
if (gmstrftime("%Y-%m-%d", $minTick->next) != gmstrftime("%Y-%m-%d", time())) {
$msg .= " on " . BOLD . gmstrftime("%d/%m/%Y", $minTick->next) . BOLD;
}
}
}
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
public function listGames($line, $args) {
static $statusText = array(
"READY" => "open for registration",
"RUNNING" => "running",
"VICTORY" => "victory conditions reached",
"ENDING" => "being terminated",
"FINISHED" => "terminated"
);
$to = $line['fromNick'];
dbConnect();
foreach (config::getGames() as $game) {
if ($game->name == 'main' || $game->status() == 'PRE') {
continue;
}
$msg = "(" . BOLD . $game->name . BOLD . ") " . BOLD . $game->text . BOLD . " - Status: "
. BOLD . $statusText[$game->status()] . BOLD;
if ($game->status() == "READY") {
$msg .= " - Starting at " . BOLD . gmstrftime("%H:%M:%S", $game->firstTick())
. BOLD . " on " . BOLD . gmstrftime("%d/%m/%Y", $game->firstTick()) . BOLD;
} elseif ($game->status() == "ENDING") {
$msg .= " - Ending at " . BOLD . gmstrftime("%H:%M:%S", $game->lastTick())
. BOLD . " on " . BOLD . gmstrftime("%d/%m/%Y", $game->lastTick()) . BOLD;
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
}
public function getRank($line, $args) {
list($player, $game) = $this->getParams($line, $args);
dbConnect();
$rv = $this->fetchGenRank($player, $game);
dbClose();
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
if (is_array($rv)) {
$msg = "[" . BOLD . $rv[0] . BOLD . "] Player " . BOLD . $player . BOLD
. ": " . BOLD . "#{$rv[1]['ranking']}" . BOLD . " (" . BOLD
. number_format($rv[1]['points']) . BOLD . " points)";
if (! is_null($rv[2])) {
$msg .= " - Overall round ranking: " . BOLD . "#{$rv[2]['ranking']}"
. BOLD . " (" . BOLD . number_format($rv[2]['points'])
. BOLD . " points)";
}
} elseif ($rv == 1) {
$msg = "Game ID '" . BOLD . $game . BOLD . "' not found";
} elseif ($rv == 2) {
$msg = "Player " . BOLD . $player . BOLD . " not found";
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
public function getCivRank($line, $args) {
list($player, $game) = $this->getParams($line, $args);
dbConnect();
$rv = $this->fetchDetRank($player, $game, 'p_civ');
dbClose();
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
if (is_array($rv)) {
$msg = "[" . BOLD . $rv[0] . BOLD . "] Player " . BOLD . $player . BOLD
. " (civilisation): " . BOLD . "#{$rv[1]['ranking']}" . BOLD . " (" . BOLD
. number_format($rv[1]['points']) . BOLD . " points)";
} elseif ($rv == 1) {
$msg = "Game ID '" . BOLD . $game . BOLD . "' not found";
} elseif ($rv == 2) {
$msg = "Player " . BOLD . $player . BOLD . " not found";
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
public function getFinRank($line, $args) {
list($player, $game) = $this->getParams($line, $args);
dbConnect();
$rv = $this->fetchDetRank($player, $game, 'p_financial');
dbClose();
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
if (is_array($rv)) {
$msg = "[" . BOLD . $rv[0] . BOLD . "] Player " . BOLD . $player . BOLD
. " (financial): " . BOLD . "#{$rv[1]['ranking']}" . BOLD . " (" . BOLD
. number_format($rv[1]['points']) . BOLD . " points)";
} elseif ($rv == 1) {
$msg = "Game ID '" . BOLD . $game . BOLD . "' not found";
} elseif ($rv == 2) {
$msg = "Player " . BOLD . $player . BOLD . " not found";
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
public function getMilRank($line, $args) {
list($player, $game) = $this->getParams($line, $args);
dbConnect();
$rv = $this->fetchDetRank($player, $game, 'p_military');
dbClose();
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
if (is_array($rv)) {
$msg = "[" . BOLD . $rv[0] . BOLD . "] Player " . BOLD . $player . BOLD
. " (military): " . BOLD . "#{$rv[1]['ranking']}" . BOLD . " (" . BOLD
. number_format($rv[1]['points']) . BOLD . " points)";
} elseif ($rv == 1) {
$msg = "Game ID '" . BOLD . $game . BOLD . "' not found";
} elseif ($rv == 2) {
$msg = "Player " . BOLD . $player . BOLD . " not found";
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
public function getIDR($line, $args) {
list($player, $game) = $this->getParams($line, $args);
dbConnect();
$rv = $this->fetchDetRank($player, $game, 'p_idr');
dbClose();
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
if (is_array($rv)) {
$msg = "[" . BOLD . $rv[0] . BOLD . "] Player " . BOLD . $player . BOLD
. " (inflicted damage): " . BOLD . "#{$rv[1]['ranking']}" . BOLD . " (" . BOLD
. number_format($rv[1]['points']) . BOLD . " points)";
} elseif ($rv == 1) {
$msg = "Game ID '" . BOLD . $game . BOLD . "' not found";
} elseif ($rv == 2) {
$msg = "Player " . BOLD . $player . BOLD . " not found";
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
private function getParams($line, $args) {
if ($args['nargs'] == 0) {
$player = $line['fromNick'];
$game = null;
} else {
$query = explode(' ', trim(preg_replace('/\s+/', ' ', $args['query'])));
if (preg_match('/^{[a-z0-9]+}$/', $query[0], $matches)) {
$game = preg_replace('/[{}]/', '', array_shift($query));
} else {
$game = null;
}
$player = join(' ', $query);
if ($player == '') {
$player = $line['fromNick'];
}
}
return array($player, $game);
}
private function fetchGenRank($player, $gameID) {
// Get the game
$game = is_null($gameID) ? config::getDefaultGame() : config::getGame($gameID);
if (is_null($game)) {
return 1;
}
// Access the rankings library
$rLib = $game->getLib('main/rankings');
// Get player ranking
$rType = $rLib->call('getType', 'p_general');
$genRank = $rLib->call('get', $rType, $player);
if (is_null($genRank['points'])) {
return 2;
}
// Try getting the overall round rankings
$rType = $rLib->call('getType', 'p_round');
$orRank = $rLib->call('get', $rType, $player);
if (is_null($orRank['points'])) {
$orRank = null;
}
return array($game->text, $genRank, $orRank);
}
private function fetchDetRank($player, $gameID, $type) {
// Get the game
$game = is_null($gameID) ? config::getDefaultGame() : config::getGame($gameID);
if (is_null($game)) {
return 1;
}
// Access the rankings library
$rLib = $game->getLib('main/rankings');
// Get player ranking
$rType = $rLib->call('getType', $type);
$rank = $rLib->call('get', $rType, $player);
if (is_null($rank['points'])) {
return 2;
}
return array($game->text, $rank);
}
public function getAllianceRank($line, $args) {
list($alliance, $game) = $this->getParams($line, $args);
dbConnect();
$rv = $this->fetchDetRank($alliance, $game, 'a_general');
dbClose();
if ($line['to'] == $this->ircClass->getClientConf('nick')) {
$to = $line['fromNick'];
} else {
$to = $line['to'];
}
if (is_array($rv)) {
$msg = "[" . BOLD . $rv[0] . BOLD . "] Alliance " . BOLD . $alliance . BOLD
. ": " . BOLD . "#{$rv[1]['ranking']}" . BOLD . " (" . BOLD
. number_format($rv[1]['points']) . BOLD . " points)";
} elseif ($rv == 1) {
$msg = "Game ID '" . BOLD . $game . BOLD . "' not found";
} elseif ($rv == 2) {
$msg = "Alliance " . BOLD . $alliance . BOLD . " not found";
}
$this->ircClass->sendRaw("PRIVMSG $to :$msg");
}
public function help($line, $args) {
$help = array(
"" => array(
"This bot allows you to get some information from the",
"Legacy Worlds game directly here, on IRC!",
" ",
"You can use any of the following commands:",
" ",
" " . BOLD . "Displaying rankings" . BOLD,
" " . BOLD . "rank" . BOLD . " - displays players' general and round rankings",
" " . BOLD . "civ" . BOLD . " - displays players' civilian rankings",
" " . BOLD . "mil" . BOLD . " - displays players' military rankings",
" " . BOLD . "fin" . BOLD . " - displays players' financial rankings",
" " . BOLD . "idr" . BOLD . " - displays players' inflicted damage rankings",
" " . BOLD . "arank" . BOLD . " - displays alliances' rankings",
" ",
" " . BOLD . "General information" . BOLD,
" " . BOLD . "games" . BOLD . " - lists available games",
" " . BOLD . "tick" . BOLD . " - displays the time and date of the next tick",
" " . BOLD . "help" . BOLD . " - help access",
" ",
"All commands must start with the '!' character. To get more",
"information on a specific command, type '!help <command>'"
),
"arank" => array(
"Syntax: " . BOLD . "!arank [{game}] tag",
" " . BOLD . "!a [{game}] tag",
" ",
"This command gives information about an alliance's ranking.",
" ",
"It is possible to select the game by adding the game's ID between",
"brackets just before the player's name.",
),
"rank" => array(
"Syntax: " . BOLD . "!rank [{game}] [player]",
" " . BOLD . "!r [{game}] [player]",
" ",
"This command gives information about a player's general ranking",
"as well as his round ranking if he has one.",
" ",
"Using the command without parameters will cause the bot to look",
"for your current nick, if it's the same as your in-game name.",
" ",
"It is possible to select the game by adding the game's ID between",
"brackets just before the player's name.",
" ",
"Examples: !r TSeeker",
" -> Displays TSeeker's rankings in the default game",
" !r {b5m2}",
" -> Displays your rankings in Match 2",
),
"civ" => array(
"Syntax: " . BOLD . "!civ [{game}] [player]",
" ",
"This command gives information about a player's civilisation",
"ranking.",
" ",
"Using the command without parameters will cause the bot to look",
"for your current nick, if it's the same as your in-game name.",
" ",
"It is possible to select the game by adding the game's ID between",
"brackets just before the player's name.",
" ",
"See also: " . BOLD . "!help rank" . BOLD
),
"mil" => array(
"Syntax: " . BOLD . "!mil [{game}] [player]",
" ",
"This command gives information about a player's military",
"ranking.",
" ",
"Using the command without parameters will cause the bot to look",
"for your current nick, if it's the same as your in-game name.",
" ",
"It is possible to select the game by adding the game's ID between",
"brackets just before the player's name.",
" ",
"See also: " . BOLD . "!help rank" . BOLD
),
"fin" => array(
"Syntax: " . BOLD . "!fin [{game}] [player]",
" ",
"This command gives information about a player's financial",
"ranking.",
" ",
"Using the command without parameters will cause the bot to look",
"for your current nick, if it's the same as your in-game name.",
" ",
"It is possible to select the game by adding the game's ID between",
"brackets just before the player's name.",
" ",
"See also: " . BOLD . "!help rank" . BOLD
),
"tick" => array(
"Syntax: " . BOLD . "!tick [game]",
" " . BOLD . "!t [game]",
" ",
"This command displays the next tick.",
" ",
"It is possible to select the game by adding the game's ID",
"after the command.",
),
"games" => array(
"Syntax: " . BOLD . "!games",
" " . BOLD . "!g",
" ",
"This command displays the list of available games.",
),
);
$topic = $args['query'];
if (! array_key_exists($topic, $help)) {
$topic = "";
}
$to = $line['fromNick'];
for ($i = 0; $i < count($help[$topic]); $i ++) {
$this->ircClass->privMsg($to, $help[$topic][$i]);
}
}
}
?>

View file

@ -0,0 +1 @@
For More Modules, see the website: http://www.phpbots.org

View file

@ -0,0 +1,11 @@
file seen_mod modules/seen/seen_mod.php
privmsg seen_mod seen
;notice seen_mod seen
join seen_mod seen
kick seen_mod seen
part seen_mod seen
quit seen_mod seen
priv !seen true true true 0 seen_mod priv_seen

View file

@ -0,0 +1,234 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.0
| ========================================================
| by Manick
| (c) 2001-2005 by http://phpbots.sf.net/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > Seen Mod
| > Module written by Manick
| > Module Version Number: 0.1
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
class seen_mod extends module {
public $title = "Seen Mod";
public $author = "Manick";
public $version = "0.1";
private $seen;
public function init()
{
$this->timerClass->addTimer("seen_mod_updateini", $this, "seen_update", "", 60*15, false);
$this->seen = new ini("modules/seen/seen.ini");
}
public function destroy()
{
$this->timerClass->removeTimer("seen_mod_updateini");
}
// Write to file
public function seen_update($args)
{
if ($this->seen->getError())
{
return;
}
$this->seen->writeIni();
$this->dccClass->dccSend("Updated Seen Mod ini database file");
return true;
}
// Update actions
public function seen($line, $args)
{
if ($this->seen->getError())
{
if (DEBUG == 1)
{
echo "Seen error!\n";
}
return;
}
if (strtolower($line['cmd']) == "join")
{
$line['text'] = "";
}
if (strtolower($line['cmd']) == "kick")
{
$offsetA = strpos($line['params'], chr(32));
$act = "kick";
$user = substr($line['params'], $offsetA + 1);
$this->addLast($user, $act, $line['text']);
}
else
{
$this->addLast($line['fromNick'], strtolower($line['cmd']), $line['text']);
}
$this->getLast($line['fromNick']);
}
private function getLast($user)
{
$user = irc::myStrToLower($user);
if (!$this->seen->sectionExists("seen"))
{
return;
}
$var = $this->seen->getIniVal("seen", $user);
if ($var == false)
{
return false;
}
$offsetA = strpos($var, "=");
$offsetB = strpos($var, "=", $offsetA + 1);
$offsetC = strpos($var, "=", $offsetB + 1);
$info = array();
$info['user'] = substr($var, 0, $offsetA);
$info['time'] = substr($var, $offsetA + 1, $offsetB - $offsetA - 1);
$info['act'] = substr($var, $offsetB + 1, $offsetC - $offsetB - 1);
$info['txt'] = substr($var, $offsetC + 1);
return $info;
}
private function addLast($user, $act, $txt)
{
$Suser = irc::myStrToLower($user);
$tAction = $user . "=" . time() . "=" . irc::myStrToLower($act) . "=" . $txt;
$this->seen->setIniVal("seen", $Suser, $tAction);
}
// User interface
public function priv_seen($line, $args)
{
if ($this->seen->getError())
{
$this->ircClass->notice($line['fromNick'], "There was an error while attempting to access the seen database.");
return;
}
if ($line['to'] == $this->ircClass->getNick())
{
return;
}
if ($args['nargs'] <= 0)
{
$this->ircClass->notice($line['fromNick'], "Usage: !seen <nick>");
return;
}
$user = irc::myStrToLower($args['arg1']);
if ($user == irc::myStrToLower($line['fromNick']))
{
$this->ircClass->privMsg($line['to'], $line['fromNick'] . ", umm... O..kay...");
$this->ircClass->action($line['to'], "points at " . $line['fromNick'] . "...");
return;
}
$data = $this->getLast($user);
if ($data === false)
{
$this->ircClass->privMsg($line['to'], $line['fromNick'] . ", I have never seen " . $args['arg1'] . " before.");
return;
}
$time = time() - $data['time'];
if ($time > 3600*24)
{
$timeString = irc::timeFormat($time, "%d days %h hours %m min %s sec");
}
else if ($time > 3600)
{
$timeString = irc::timeFormat($time, "%h hours %m min %s sec");
}
else if ($time > 60)
{
$timeString = irc::timeFormat($time, "%m min %s sec");
}
else
{
$timeString = irc::timeFormat($time, "%s sec");
}
$action = "";
switch ($data['act'])
{
case "privmsg":
$action = "saying in a channel";
break;
case "notice":
$action = "noticing a channel";
break;
case "join":
$action = "joining a channel";
break;
case "kick":
$action = "being kicked from a channel";
break;
case "part":
$action = "parting a channel";
break;
case "quit":
$action = "quitting";
break;
}
if ($data['txt'] != "")
{
$action .= ": " . $data['txt'];
}
$this->ircClass->privMsg($line['to'], $line['fromNick'] . ", I last saw " . $data['user'] . " " . $timeString . " ago " . $action . ".");
}
}
?>

View file

@ -0,0 +1,39 @@
<?php
/*
Change:
'class_name' to the name of your module (specified in function.conf)
Add:
Your functions after "//Methods here:"
Add:
Timer declarations and other general startup stuff to be run when the bot starts up in the init() function
*/
class class_name extends module {
public $title = "<title>";
public $author = "<author>";
public $version = "<version>";
public function init()
{
// Add your timer declarations and whatever
// else here...
}
public function destroy()
{
// Put code here to destroy the timers that you created in init()
// and whatever else cleanup code you want.
}
//Methods here:
}
?>

1143
ircbot/parser.php Normal file

File diff suppressed because it is too large Load diff

339
ircbot/queue.php Normal file
View file

@ -0,0 +1,339 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > queue module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
/* This module is my response to a big problem. PHP-IRC, on idling, would use
* 2.0% or more of the CPU on a 500mhz machine. This annoyed me, and I decided
* to do something about it. So, I changed the way that PHP-IRC works, from a
* "round-robin" approach to an "interrupt" type approach. Whenever something
* happens, say, new data is read from a socket, a process Queue is added with
* a pointer to the function that reads input for that socket; or for
* another example, if a file transfer is in effect, and new data is read from
* that socket, but we also have a dcc chat going, we will only handle data for
* the file transfer, instead of wasting CPU cycles on the dcc chat, like is
* currently done in <=2.1.1. I've learned a bit more about timers and socket
* timeouts since then. Also, we have to handle timers in a different way now.
* There will still be a "timers" class, for re-occuring processes, but the
* next timer is inserted into this process queue, and the callback for the timer
* will be a pointer to the timer class which handles the timer. Then, the timer
* class will do the appropriate stuff for the timer, and then add the next timer
* into the process Queue. --Manick
*
* P.S.; I never knew this would change so much code... I figured adding in select()
* timeouts would be a piece of cake... until I realized that my whole framework
* was incompatible with the idea. What a pain in the ass -_-.
*/
/* Module Written 11/30/04 by Manick */
class processQueue {
private $numQueued;
private $queuedItems;
private $currProc;
function __construct()
{
$this->queuedItemsArray = array();
$this->queuedItems = NULL;
$this->currProc = NULL;
$this->numQueued = 0;
}
public function getNumQueued()
{
return $this->numQueued;
}
public static function getMicroTime()
{
return microtime(true);
}
/* Only allow removal of entire irc class (as in we shut down the bot.. otherwise, we don't
want to deal with shutting down specific queues during the queueing process. Have the callbacks
handle that themselves. We only have to worry when the callbacks won't exist anymore, as when an
irc bot is shut down, and the ircclass is discarded
*/
public function removeOwner($class)
{
$next = NULL;
for ($queue = $this->queuedItems; $queue != NULL; )
{
$next = $queue->next;
if ($queue->owner === $class)
{
$this->removeQueue($queue);
}
$queue = $next;
}
}
/* Remove reference to queued item, let PHP5 do the rest */
private function removeQueue($item)
{
if ($item->prev == NULL)
{
$this->queuedItems = $item->next;
if ($item->next != NULL)
{
$item->next->prev = NULL;
}
}
else
{
$item->prev->next = $item->next;
if ($item->next != NULL)
{
$item->next->prev = $item->prev;
}
}
$item->removed = true;
unset($item->args);
unset($item->owner);
unset($item->callBack_class);
unset($item->next);
unset($item->prev);
unset($item);
$this->numQueued--;
}
/* Add an item to the process queue */
public function addQueue($owner, $class, $function, $args, $nextRunTime)
{
// echo "Queue Added: $function with $nextRunTime\n";
if ($function == "" || $function == NULL)
{
return false;
}
if (!is_object($class))
{
$class = null;
}
$nextRunTime = floatval($nextRunTime);
$queue = new queueItem;
$queue->args = $args;
$queue->owner = $owner;
$queue->removed = false;
$queue->callBack_class = $class;
$queue->callBack_function = $function;
$queue->nextRunTime = self::getMicroTime() + $nextRunTime;
//Now insert as sorted into queue
$prev = NULL;
for ($item = $this->queuedItems; $item != NULL; $item = $item->next)
{
if ($queue->nextRunTime < $item->nextRunTime)
{
break;
}
$prev = $item;
}
if ($item == NULL)
{
if ($prev == NULL)
{
$queue->next = NULL;
$queue->prev = NULL;
$this->queuedItems = $queue;
}
else
{
$queue->next = NULL;
$queue->prev = $prev;
$prev->next = $queue;
}
}
else
{
if ($item->prev == NULL)
{
$queue->next = $this->queuedItems;
$queue->prev = NULL;
$item->prev = $queue;
$this->queuedItems = $queue;
}
else
{
$queue->next = $item;
$queue->prev = $item->prev;
$item->prev = $queue;
$queue->prev->next = $queue;
}
}
//Okay, we're inserted, return true;
$this->numQueued++;
return true;
}
public function displayQueue()
{
//Used for debug
echo "Current Time: " . self::getMicroTime() . "\n";
echo "\n\n";
for ($i = $this->queuedItems; $i != NULL; $i = $i->next)
{
echo $i->callBack_function . "-" . $i->nextRunTime . "\n";
echo "---" . "Prev: " . $i->prev . " Next: " . $i->next . " Me: " . $i . "\n";
}
echo "\n\n";
}
/* Handle the process queue, return the time until the next item */
public function handle()
{
// Handle all items with $queue->nextRunTime < getMicroTime(), then return with time until next item must
// be run
// Populate a runQueue with all current items that need to be run. We need to do this because some of these
// callback functions might add another process to the queue, and if the runtime is < 0, we would run that item
// instead of timing out before we do. If we have something like a file transfer, this could be a bad thing.
$runQueue = array();
$time = self::getMicroTime();
for ($item = $this->queuedItems; $item != NULL; $item = $item->next)
{
if ($item->nextRunTime <= $time)
{
$runQueue[] = $item;
}
else
{
break;
}
}
//Okay, now run each item.
foreach ($runQueue AS $index => $item)
{
if (!is_object($item) || $item->removed === true)
{
if (is_object($item))
{
unset($item);
}
continue;
}
self::handleQueueItem($item);
}
unset($runQueue);
//Return time until next item needs to be run, or true if there are no queued items
//Hmm, true returned here, means we'll just sleep for like an hour or something until data
//is recieved from the sockets, because we have no active timers
if ($this->queuedItems == null)
{
return true;
}
//Get new time
$time = self::getMicroTime();
$timeTillNext = $this->queuedItems->nextRunTime - $time;
if ($timeTillNext < 0)
{
$timeTillNext = 0;
}
//When zero is returned, we'll always sleep at least 50000 usec in the socket class anyway
return $timeTillNext;
}
/* Specific function to deal with queued items */
private function handleQueueItem($item)
{
$this->currTimer = $item;
$class = $item->callBack_class;
$func = $item->callBack_function;
//Call the callback function! Now the callback function will check all possible triggers,
//such as socket input, etc, and add new queued items if it needs more processing/other processing
if ($class == null)
{
$status = $func($item->args);
}
else
{
$status = $class->$func($item->args);
}
//If true is returned from the function, then keep the bitch in the queue. This is useful when a
//function has not completed processing (i.e., irc->connection waiting on socket class to return
//the fact that its connected.
if ($item->removed !== true && $status !== true)
{
self::removeQueue($item);
}
}
}
?>

1364
ircbot/readme.txt Normal file

File diff suppressed because it is too large Load diff

213
ircbot/remote.php Normal file
View file

@ -0,0 +1,213 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > remote class module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
/* Remote, a class to handle addQuery connection from ircClass */
class remote {
//External Classes
private $socketClass;
private $ircClass;
private $timerClass;
//Internal variables
private $host;
private $port;
private $query;
private $line;
private $class;
private $function;
private $connTimeout;
private $transTimeout;
private $sockInt;
private $connection;
private $connected;
//Output internal variables
private $response;
private $type;
function __construct($host, $port, $query, $line, $class, $function, $transTimeout)
{
$this->host = $host;
$this->port = $port;
$this->query = $query;
$this->line = $line;
$this->class = $class;
$this->function = $function;
$this->transTimeout = $transTimeout;
$this->response = "";
$this->connected = false;
$this->type = QUERY_SUCCESS;
}
public function setSocketClass($class)
{
$this->socketClass = $class;
}
public function setIrcClass($class)
{
$this->ircClass = $class;
}
public function setTimerClass($class)
{
$this->timerClass = $class;
}
public function connect()
{
if ($this->host == null || $this->port == null)
{
return false;
}
if (!is_object($this->socketClass))
{
return false;
}
if (!is_object($this->ircClass))
{
return false;
}
$conn = new connection($this->host, $this->port, CONNECT_TIMEOUT);
$conn->setSocketClass($this->socketClass);
$conn->setIrcClass($this->ircClass);
$conn->setCallbackClass($this);
$conn->setTimerClass($this->timerClass);
/* Set Timeouts */
$conn->setTransTimeout($this->transTimeout);
$conn->init();
if ($conn->getError())
{
$this->setError("Could not allocate socket");
return false;
}
$this->sockInt = $conn->getSockInt();
$conn->connect();
$this->connection = $conn;
return true;
}
public function disconnect()
{
$this->connection->disconnect();
$this->setError("Manual disconnect");
}
/* Specific handling functions */
public function onTransferTimeout($conn)
{
$this->connection->disconnect();
$this->setError("The connection timed out");
}
public function onConnectTimeout($conn)
{
$this->connection->disconnect();
$this->setError("Connection attempt timed out");
}
public function onConnect($conn)
{
$this->connected = true;
$this->socketClass->sendSocket($this->sockInt, $this->query);
}
public function onRead($conn)
{
$this->response .= $this->socketClass->getQueue($this->sockInt);
}
public function onWrite($conn)
{
// do nothing, we really don't care about this
}
public function onDead($conn)
{
$this->connection->disconnect();
if ($this->connected === true)
{
$this->doCallback();
}
else
{
$this->setError($this->connection->getErrorMsg());
}
}
/* Error handling */
private function setError($msg)
{
$this->response = $msg;
$this->type = QUERY_ERROR;
$this->doCallback();
}
private function doCallback()
{
if ($this->line != null && is_array($this->line) && isset($this->line['text']))
{
$lineArgs = parser::createLine($this->line['text']);
}
else
{
$lineArgs = array();
}
$func = $this->function;
$this->class->$func($this->line, $lineArgs, $this->type, $this->response);
}
}
?>

1010
ircbot/socket.php Normal file

File diff suppressed because it is too large Load diff

235
ircbot/timers.php Normal file
View file

@ -0,0 +1,235 @@
<?php
/*
+---------------------------------------------------------------------------
| PHP-IRC v2.2.1 Service Release
| ========================================================
| by Manick
| (c) 2001-2005 by http://www.phpbots.org/
| Contact: manick@manekian.com
| irc: #manekian@irc.rizon.net
| ========================================
+---------------------------------------------------------------------------
| > timers module
| > Module written by Manick
| > Module Version Number: 2.2.0
+---------------------------------------------------------------------------
| > 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.
+---------------------------------------------------------------------------
| Changes
| =======-------
| > If you wish to suggest or submit an update/change to the source
| > code, email me at manick@manekian.com with the change, and I
| > will look to adding it in as soon as I can.
+---------------------------------------------------------------------------
*/
/*
* Redesigned 12/22/04... Yes... this file sucks. I basically am going to
* do a few things here. I have been stuck on this file for the past 2 weeks,
* trying to come up with some ideas to handle the hopeless situation which
* faced me. With the new queue system, this timer class became very interesting
* to handle. I had to decide how I would add proc queues to the queue class
* to handle specific timers in this file. Say, for instance, that a timer
* is added, and then another is added that has a shorter time than that one.
* The first one will have a proc queue added into the queue class, but then
* the second one will have to add another proc queue. But hold on a second,
* the way this works right now, after a timer is done running, the next one
* is added to the process queue. I handled this by keeping track of how
* many processes were in the queue, and didn't add one if there were more than
* one, and the call to setCurrentTimer was from handle(). This worked, unless
* you have a timer that repeats. Then the problem comes in, as it will not be
* added to the proc queue until the next timer is complete. To just handle
* this problem, I'm just going to add a proc to the queue for every timer
* that is added, and then every timer will have a queue in the procqueue.
* that way, we don't have to worry about anything.
*
* Also, I added a "timerStack" so that I could have reserved names and what
* not. Each timer gets a unique name or ID, and that is added to the stack,
* as well as sorted into the timerList.
*
* Okay, way that timers are handled... has changed, if you want a timer to
* repeat, you must return true from the timer, runOnce was removed.
*
* Ooohh oohh ohh! Idea. screw linked lists and shit. I'll just add each
* timer to the proc queue, and then have them call handle() with the timer
* referenced! This solves all problems, and is incredibly more efficient!
* This officially takes the last linked list out of my bot. I have NO IDEA
* why I even used them in the first place, as php already has associative arrays
* which are a lot better! GEEZ!
*/
class timers {
//Local variables
private $timerStack = array(); //list of all timers indexed by name
//External Classes
private $procQueue;
private $socketClass;
private $ircClass;
//Private list of reserved php-irc timer names (please do not
//use these names)
private $reserved = array( "listening_timer_[0-9]*",
"check_nick_timer",
"check_channels_timer",
"check_ping_timeout_timer",
);
public function __construct()
{
$this->time = time();
$this->timerStack = array();
}
public function setSocketClass($class)
{
$this->socketClass = $class;
}
public function setIrcClass($class)
{
$this->ircClass = $class;
}
public function setProcQueue($class)
{
$this->procQueue = $class;
}
public static function getMicroTime()
{
return microtime(true);
}
public function getTimers()
{
return $this->timerStack;
}
public function handle($timer)
{
$microTime = self::getMicroTime();
if (!isset($this->timerStack[$timer->name]))
{
return false;
}
if ($this->timerStack[$timer->name] !== $timer)
{
return false;
}
$timer->lastTimeRun = $microTime;
$timer->nextRunTime = $microTime + $timer->interval;
if ($timer->class != null)
{
$theFunc = $timer->func;
$status = $timer->class->$theFunc($timer->args);
}
else
{
$theFunc = $timer->func;
$status = $theFunc($timer->args);
}
if ($status != true)
{
$this->removeTimer($timer->name);
}
else
{
$this->procQueue->addQueue($this->ircClass, $this, "handle", $timer, $timer->interval);
}
return false;
}
public function removeAllTimers()
{
foreach ($this->timerStack AS $timer)
{
$this->removeTimer($timer->name);
}
}
public function addTimer($name, $class, $function, $args, $interval, $runRightAway = false)
{
if (trim($name) == "")
{
return false;
}
if (isset($this->timerStack[$name]))
{
return false;
}
$newTimer = new timer;
$newTimer->name = $name;
$newTimer->class = $class;
$newTimer->func = $function;
$newTimer->args = $args;
$newTimer->interval = $interval;
$newTimer->removed = false;
if ($runRightAway == false)
{
$newTimer->lastTimeRun = $this->getMicroTime();
$newTimer->nextRunTime = $this->getMicroTime() + $interval;
$tInterval = $interval;
}
else
{
$newTimer->lastTimeRun = 0;
$newTimer->nextRunTime = $this->getMicroTime();
$tInterval = 0;
}
$this->procQueue->addQueue($this->ircClass, $this, "handle", $newTimer, $tInterval);
$this->timerStack[$newTimer->name] = $newTimer;
return $name;
}
/* Remove the current timer from both the list and stack, changed in 2.1.2, can only call by
* timer name now.
*/
public function removeTimer($name)
{
if (!isset($this->timerStack[$name]))
{
return false;
}
//Set removed flag,
$this->timerStack[$name]->removed = true;
//Remove from stack
unset($this->timerStack[$name]->args);
unset($this->timerStack[$name]->class);
unset($this->timerStack[$name]);
return true;
}
}
?>

75
ircbot/typedefs.conf Normal file
View file

@ -0,0 +1,75 @@
type file ~ ;----Used to import files
name ~ ;----the module name
filename
type section ~ ;----Used to section functions in dcc chat (used with 'help')
name ~ ;-id name to specify with dcc function
longname ~ ;-section name displayed when 'help' is pressed
type ctcp ~ ;----handle all ctcp commands
name ~ ;----the command typed (or trigger, like !list)
module ~
function
type priv ~ ;----Used to process input of users in channels
name ~
active ~
inform ~
canDeactivate ~
usage ~
module ~
function
type dcc ~ ;----Used to process input of users in dcc interface
name ~
numArgs ~
usage ~
help ~
admin ~
module ~
function ~
section ;--added 2.2.0
type privmsg ~ ;----Used to process privmsg irc command
module ~
function
type notice ~ ;----Used to process notice irc command
module ~
function
type mode ~ ;----Used to process mode irc command
module ~
function
type join ~ ;----Used to process join irc command
module ~
function
type kick ~ ;----Used to process kick irc command
module ~
function
type part ~ ;----Used to process part irc command
module ~
function
type quit ~ ;----Used to process quit irc command
module ~
function
type connect ~ ;----Perform on connect
module ~ ;----Note this is really 004 from irc
function
type disconnect ~ ;----Perform on disconnect $line['text'] holds reason
module ~ ;----Note, this is really ERROR from irc
function
type raw ~
module ~
function
type action ~
module ~
function

View file

@ -0,0 +1,109 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Accounts and Games</title>
<section id="accga_intro" title="Introduction">
Each player in LegacyWorlds has a single <mlink to="accga_acc">account</mlink> which provides him access to all possible <mlink to="accga_gm">games</mlink> he wishes to play. This section of the manual explains in details how to <mlink to="accga_acc_new">create</mlink> and <mlink to="accga_acc_act">activate</mlink> an account along with <mlink to="accga_acc_del">account deletion</mlink> and how to <mlink to="accga_gm">manage games</mlink>.
</section>
<section id="accga_acc" title="Account management">
<section id="accga_acc_new" title="Account creation">
From the <mlink to="home_page">game home page</mlink>, clicking on the <i>Create Account</i> link directs you to account creation form. You have to fill in:<ul>
<li><i>Username</i>: your in game name</li>
<li><i>Language</i>: language in which you want everything to be displayed</li>
<li><i>E-mail</i>: a <i>valid</i> e-mail address to be associated with the account. This has to be typed in twice to avoid mistakes</li>
<li><i>Password</i>: the password to be used along with your username to access your account. This has to be typed in twice to avoid mistakes</li>
</ul>
Once your are satisfied with the data you've entered you can click the <i>Create Account</i> Button.
<br/>
If the account creation process has been successful an <i>e-mail is sent</i> to the provided e-mail address containing:<ul>
<li>a <i>reminder</i> about the typed in <i>account information</i></li>
<li>information about the <mlink to="accga_acc_act">account activation procedure</mlink></li>
</ul>
</section>
<section id="accga_acc_act" title="Account activation">
The <i>e-mail you have received</i> when <mlink to="accga_acc">creating an account</mlink> contains information to activate your account. In order to activate your account you have to look at the <mlink to="home_cons_left_top">top part of the left panel of the home page</mlink>. A logging form is displayed there. In the form, you have to provide:<ul>
<li><i>Username</i>: the in game username you've chosen</li>
<li><i>Password</i>: the password you've chosen</li>
</ul>
You can then click the <i>ok</i> button to log in.
<br/>
A new form is then displayed asking for a <i>confirmation code</i>. This code has been sent to you <i>in the e-mail</i> mentioned above. Type in the code in the provided text field and click on the <i>Confirm account creation</i> button. If you provide the right code you get directed towards the main game selection page.
</section>
<section id="accga_acc_clo" title="Closing Account">
<section id="accga_acc_clo_intro" title="Introduction">
<i>Closing your account</i> allows you to <i>delete all game data related to your account</i>. But be careful: <i>it doesn't deleted your account</i> and you can <mlink to="accga_acc_clo_rea">reactivate it</mlink> any time you wish. The next paragraphs will cover those topics more closely.
</section>
<section id="accga_acc_clo_pro" title="Procedure">
<section id="accga_acc_clo_pro_acc" title="Accessing the form">
The form to <i>close your account</i> is accessible from the <mlink to="home_cont_home_log_intro">home page of the game when you are logged it</mlink>. In order <i>to access the page</i> you have two options:<ul>
<li><i>if you're not logged in</i>, follow the <mlink to="home_cons_left_top">logging in procedure</mlink>. The bottom section of the page displayed in the body of the home page should be about closing your account. Below an introduction about the topic, Is displayed a <i>Close my account</i> button. Clicking the button opens the forms that lead to the path to closing your account</li>
<li>if you are logged in and playing a LegacyWorlds game, clicking on the <i>My Account</i> menu item gets you to the logged in home page of the game. As in the previous case below the introduction about the topic, is displayed the <i>Closing my account</i> button. Clicking the button opens the forms that lead to closing your account</li>
</ul>
</section>
<section id="accga_acc_clo_pro_clo" title="Closing the account">
<i>Clicking the button</i> opens a new <i>form</i> that you have to fill in in order to <i>close the account</i>. You have to provide the <i>following information</i>:<ul>
<li>Your <i>password</i> in the corresponding <i>textfield</i> to make sure you're really you're who you're saying you are</li>
<li>Optionally a <i>text area</i> is provided where you can if you wish <i>explain why you're closing your account</i></li>
</ul>
Below these two fields are displayed two buttons:<ul>
<li><i>I really want to close my account</i>: clicking this button starts a countdown to real account closing. You have a 24 to 48h delay to cancel the action</li>
<li><i>No, I was just kidding</i>: clicking this button cancels the account closing procedure</li>
</ul>
</section>
</section>
<section id="accga_acc_clo_can" title="Cancelling account closing">
<section id="accga_acc_clo_can_acc" title="Accessing the form">
During the delay to account closing you can still cancel the operation. The form to <i>cancel account closing</i> is accessible from the <mlink to="home_cont_home_log_intro">home page of the game when you are logged it</mlink>. In order <i>to access the page</i> you have two options:<ul>
<li><i>if you're not logged in</i>, follow the <mlink to="home_cons_left_top">logging in procedure</mlink>. The bottom section of the page displayed in the body of the home page should be about closing your account. Below an introduction about the topic and information about the time at which the account will be closed, is displayed a <i>Don't close my account</i> button. Clicking the button opens the forms that allow to cancel the closing operation</li>
<li>if you are logged in and playing a LegacyWorlds game, clicking on the <i>My Account</i> menu item gets you to the logged in home page of the game. As in the previous case below the introduction about the topic, is displayed the <i>Don't close my account</i> button. Clicking the button opens the forms that allow to cancel the operation</li>
</ul>
</section>
<section id="accga_acc_clo_can_can" title="Cancelling the operation">
<i>Clicking the button</i> opens a <i> new page</i> with <i>two buttons</i>:<ul>
<li><i>Yes, cancel the countdown</i>: clicking this button cancels account closing</li>
<li><i>No, get on with it</i>: clicking this button goes on with the account closing procedure</li>
</ul>
</section>
</section>
<section id="accga_acc_clo_abou" title="About closed accounts">
You have to be aware of the fact that <i>closing your account doesn't delete your account information from the LegacyWorlds database</i> but <i>only your game data</i>. This prevents anyone from using your player name at your place and impersonate you in game. It also allows you to reactivate your account.
<br/>
This also means that all information regarding your account and in particular <i>your personal data are permanently stored</i> in the LegacyWorlds database. If you want those <i>information to be erased from the database</i>, please contact the <a href="mailto:staff@legacyworlds.com">staff</a>.
</section>
<section id="accga_acc_clo_rea" title="Account reactivation">
If you want to <i>reactivate your account</i> you only have to log in as usual. <i>Joining a LegacyWorlds game</i> is then all the <mlink to="accga_acc_new">same as for new accounts</mlink>.
</section>
</section>
</section>
<section id="accga_login" title="Logging in">
In the login form of the <mlink to="home_cons_left_top">left panel of the home page</mlink> you have to fill in:<ul>
<li><i>Username</i>: the in game username you've chosen</li>
<li><i>Password</i>: the password you've chosen</li>
</ul>
You can then click the <i>Log in -></i> button to log in.
</section>
<section id="accga_gm" title="Games management">
<section id="accga_gm_intro" title="Introduction">
<i>Several LegacyWorlds games</i> may be running at once. You can <i>choose</i> which games you want to play from the main game selection page you reach when logging in.
</section>
<section id="accga_gm_join" title="Joining a new game">
The game selection list provides informations about current available games, including:<ul>
<li><i>Game name</i>: name of the game. This name is a link to join that particular game</li>
<li><i>Players</i>: number of players in this game</li>
<li><i>Running</i>: if you are not currently playing this game this field presents if the game is running or not thus informing you if you can join in or not</li>
</ul>
In order to <i>join</i> a particular game click on its name in the games list.
<br/>
You'll get then directed to a <mlink to="planet">planet</mlink> creation form. This form will allow you to choose the name of your first <mlink to="planet">planet</mlink> in the game. Type in the <mlink to="planet">planet</mlink> name in the provided text field and click the <i>ok</i> button to validate your input. You can now start taking care of your newborn <mlink to="empire">empire</mlink> in this game.
</section>
<section id="accga_gm_play" title="Playing a game you've joined">
A list of current games you are playing is also provided. This list presents:<ul>
<li><i>Game name</i>: name of the game. This name is a link to play that particular game</li>
<li><mlink to="planets">Planets</mlink>: number of <mlink to="planet">planets</mlink> in your <mlink to="empire">empire</mlink> in this game</li>
<li><mlink to="money">Cash</mlink>: amount of <mlink to="money">money</mlink> you have in this particular game</li>
</ul>
In order to <i>play a particular game</i> click on its name in the list. You'll get directed to the <mlink to="overview_page">overview page</mlink> for this particular game.
</section>
</section>
</lwdoc>

View file

@ -0,0 +1,35 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Accounts</title>
<section id="acc" title="Introduction">
Along with the good practices, some rules apply to your account in Legacy Worlds. Those are summed up in this section of the manual.
</section>
<section id="acc_multi" title="Multiple Accounts">
As for every game of the kind the general rule is: one account per player and one account only.
<br/>
Having multiple accounts for one player provides too big an advantage to the player controlling them and it wouldn't be a fair game to allow such a behaviour. It's simply cheating.
<br/>
There might not be an automated Anti-Multi System in Legacy Worlds for now but the small number of current players allows for the game administration team to check in the game database and spot by hand suspect behaviours. An automated system will be set up in a future Beta so it doesn't cost much to get good habits from the beginning.
</section>
<section id="acc_share" title="Password sharing">
Occasional password sharing among a little group of players is tolerated as long as several accounts are in the control of the same player for only a short period of time. Holding a database or file of allied account information isn't forbidden either as long as the actual use of those data complies with the previous statement.
<br/>
The "trusted allies" list should provide you with most of the gains you might expect from password sharing. Use this feature...
</section>
<section id="acc_age" title="Account Age">
Depending on their ages, newly created accounts face a certain amount of limitations that are lifted over time:<ul>
<li>Your account has to be 10 days old to allow cash transfer</li>
<li>Your account has to be 10 days old to allow for diplomatic exchange of technologies</li>
</ul>
</section>
<section id="grule_acc_inact" title="Inactive accounts">
Inactive accounts are accounts on which no activity hasn't occured in a certain amount of time. Those accounts will be neutralised. This means they will still exist in the database but won't be involved in any current game anymore. You may be able to reactivate them but you'll have to rejoin all the games you were playing.
</section>
<section id="grule_acc_priv" title="Privacy Warning">
In order to check on suspicious behaviour from some players the game administrators might have to look into the database for insult messages and such. As a consequence you have to be aware that they might read your messages. So be careful about what you may say in those.
<br/>
You also have to be aware that no messages are actually deleted even if you delete them in-game. They are kept in the database with a "deleted" flag.
</section>
</lwdoc>

View file

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Alliance</title>
<section id="alliance_bas" title="Basic concepts">
An alliance is a group of players who have decided to team up and work together to be stronger in the game. An alliance is identified by its tag, which usual consists of a short hand for its name. An alliance has a leader and is composed of members of different custom ranks. Depending on the privileges attached to their rank members have access to various types of features on the alliance page. An alliance can be either a democracy (members can vote for their leader) or a dictature (no voting system). Alliance specific forums can also be created by members of sufficient rank and their access to members can be restricted according to their rank.
</section>
<section id="alliance_join" title="Creating / joining an alliance" linkto="alliance_create">
At the beginning of the game you don't belong to any alliance. You can then choose among several options:<ul>
<li>Remain a lone gunman</li>
<li>Join an existing alliance</li>
<li>Create a new alliance</li>
</ul>
We'll have a closer look at the two last options in the corresponding manual section.
</section>
<section id="alliance_memb" title="As member of an alliance">
The internal organisation of an alliance is usually set up by its leadership and we won't cover those matters in this manual.
<br/>
As member of an alliance and depending on your rank inside the alliance you may have access to various alliance management features. You are invited to read the manual sections covering the features you have access to to learn more about them.
</section>
<section id="alliance_manag" title="Alliance management" linkto="alliance_manage">
The alliance management pages provide you with useful information about the alliance in the same trend as the alliance information previously described or listings of members and controlled planets. It also offers means to manage members, alliance specific forums and ranks. The various sections of this part of the manual describe those features.
</section>
<section file="alliance_create.lwdoc"/>
<section file="alliance_manage.lwdoc"/>
</lwdoc>

View file

@ -0,0 +1,47 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Creating / Joining an Alliance</title>
<section id="ajoin_intro" title="Introduction">
At the beginning of the game you don't belong to any alliance. You can then choose among several options:<ul>
<li>Remain a lone gunman</li>
<li>Join an existing alliance</li>
<li>Create a new alliance</li>
</ul>
We'll have a closer look at the two last options in the following paragraphs.
</section>
<section id="ajoin_join" title="Join an alliance">
Before joining an alliance you have to know what the existing alliances are and which ones might be looking for new members. Several means at are your disposal:<ul>
<li>The general forums: among the general forums there is a recrutment forum in which alliances which are recruting new members can advertise. You can choose one from there</li>
<li>The rankings: on the ranking page, there is an alliance ranking section from which you can pick your future alliance.</li>
<li>The maps: there is an alliance display mode for the maps which reveals alliance tags on the map. You can select a neighbouring alliance to send a joining request to.</li>
</ul>
Once you've selected an alliance to join or in order to choose one you might be interested in getting more data on the alliance. The alliance information section of the alliance page allows you to do just that.
<br/>
Once you've made you decision about the alliance you want to join you may send a joining request. It's what the Join an alliance section of the page is for. In order to send a joining request you have to type the alliance tag in the relevant text field and click the Send request button.
<br/>
The section of the page now present a status on the current sent request. In case you'd change you mind you can click the Cancel Request button to cancel your request.
<br/>
A message will be sent to your account and stored in the Internal Transmission folder once your joining request is accepted or rejected.
<br/>
Keep also in mind that you can only send one request at once and can only be member of one alliance at a time.
</section>
<section id="ajoin_info" title="Alliance information">
Providing the alliance tag in the text field and clicking the display information button reveals:<ul>
<li>Alliance name: full length name of the alliance</li>
<li>Leader: name of the player leading the alliance</li>
<li>Rank: rank of the alliance in the alliance ranking</li>
<li>Points: number of points for the alliance in the rankings</li>
<li>Planets: total number of planets controlled by members of this alliance</li>
<li>Avg. coordinates: average coodinates of the planets controlled by this alliance</li>
</ul>
</section>
<section id="ajoin_creat" title="Create a new alliance">
In order to create a new alliance you have to provide two different elements in the relevant text fields of this section of the page:<ul>
<li>Alliance tag: it's the short hand used for joining request and diplays on the maps and so on</li>
<li>Alliance name: complete name of the alliance</li>
</ul>
You can now click the Create this alliance button. Your alliance will be created and you'll have a lot to do to manage it, as presented in other sections of this manual.
</section>
</lwdoc>

View file

@ -0,0 +1,173 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Alliance Management</title>
<section id="amanag_intro" title="Introduction">
The alliance management pages provide you with useful information about the alliance in the same trend as the alliance information previously described or listings of members and controlled planets. It also offers means to manage members, alliance specific forums and ranks. The various sections of this part of the manual describe those features.
</section>
<section id="amanag_main" title="Main page">
<section id="alliance_manag_main_intro" title="Introduction">
This section present the main elements concerning the alliance along with means to acquire data about other alliances and a way to leave it.
</section>
<section id="amanag_main_curr" title="Current alliance">
This part of the page displays your status inside the alliance (leader or member) along with useful data similar to those displayed in the Alliance Information part. See this manual section for an exact list.
<br/>
If you are leader of the alliance and have a successor you can choose to step down by clicking the corresponding button in this part of the page. Your successor will automatically become the new leader of the alliance.
<br/>
The Leave button also allows you to leave the alliance whenever you want.
</section>
<section id="amanag_main_sett" title="General settings">
The leader can change here some general settings for the alliance:<ul>
<li>Government: it can be either Dictatorial (members do have access to any voting facility to elect a new leader) or Democratic (members can vote for their leader). The goverment system can be chosen by using the radio button in front of the government system to select.</li>
<li>Successor: a member name can be put in the texfield. This member will automatically become the alliance leader if the current one loses all his planets, steps down or leaves the alliance.</li>
</ul>
Once data are changed in this section, two buttons appear. The Update button allows to take changes into account. The Reset button reverts to previous settings.
</section>
<section id="amanag_main_info" title="Alliance information">
It's the same system as when you have'nt joined an alliance yet.
</section>
</section>
<section id="amanag_list" title="Listings">
<section id="amanag_list_intro" title="Introduction">
This section provides different listings linked with alliances:<ul>
<li>Alliance Planets: lists the planets belonging to the alliance</li>
<li>Alliance Members: lists the players who are members of the alliance</li>
<li>Planets under Attack: lists the planets which are part of the alliance and currently are under attack</li>
</ul>
It also offers common features for all lists.
</section>
<section id="amanag_list_comm" title="Common features">
At the top of the page the Listing drop down list allows to switch among listings.
<br/>
You can also chose the number of elements to display per page with the coresponding drop down list. When several pages are necessary a specific drop down list appear to allow you to move between pages.
<br/>
A search facility is also provided. When it is relevant you can either choose to search a planet or a player name by selected the radio button before the item you're interested in. When filling in the search textfield the listing will be automatically limited to the items containing the string you've typed in wherever it may be in the whole name.
</section>
<section id="amanag_list_plan" title="Alliance Planets">
This lists all planets in the alliance including for each of them:<ul>
<li>Coordinates: coordinates of the planets</li>
<li>Planet: name of the planet</li>
<li>Owner: name of the player who owns the planet</li>
<li>Factories: total number of factories on the planet</li>
<li>Turrets: total number of turrets on the planet</li>
</ul>
In this listing, clicking on the title of one column allows to order the list according to the values of that field. Depending on the direction of the arrow which appears the order is ascending or descending. Clicking again on the same title changes the order from ascending to descending and the other way around.
<br/>
A colour code is used to allow you to see if planets are under attack at a glance; these are displayed in red.
</section>
<section id="amanag_list_memb" title="Alliance Members">
This lists all members in the alliance including:<ul>
<li>Name: name of the player</li>
<li>Rank: rank of the player inside the alliance; see rank administration of this manual to learn more about the alliance rank system</li>
</ul>
In this listing, clicking on the title of one column allows to order the list according to the values of that field. Depending on the direction of the arrow which appears the order is ascending or descending. Clicking again on the same title changes the order from ascending to descending and the other way around.
<br/>
If you have sufficient privileges a checkbox is diplayed before each member name. Checking the box displays some actions features at the bottom of the page including two buttons:<ul>
<li>Kick: to kick the selected members out of the alliance</li>
<li>Change their rank: to change the rank of the selected members to the rank selected in the drop down list displayed afterwards.</li>
</ul>
</section>
<section id="amanag_list_att" title="Planets under Attack">
This lists planets belonging to the alliance which are currently under attack along with useful information such as:<ul>
<li>Coordinates: coordinates of the planet under attack</li>
<li>Planet: name of the planet under attack</li>
<li>Owner: name of the player who owner the planet under attack</li>
<li>Def. Power: power of the fleets which defend the planet</li>
<li>Att. Power: power of the fleets which attack the planet</li>
<li>Defenders: list of names of players who are currently defending the planet</li>
<li>Attackers: list of names of players who are currently attacking the planet</li>
</ul>
For each planet under attack a colour code represents the current defense status compared to enemy fleets:<ul>
<li>Green: defending fleets have more than 3 times the enemy average power. It's very likely no support is needed and defending fleets should win</li>
<li>Red: attacking fleets have more than 3 times the defending average power. It's very like the defenses will be defeated</li>
<li>Grey: the average power difference between defending and attacking fleets isn't that big and the outcome of the battle isn't obvious</li>
</ul>
In this listing, clicking on the title of one column allows to order the list according to the values of that field. Depending on the direction of the arrow which appears the order is ascending or descending. Clicking again on the same title changes the order from ascending to descending and the other way around.
<br/>
You have to be aware that the information provided in this listing may not be 100% accurate. Indeed the are influenced by technologies of the communications area and are subject to electronic counter measures (encryption methods and such) as long as electronic counter counter measures (jamming). The accuracy of the data displayed depends both on the level of technology you and the enemy have in the field.
</section>
</section>
<section id="amanag_requ" title="Pending requests">
When a player requests to join an alliance for which you can manage pending joining requests a message is sent to your account and stored in the Internal Transmissions folder.
<br/>
The Pending Requests part of the Alliance page displays the list of pending joining requests. To accept or reject a given player you have to check the checkbox in front of his name and click the relevant button: Accept or Reject.
</section>
<section id="amanag_forum" title="Forums administration">
<section id="amanag_forum_intro" title="Introduction">
This section of the alliance management page allows you to perform administration tasks on the alliance specific forums. You can both create and manage those forums from here.
</section>
<section id="amanag_forum_creat" title="Create a forum">
The Create a forum link in the top right corner of the page directs you to a forum creating form you have to fill in properly in order to create a new forum. Before creating the forum you have to provide the following information:<ul>
<li>Forum name: in this textfield you have to type a new name for the future forum</li>
<li>New threads: you have to select who will be allowed to create new threads in the forum by clicking the radio button before the option you're interested in. It can be either Everyone or Moderators only</li>
<li>Initial position: this drop down list allows you to select where to place the forum in the forum management page compared to the other existing forums</li>
<li>Description: in this textarea you can type in a longer description of the forum</li>
<li>Forum access: in this section you have to decide for an access level for each of the customised ranks defined for the alliance. In order to do so you have to check the checkbox located before the rank(s) you want to change access for. Three buttons will appear at the bottom of the page to allow you to manage the access level of the given rank(s):<ul>
<li>No access: in order to forbid access to that forum to members of this rank click on the Give no access button</li>
<li>Standard access: in order to provide access with no extra privileges to the forum for members of that rank click the Give standard access button</li>
<li>Moderators: in order to give moderator privileges for that forum to the members of this rank click the Make moderator button</li>
</ul>
</li>
</ul>
You can now either click the OK button to create the forum or the Cancel one to cancel your changes.
</section>
<section id="amanag_forum_manag" title="Manage forums">
Once created, all forums are listed in the Alliance Forums page along with:<ul>
<li>Name and description: name and description of the forum along with useful links</li>
<li>New threads: information about who can create new threads in that forum</li>
</ul>
Along with each forum name and description a set of links allow to manage them:<ul>
<li>Edit: goes back to the forum creation form with prefilled data for the current forum so that you can make changes</li>
<li>Delete: allows you to delete the given forum</li>
<li>Move down: allows you to move the forum down in the list</li>
<li>Move up: allows you to move the forum up in the list</li>
</ul>
</section>
</section>
<section id="amanag_rank" title="Ranks admininistration">
<section id="alliance_manag_rank_intro" title="Introduction">
This section of the alliance management page allows you to both create and manage customised ranks of members of your alliance. These ranks are linked with a set of alliance features that you define here.
</section>
<section id="amanag_rank_creat" title="Create a Rank">
The Create a rank link at the top right corner of the page directs you to a rank creation for you have to fill in. In order to create a rank you have to provide the following information:<ul>
<li>Designation: name of the rank as it will appear in the members' listing</li>
<li>List access: this drop down list allows you to select which alliance listing will be displayed for players of this rank. It can be either:<ul>
<li>Detailed planet list: all lists are available</li>
<li>Planet list: a less complete planet list is displayed</li>
<li>Member list: only the member list is available, the planet list is hidden</li>
<li>No access: no listing is displayed</li>
</ul>
</li>
<li>List of planets under attack: check this checkbox so that the player can see the list of planets currently under attack</li>
<li>Diplomatic contact: use this radio buttons to make members of this rank diplomatic contact for the alliance or not. As diplomatic contact members receive messages sent to the alliance</li>
<li>Can vote: use this radio button to allow members of this rank to vote or not in democratic alliances</li>
<li>Can apply for presidency: use this radio button to allow members of this rank to apply for presidency or not in democratic alliances</li>
<li>Member management: the following items allow you to decide what role in member management the players of this rank will have:<ul>
<li>Accept pending requests: use this radio button to allow members of this rank to accept pending joining request</li>
<li>Kick members: use this radio button to allow members of this rank to kick members of not. If the Only members of a specific rank option is chosen, a list of all currently existing ranks will be displayed with checkboxes before each rank. Check the boxes before the ranks you want the members of ths rank to be allowed to kick.</li>
<li>Change ranks: use this radio button to allow members of this rank to change the rank of other members or not. If the Only members of a specific rank option is chosen, a list of all currently existing ranks will be displayed with checkboxes before each rank. Check the boxes before the ranks you want the members of this rank to be allowed to promote / demote.</li>
</ul>
</li>
<li>Forum access: the following items allow you to decide what forum access the members of the new rank will have:<ul>
<li>Forum administrator: use this radio button to make members of the new rank forum administrators. As such they'd have all privileges on all forums and the following items will be hidden</li>
<li>Forum access: for each existing forum a radio button allows you to chose an access level for members of the new rank. It can be either No access, User or Moderator.</li>
</ul>
</li>
</ul>
Once you've made your modificaction you can either click the Ok button to create the new rank or the cancel button to cancel the changes.
</section>
<section id="amanag_rank_manag" title="Manage ranks">
The Rank Administration page provides a list of all defined ranks for the alliance along with useful links including:<ul>
<li>Rank name: name of the rank as defined during its creation</li>
<li>Actions: actions which can be performed on the rank. It can be either edit or delete. The default rank Standard member can't be deleted but only edited</li>
<li>Members: number of members of this rank in the alliance</li>
</ul>
For each rank several actions are possible:<ul>
<li>[ + ]: clicking on this symbol before the name of the rank displays a short description based on the privileges attached to this rank</li>
<li>Edit: clicking on this link directs you to the rank creation page with prefilled values for the current rank so that you can make changes.</li>
<li>Delete: this link allows you to delete a rank. If the alliance has members who currently have this rank a drop down list of available ranks is displayed which allows you to choose to what rank to demote the members who have to rank to delete</li>
</ul>
</section>
</section>
</lwdoc>

View file

@ -0,0 +1,27 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Trusted Allies</title>
<section id="tall_bas" title="Basic concepts">
In Legacy Worlds you can entrust other players with control of your fleets while you're not online. This page allows you to manage the list of players you want to trust with your fleets in those circumstances along as to know which players might trust you with their fleets.
</section>
<section id="tall_add" title="Add Ally">
Typing the name of a player in the provided textfield in this section of the page and clicking the Add button adds the player to your trusted allies list. You can add up to 5 players to the list.
</section>
<section id="tall_list" title="Allies List">
This list present your trusted allies in an ordered way. The different shades of green represent trust levels. When you're not online the player who can move your first is the first online player in the ordered trusted allies list, that is to say the online player with the higher trust level.
<br/>
A checkbox is displayed in front of each player name in the list. You have to check the checkbox in front of a name to select the corresponding player. You can perfom several actions on selected players:<ul>
<li>Remove: clicking on the Remove button removes the selected player from the trusted allies list</li>
<li>Up: clicking on the Up button moves the selected player up in the trusted allies list</li>
<li>Down: clicking on the down button moves the selected player down in the trusted allies list</li>
</ul>
</section>
<section id="tall_play" title="Players who trust you">
This list present all players who trust you, including:<ul>
<li>Player: name of the player who has you in his trusted allies list</li>
<li>Trust Level: level of trust at which you are located in this player's list, that is to say your rank in his trusted allies list</li>
</ul>
</section>
</lwdoc>

View file

@ -0,0 +1,17 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Background</title>
<section id="bg_holocaust" title="The holocaust">
Land, resources, religion, ideology, colour of skin, power... any cause is worth it. A fight, a war. It could be now, it could be tomorrow. Does it really matter? In the end, the result is all the same: devasted cities, wastelands, undrinkable water, polluted soil and scattered survivors. After years of internal conflicts and devastating wars humanity has finally achieved its ultimate goal: the devastation of its home planet, Earth. What hope is there for those faced with an impossible task: survival on a radioactive piece of rock which could collapse into space dust at any time. The only option left for the remaining survivors of the holocaust: flee to the stars in the hope of finding a new home and rebuilding their civilisation.
</section>
<section id="bg_journey" title="The long journey">
Hundreds of ships were launched into deep space. Their hope: finding a suitable planet, one that can sustain life as they knew it, one where they could settle and rebuild, one that they might take better care of than the previous one. They searched for years for such harbor, safe haven.Going deeper and deeper into the galaxy. Where noone has gone before.
</section>
<section id="bg_arrival" title="The arrival">
As commandant of a small group of colonists you've finally managed to find a planet matching the required parameters and you're about to start rebuilding on it. It will be up to you to make it grow into a new galactic empire within a hostile universe. To achieve that goal you'll have to find allies among the other Earth refugees who settled in the neighbouring star systems and fight those willing to spoil your hard work.
<br/>
It will also be up to you to provide your citizens with what they might need and encourage the scientists of the expedition in their research to achieve new technological breakthroughs. It will be up to you to fufill Earth's legacy...
</section>
</lwdoc>

View file

@ -0,0 +1,60 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Battles</title>
<section id="battle_intro" title="Introduction">
<i>Battles</i> regulate the way military engagements occure in LegacyWorlds. The next parapgraphs describe how battles are managed in game.
When entering into <i>battle mode</i>, fleets remain <i>unavailable</i> until a <mlink to="ticks_tick">battle tick</mlink> has occured on the stellar object they are orbiting.
</section>
<section id="battle_rul" title="Battle rules">
<section id="battle_rul_cond" title="Battle conditions">
Battles occure when the following conditions are met:<ul>
<li><mlink to="ipp_ot">Location</mlink>: the fleets have to be at the same location. Same location means <i>orbiting the same stellar object</i>. Two fleets <i>in <mlink to="move_gen_hypnorm_hyp">hyperspace</mlink> don't engage in battle</i> because the particular nature of this parallel dimension renders weapons inefficient</li>
<li><mlink to="move_pract_order_change_mod">Fleets' mode</mlink>: the <mlink to="move_pract_order_change_mod">modes</mlink> of the fleets have to be different ((one in defense and one in attack at least)</li>
<li><mlink to="vacation_mode">Vacation mode</mlink>: in the case of an attack on a planet, the attacked planet has to belong to a player who isn't in <mlink to="vacation_mode">vacation mode</mlink></li>
<li><mlink to="planet">Planet</mlink>: a battle also occures when a fleet is in attack mode on a planet, be it defended by <mlink to="fleets">fleets</mlink> or <mlink to="ship_cat_list">turrets</mlink> or not</li>
</ul>
</section>
<section id="battle_rul_comp" title="Battle computations">
<i>Battle computations</i> correspond to the calculation of the outcome of a battle. They are regulated by the <i>following rules</i>:<ul>
<li><i>Battle computations</i> take place at <mlink to="ticks_tick">Battle ticks</mlink>, every 4 hours</li>
<li>The <i>losses</i> of <mlink to="ships_cat_list">ships</mlink> and <mlink to="ship_cat_list">turrets</mlink> for each side are calculating <i>depending on relative average power</i> and <i>fleet composition</i> of each side</li>
<li>The <i>primary factor</i> taken into account is the <i>relative <mlink to="ship_cat_pow">power</mlink></i> between attacking and defending <mlink to="fleets">fleets</mlink>. The bigger the difference, the more losses the smaller fleet will sustain and the less losses the bigger fleet will have</li>
<li>The <i>number of <mlink to="ships_cat_list">ships of each type</mlink></i> being detroyed depends on <i>fleet composition</i>. The more ships of one category the more will be destroyed</li>
</ul>
</section>
</section>
<section id="battle_report" title="Battle reports">
Each time a <mlink to="ticks_tick">battle tick</mlink> during which you have been <i>engaged in battle has occured</i>, a <i>battle report</i> is sent in your <mlink to="msg_int">Internal Transmissions</mlink> folder by your <i>Military Advisor</i>. This report includes <i>for each location</i> a description of the <mlink to="fleets">fleets</mlink> in presence and the outcome:<ul>
<li><i>Fleet categories</i>: the report includes up to <i>three categories</i> of <mlink to="fleets">fleets</mlink>:<ul>
<li><i>own fleets</i> (green)</li>
<li><i>friendly fleets</i> (blue)</li>
<li><i>enemy fleets</i> (red)</li>
</ul></li>
<li><i>Fleet composition</i>: for each group of <mlink to="fleets">fleets</mlink> is displayed the <i>composition of the fleet</i> before the battle (<i>Start</i> Column) and the losses (<i>Losses</i> column) for <mlink to="ships_cat_list">each ship category</mlink> present and for <mlink to="ships_cat_list">Turrets</mlink> if any, along with the same data in <mlink to="ship_cat_pow">power of the fleet</mlink></li>
<li><i>Comment</i>: at the bottom of the <i>Battle Report</i> the <i>Military Advisor</i> provides some <i>insights on the next move to make</i></li>
</ul>
</section>
<section id="battle_ownchange" title="Planet owner change">
<section id="battle_ownchange_intro" title="Introduction">
<i>When attacking a planet with sufficient forces</i>, a point is reached where <i>all defenses have been destroyed</i>, be they <mlink to="ships_cat_list">ships</mlink> or <mlink to="ships_cat_list">turrets</mlink>. At the next <mlink to="ticks_tick">hour tick</mlink> is then computed if anyone could <i>take control of the planet</i>. Owner change is decided based on the rules described in the next paragraphs.
</section>
<section id="battle_ownchange_ga" title="Planetary control">
The <i>control over the planet</i> can only <i>change</i> if the <i>ground assault troups have a i<mlink to="ship_cat_ga">sufficient control</mlink> over the population</i>. A single company can't control a whole planet, whatever elite they are, can't they?
<br/>
As a consequence a player has to have more <mlink to="ship_cat_ga">GAs ships</mlink> than the number of <mlink to="ship_cat_ga">GA ships</mlink> required to <mlink to="ship_cat_ga">control the population</mlink>, in order <i>to take control of the planet</i>.
<br/>
At the <i>beginning of the game</i>, the troups transported in <i>1 GA ship</i> can control <i>200 population units</i>. This number can be increased through <mlink to="technology">technological advances</mlink> such as:<ul>
<li><mlink to="tech_39">Exoskeleton</mlink></li>
<li><mlink to="tech_26">Nanofiber Armor</mlink></li>
<li><mlink to="tech_54">Self-repairing Exoskeleton</mlink></li>
</ul>
</section>
<section id="battle_ownchange_play" title="Player gaining control">
In some cases, <i>several players</i> with <mlink to="fleets">fleets</mlink> including <mlink to="ship_cat_ga">GA ships</mlink> may be attacking the same <mlink to="planet">planet</mlink> at once. When <i>several players</i> are attacking the same <mlink to="planet">planet</mlink>, <i>control over the planet</i> is given to the one who <i>has the capacity to control the more population</i>.
<br/>
It doesn't necessarily mean that the player with the more <mlink to="ship_cat_ga">GA ships</mlink> will gain control. Everything depends on the level of <mlink to="technology">technology</mlink> each player involved has.
</section>
</section>
</lwdoc>

View file

@ -0,0 +1,29 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Communications</title>
<section id="com_intro" title="Introduction">
There are two major means of communication in LegacyWorlds: a messaging system and forums. These allow you to keep in touch with other players both inside your own alliance and outside of it.
</section>
<section id="com_page" title="Communications Overview Page" linkto="communications_page">
This page sums up your current status towards the messaging system and the forums. It allows to see at a glance where to read and where you attention is needed when things come to communications. This manual page describes the contents of this page.
</section>
<section id="com_msg" title="Messaging System" linkto="messages">
The Messaging System in Legacy Worlds is very similar to a simple mail client. It allows for folder creation to manage and store messages and offers a linear or threaded view of messages. In the bottom left part of the messaging system pages there is a link that allows you to switch to the forums. The various features are described in more details in the Messaging System section of the manual.
</section>
<section id="com_for" title="Forums" linkto="forums">
Those forums are very similar to those you might find in any message board.
There are several categories of forums:<ul>
<li>Legacy Worlds Forums:- these are used by the staff to make announcements and by layers to report bugs and ask for new features.</li>
<li>General Forums:- these are used for general discussions about the game and beyond.</li>
<li>Legacy Worlds - Public beta 5:- these are public forums which are specific for Beta 5. They include alliance recruitment forums and such.</li>
<li>Alliance specific Forums:- these are the forums of each individual alliance. Their name correspond to the alliance name.</li>
</ul>
Forum features and forum categories are described more precisely in the Forums section of the manual.
</section>
<section file="communications_page.lwdoc"/>
<section file="messages.lwdoc"/>
<section file="forums.lwdoc"/>
</lwdoc>

View file

@ -0,0 +1,55 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Communications Overview Page</title>
<section id="comp_intro" title="Introduction">
This page sums up your current status towards the messaging system and the forums. It allows to see at a glance where to read and where you attention is needed when things come to communications. This manual page describes the contents of this page.
<br/>
This page in split in two sections:<ul>
<li>Private Messages: this left part of the page presents an overview of the status of your messaging system</li>
<li>Forums: this right part of the part provides a summary about both general and alliance forums</li>
</ul>
The next parts of the manual page will describe each.
</section>
<section id="comp_msg" title="Private Messages">
<section id="comp_msg_intro" title="Introduction">
This left part of the page presents data related to the messaging system.
<br/>
It first of all provides a Compose a Message which directs you to the message edition form where you can write a private message to send to either a player, a planet, or an alliance diplomatic staff.
<br/>
The next two sections of the page will be described in the next paragraphs.
</section>
<section id="comp_msg_def" title="Default Folders">
This part of the page presents the list of the three default folders that are available for all accounts:<ul>
<li>Inbox</li>
<li>Internal Transmissions</li>
<li>Outbox</li>
</ul>
For each of those folder, the name of the folder is the link to the contents of the folder.
<br/>
Next to the folder name, the total number of message contained in the folder is displayed. If unread messages are located in one folder, the number of unread messages is presented between brackets.
</section>
<section id="comp_msg_cus" title="Custom Folders">
This part of the page present the list of all the custom folders you have created, if any. For each of those folder, the name of the folder is the link to the contents of the folder.
<br/>
Next to the folder name, the total number of message contained in the folder is displayed. If unread messages are located in one folder, the number of unread messages is presented between brackets.
<br/>
Below the list of custom folders a Manage Custom folders link directs you to the folder management page.
</section>
</section>
<section id="comp_for" title="Forums">
<section id="comp_for_lists" title="List">
The right part of the page presents a list of all available forums. This list is split into two sections:<ul>
<li>General forums: those forums are available to all players. They are organised in categories that are also displayed in the list</li>
<li>Alliance forums: if you're a member of an alliance and the leadership of the alliance has created forums, the forums you have access to are listed here. Only specific members of the alliance have access to each alliance forum, depending on the access rules set up on the alliance forum management page.</li>
</ul>
</section>
<section id="comp_for_dat" title="Displayed data">
For each forum or forum category in the list, the name is the a link to the forum page of this particular forum or forum category.
<br/>
Along the name is displayed the number of topics or threads in the forum. If there are unread topics, the number of unread threads is displayed after the number of topics between brackets.
</section>
</section>
</lwdoc>

View file

@ -0,0 +1,34 @@
<?xml version="1.0"?>
<lwdoc>
<version>beta5</version>
<language>en</language>
<title>Diplomacy</title>
<section id="diplo_intro" title="Introduction">
Diplomacy covers a lot of concepts concerning in game interactions of players outside of the direct communication means. The major element is the alliance system which allows players to build up teams. The diplomatic section of the game allows you also to manage list of enemy and trusted players. Diplomacy is also a way to acquire technologies you can't research on your own and to exchange planets and fleets through the marketplace. The main Diplomacy page provides an overview of all these topics.
</section>
<section id="diplo_page" title="Main Diplomacy Page" linkto="diplomacy_page">
This page provides an overview of your alliance if your part of one along with an overview of your allies and enemies and of your messaged. It includes shortcuts for the major elements in this area. The different sections of the page are the topic of the corresponding manual section.
</section>
<section id="diplo_alliance" title="Alliance" linkto="alliance">
An alliance is a group of players who have decided to team up and work together to be stronger in the game. Alliance related topics are detailed in the Alliance section of the manual.
</section>
<section id="diplo_enem" title="Enemies" linkto="enemies">
This page allows you to keep a list of enemy players and alliance. This topic is discussed in more details in the Enemies manual section.
</section>
<section id="diplo_tall" title="Trusted allies" linkto="allies.lwdoc">
In Legacy Worlds you can entrust other players with control of your fleets while you're not online. This page is presented in the manual in the Trusted Allies section.
</section>
<section id="diplo_res" title="Research exchanges" linkto="tech_exchange">
As the complete technological tree isn't available to one given player, you'll have to acquire some technologies from other players through diplomatic exchanges in order to obtain technologies you don't have access to. This feature is the topic of this manual section.
</section>
<section id="diplo_market" title="Marketplace">
They might not be diplomatic relations per se but economic relations might be considered as a first step towards establishing more solid agreements. As such the marketplace is the place where you can buy or accept and sell or give fleets and planets in LegacyWorlds.
</section>
<section file="diplomacy_page.lwdoc"/>
<section file="alliance.lwdoc"/>
<section file="enemies.lwdoc"/>
<section file="allies.lwdoc"/>
<section file="tech_exchange.lwdoc"/>
<section file="marketplace.lwdoc"/>
</lwdoc>

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