mirror of
https://github.com/Shadowss/TravianZ.git
synced 2026-07-22 12:36:09 +00:00
Major refactor: Extract Database and Automation into domain-specific trait files
### Core Architecture Refactor - Split the `Database.php` class into domain-specific traits under `GameEngine/Database/`. - Split the `Automation` class into domain-specific traits under `GameEngine/Automation/`. - Grouped methods by functional domain for improved maintainability and navigation. - Preserved 100% backward compatibility. - No logic or behavioral changes. - Pure structural refactor.
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationAccountMaintenance.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Account deletion, inactive accounts, bans, invitations, ##
|
||||
## climbers ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationAccountMaintenance {
|
||||
|
||||
|
||||
private function clearDeleting() {
|
||||
global $database;
|
||||
|
||||
$needDelete = $database->getNeedDelete();
|
||||
if(count($needDelete) > 0) {
|
||||
|
||||
//Remove the time limit, otherwise deleting players with 80 or more villages couldn't be deleted in one run
|
||||
@set_time_limit(0);
|
||||
|
||||
foreach($needDelete as $need) {
|
||||
$need['uid'] = (int) $need['uid'];
|
||||
|
||||
//Get the villages which have to be deleted
|
||||
$needVillages = $database->getVillagesID($need['uid']);
|
||||
|
||||
//Delete all villages
|
||||
$database->DelVillage($needVillages);
|
||||
|
||||
for($i = 0;$i < 20; $i++){
|
||||
$q = "SELECT id FROM ".TB_PREFIX."users where friend".$i." = ".$need['uid']." or friend".$i."wait = ".$need['uid']."";
|
||||
$array = $database->query_return($q);
|
||||
foreach($array as $friend){
|
||||
$database->deleteFriend($friend['id'],"friend".$i);
|
||||
$database->deleteFriend($friend['id'],"friend".$i."wait");
|
||||
}
|
||||
}
|
||||
|
||||
$database->updateUserField($need['uid'], 'alliance', 0, 1);
|
||||
|
||||
if($database->isAllianceOwner($need['uid'])){
|
||||
$alliance = $database->getUserAllianceID($need['uid']);
|
||||
$newowner = $database->getAllMember2($alliance);
|
||||
$newleader = $newowner['id'];
|
||||
$q = "UPDATE " . TB_PREFIX . "alidata set leader = ".(int) $newleader." where id = ".(int) $alliance."";
|
||||
$database->query($q);
|
||||
$database->updateAlliPermissions($newleader, $alliance, "Leader", 1, 1, 1, 1, 1, 1, 1);
|
||||
Automation::updateMax($newleader);
|
||||
}
|
||||
|
||||
if (isset($alliance)) $database->deleteAlliance($alliance);
|
||||
|
||||
$q = "DELETE FROM ".TB_PREFIX."hero where uid = ".$need['uid'];
|
||||
$database->query($q);
|
||||
|
||||
$q = "DELETE FROM ".TB_PREFIX."mdata where target = ".$need['uid']." or owner = ".$need['uid'];
|
||||
$database->query($q);
|
||||
|
||||
$q = "DELETE FROM ".TB_PREFIX."ndata where uid = ".$need['uid'];
|
||||
$database->query($q);
|
||||
|
||||
$q = "DELETE FROM ".TB_PREFIX."users where id = ".$need['uid'];
|
||||
$database->query($q);
|
||||
|
||||
$q = "DELETE FROM ".TB_PREFIX."deleting where uid = ".$need['uid'];
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function ClearUser() {
|
||||
global $database;
|
||||
|
||||
if(AUTO_DEL_INACTIVE) {
|
||||
$time = time() - UN_ACT_TIME;
|
||||
|
||||
$q = "INSERT INTO ".TB_PREFIX."deleting SELECT id, UNIX_TIMESTAMP() FROM ".TB_PREFIX."users WHERE timestamp < $time AND tribe IN(1, 2, 3)";
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
|
||||
private function ClearInactive() {
|
||||
global $database;
|
||||
|
||||
if(TRACK_USR) {
|
||||
$timeout = time()-USER_TIMEOUT * 60;
|
||||
$q = "DELETE FROM ".TB_PREFIX."active WHERE timestamp < $timeout";
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
|
||||
private function checkInvitedPlayes() {
|
||||
global $database;
|
||||
|
||||
$q = "SELECT id, invited FROM ".TB_PREFIX."users WHERE invited > 0";
|
||||
$array = $database->query_return($q);
|
||||
|
||||
// preload villages data
|
||||
$userIDs = [];
|
||||
foreach($array as $user) {
|
||||
$userIDs[] = $user['id'];
|
||||
}
|
||||
$database->getProfileVillages($userIDs);
|
||||
|
||||
// continue...
|
||||
foreach($array as $user) {
|
||||
$numusers = mysqli_fetch_array(mysqli_query($database->dblink,"SELECT Count(*) as Total FROM ".TB_PREFIX."users WHERE id = ".(int) $user['invited']), MYSQLI_ASSOC);
|
||||
if($numusers['Total'] > 0){
|
||||
$varray = count($database->getProfileVillages($user['id']));
|
||||
if($varray > 1){
|
||||
$usergold = $database->getUserField($user['invited'],"gold",0);
|
||||
$gold = $usergold+50;
|
||||
$database->updateUserField($user['invited'],"gold",$gold,1);
|
||||
$database->updateUserField($user['id'],"invited",0,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function updateGeneralAttack() {
|
||||
global $database;
|
||||
|
||||
mysqli_query($database->dblink, "
|
||||
UPDATE ".TB_PREFIX."general
|
||||
SET
|
||||
shown = 0
|
||||
WHERE
|
||||
shown = 1 AND
|
||||
`time` < (UNIX_TIMESTAMP() - (86400 * 8))");
|
||||
}
|
||||
|
||||
private function procNewClimbers() {
|
||||
global $database, $ranking;
|
||||
|
||||
$ranking->procRankArray();
|
||||
$climbers = $ranking->getRank();
|
||||
if(count($climbers) > 0){
|
||||
$q = "SELECT week FROM ".TB_PREFIX."medal order by week DESC LIMIT 0, 1";
|
||||
$result = mysqli_query($database->dblink,$q);
|
||||
if(mysqli_num_rows($result)) {
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
$week = $row['week'] + 1;
|
||||
}
|
||||
else $week = 1;
|
||||
|
||||
$q = "SELECT id FROM ".TB_PREFIX."users where oldrank = 0 and id > 5";
|
||||
$array = $database->query_return($q);
|
||||
foreach($array as $user){
|
||||
$newrank = $ranking->getUserRank($user['id']);
|
||||
if($week > 1){
|
||||
for($i = $newrank + 1; $i < count($climbers); $i++) {
|
||||
if(isset($climbers[$i]['userid'])){
|
||||
$oldrank = $ranking->getUserRank($climbers[$i]['userid']);
|
||||
$totalpoints = $oldrank - $climbers[$i]['oldrank'];
|
||||
$database->removeclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}
|
||||
}
|
||||
$database->updateoldrank($user['id'], $newrank);
|
||||
}else{
|
||||
$totalpoints = count($climbers) - $newrank;
|
||||
$database->setclimberrankpop($user['id'], $totalpoints);
|
||||
$database->updateoldrank($user['id'], $newrank);
|
||||
for($i = 1; $i < $newrank; $i++){
|
||||
if(isset($climbers[$i]['userid'])){
|
||||
$oldrank = $ranking->getUserRank($climbers[$i]['userid']);
|
||||
$totalpoints = count($climbers) - $oldrank;
|
||||
$database->setclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}
|
||||
}
|
||||
for($i = $newrank + 1; $i < count($climbers); $i++){
|
||||
if(isset($climbers[$i]['userid'])){
|
||||
$oldrank = $ranking->getUserRank($climbers[$i]['userid']);
|
||||
$totalpoints = count($climbers) - $oldrank;
|
||||
$database->setclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function procClimbers($uid) {
|
||||
global $database, $ranking;
|
||||
|
||||
$ranking->procRankArray();
|
||||
$climbers = $ranking->getRank();
|
||||
if(count($ranking->getRank()) > 0){
|
||||
$q = "SELECT week FROM ".TB_PREFIX."medal order by week DESC LIMIT 0, 1";
|
||||
$result = mysqli_query($database->dblink,$q);
|
||||
if(mysqli_num_rows($result)) {
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
$week = $row['week'] + 1;
|
||||
}
|
||||
else $week = 1;
|
||||
|
||||
$myrank = $ranking->getUserRank($uid);
|
||||
if(isset($climbers[$myrank]['oldrank']) && $climbers[$myrank]['oldrank'] > $myrank){
|
||||
for($i = $myrank + 1; $i <= $climbers[$myrank]['oldrank']; $i++) {
|
||||
if(isset($climbers[$i]['oldrank'])){
|
||||
$oldrank = $ranking->getUserRank($climbers[$i]['userid']);
|
||||
if($week > 1){
|
||||
$totalpoints = $oldrank - $climbers[$i]['oldrank'];
|
||||
$database->removeclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}else{
|
||||
$totalpoints = count($ranking->getRank()) - $oldrank;
|
||||
$database->setclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isset($climbers[$myrank]['oldrank'])){
|
||||
if($week > 1){
|
||||
$totalpoints = $climbers[$myrank]['oldrank'] - $myrank;
|
||||
$database->addclimberrankpop($climbers[$myrank]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$myrank]['userid'], $myrank);
|
||||
}else{
|
||||
$totalpoints = count($ranking->getRank()) - $myrank;
|
||||
$database->setclimberrankpop($climbers[$myrank]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$myrank]['userid'], $myrank);
|
||||
}
|
||||
}
|
||||
}else if(isset($climbers[$myrank]['oldrank']) && $climbers[$myrank]['oldrank'] < $myrank){
|
||||
for($i = $climbers[$myrank]['oldrank']; $i < $myrank; $i++) {
|
||||
if(isset($climbers[$i]['oldrank'])){
|
||||
$oldrank = $ranking->getUserRank($climbers[$i]['userid']);
|
||||
if($week > 1){
|
||||
$totalpoints = $climbers[$i]['oldrank'] - $oldrank;
|
||||
$database->addclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}else{
|
||||
$totalpoints = count($ranking->getRank()) - $oldrank;
|
||||
$database->setclimberrankpop($climbers[$i]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$i]['userid'], $oldrank);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isset($climbers[$myrank-1]['oldrank'])){
|
||||
if($week > 1){
|
||||
$totalpoints = $myrank - $climbers[$myrank-1]['oldrank'];
|
||||
$database->removeclimberrankpop($climbers[$myrank-1]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$myrank-1]['userid'], $myrank);
|
||||
}else{
|
||||
$totalpoints = count($ranking->getRank()) - $myrank;
|
||||
$database->setclimberrankpop($climbers[$myrank-1]['userid'], $totalpoints);
|
||||
$database->updateoldrank($climbers[$myrank-1]['userid'], $myrank);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$ranking->procARankArray();
|
||||
$aid = $database->getUserField($uid,"alliance",0);
|
||||
if(count($ranking->getRank()) > 0 && $aid != 0){
|
||||
$ally = $database->getAlliance($aid);
|
||||
$memberlist = $database->getAllMember($ally['id']);
|
||||
$oldrank = 0;
|
||||
|
||||
$memberIDs = [];
|
||||
foreach($memberlist as $member) {
|
||||
$memberIDs[] = $member['id'];
|
||||
}
|
||||
$data = $database->getVSumField($memberIDs,"pop");
|
||||
|
||||
if (count($data)) {
|
||||
foreach ($data as $row) {
|
||||
$oldrank += $row['Total'];
|
||||
}
|
||||
}
|
||||
|
||||
if($ally['oldrank'] != $oldrank){
|
||||
if($ally['oldrank'] < $oldrank) {
|
||||
$totalpoints = $oldrank - $ally['oldrank'];
|
||||
$database->addclimberrankpopAlly($ally['id'], $totalpoints);
|
||||
$database->updateoldrankAlly($ally['id'], $oldrank);
|
||||
} else
|
||||
if($ally['oldrank'] > $oldrank) {
|
||||
$totalpoints = $ally['oldrank'] - $oldrank;
|
||||
$database->removeclimberrankpopAlly($ally['id'], $totalpoints);
|
||||
$database->updateoldrankAlly($ally['id'], $oldrank);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function checkBan() {
|
||||
global $database;
|
||||
|
||||
mysqli_query($database->dblink, "
|
||||
UPDATE ".TB_PREFIX."banlist as b
|
||||
JOIN ".TB_PREFIX."users as u ON b.uid = u.id
|
||||
SET
|
||||
b.active = 0,
|
||||
u.access = 2
|
||||
WHERE
|
||||
b.active = 1 AND
|
||||
b.`end` < UNIX_TIMESTAMP() AND
|
||||
b.`end` > 0");
|
||||
}
|
||||
|
||||
public static function updateMax($leader) {
|
||||
global $bid18, $database;
|
||||
|
||||
$q = mysqli_fetch_array(mysqli_query($database->dblink,"SELECT Count(*) as Total FROM " . TB_PREFIX . "alidata where leader = ". (int) $leader), MYSQLI_ASSOC);
|
||||
if ($q['Total'] > 0) {
|
||||
$villages = $database->getVillagesID2($leader);
|
||||
$max = 0;
|
||||
|
||||
// cache resource levels
|
||||
$vilIDs = [];
|
||||
foreach($villages as $village){
|
||||
$vilIDs[$village['wref']] = true;
|
||||
}
|
||||
$database->cacheResourceLevels(array_keys($vilIDs));
|
||||
|
||||
foreach($villages as $village){
|
||||
$field = $database->getResourceLevel($village['wref'], false);
|
||||
for($i = 19; $i <= 40; $i++){
|
||||
if($field['f'.$i.'t'] == 18){
|
||||
$level = $field['f'.$i];
|
||||
$attri = $bid18[$level]['attri'];
|
||||
}
|
||||
}
|
||||
if($attri > $max){
|
||||
$max = $attri;
|
||||
}
|
||||
}
|
||||
$q = "UPDATE ".TB_PREFIX."alidata set max = ".(int) $max." where leader = ".(int) $leader;
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationBuildQueue.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Building completion, WW, demolitions, research ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationBuildQueue {
|
||||
|
||||
|
||||
private function buildComplete() {
|
||||
global $database;
|
||||
|
||||
$time = time();
|
||||
// IDs of villages that were affected by this building completion update,
|
||||
// used to calculate statistical data at the end
|
||||
$villagesAffected = [];
|
||||
// holds additional conditions when updating loopcon records in the bdata table
|
||||
$loopconUpdates = [];
|
||||
// this will hold IDs of bdata table records to delete
|
||||
$dbIdsToDelete = [];
|
||||
|
||||
// get all pending builds that should be complete by now
|
||||
$res = $database->query_return(
|
||||
"SELECT
|
||||
id, wid, field, level, type, timestamp
|
||||
FROM
|
||||
".TB_PREFIX."bdata
|
||||
WHERE
|
||||
timestamp < $time and master = 0"
|
||||
);
|
||||
|
||||
// preload village data
|
||||
$vilIDs = [];
|
||||
foreach($res as $indi) {
|
||||
$vilIDs[$indi['wid']] = true;
|
||||
}
|
||||
$vilIDs = array_keys($vilIDs);
|
||||
$database->getProfileVillages($vilIDs, 5);
|
||||
$database->getEnforceVillage($vilIDs, 0);
|
||||
|
||||
// complete buildings
|
||||
foreach($res as $indi) {
|
||||
// store village ID for later for statistical updates
|
||||
$villageData = $database->getVillageFields($indi['wid'],'owner, maxcrop, maxstore, starv, pop');
|
||||
$villageOwner = $villageData['owner'];
|
||||
$villagesAffected[] = (int) $indi['wid'];
|
||||
$fieldsToSet = [];
|
||||
|
||||
$q = "UPDATE ".TB_PREFIX."fdata SET f".$indi['field']." = ".$indi['level'].", f".$indi['field']."t = ".$indi['type']." WHERE vref = ".(int) $indi['wid'];
|
||||
|
||||
if($database->query($q)) {
|
||||
// this will be the level we brought the building to now
|
||||
$level = $indi['level'];
|
||||
|
||||
// TODO: magic numbers into constants (for building types below)
|
||||
|
||||
// update capacity if we updated a warehouse or a granary
|
||||
if (in_array($indi['type'], [10, 11, 38, 39])) {
|
||||
[$fieldDbName, $max] = $this->updateStorageCapacity($indi['type'], $level, $villageData);
|
||||
$fieldsToSet[$fieldDbName] = $max;
|
||||
}
|
||||
|
||||
// if we updated Embassy, update maximum members that the alliance can take
|
||||
if($indi['type'] == 18) Automation::updateMax($villageOwner);
|
||||
|
||||
// World Wonder completion handling (Natar attacks, winner lock, last-upgrade time)
|
||||
if ($indi['type'] == 40) $this->completeWorldWonder($indi);
|
||||
|
||||
// TODO: find out what exactly these conditions are for
|
||||
// no special military conditioning for Teutons and Gauls
|
||||
if ($database->getUserField($villageOwner, "tribe", 0) != 1) $loopconUpdates[$indi['wid']] = '';
|
||||
else
|
||||
{
|
||||
// special condition for Roman military buildings
|
||||
if ($indi['field'] > 18) $loopconUpdates[$indi['wid']] = ' AND field > 18';
|
||||
else $loopconUpdates[$indi['wid']] = ' AND field < 19';
|
||||
}
|
||||
|
||||
$dbIdsToDelete[] = (int) $indi['id'];
|
||||
}
|
||||
|
||||
//Update starvation data
|
||||
$database->addStarvationData($indi['wid']);
|
||||
|
||||
// update the requested fields, all at once
|
||||
$database->setVillageFields($indi['wid'], array_keys($fieldsToSet), array_values($fieldsToSet));
|
||||
}
|
||||
|
||||
// update statistical data for affected villages
|
||||
foreach ($villagesAffected as $affected_id) $this->recountPop($affected_id, false);
|
||||
|
||||
// update data that can be done in one swoop instead of using multiple update queries
|
||||
// no special checks for Romans
|
||||
foreach ($loopconUpdates as $villageId => $updateCondition) {
|
||||
$database->query(
|
||||
"UPDATE
|
||||
".TB_PREFIX."bdata
|
||||
SET
|
||||
loopcon = 0
|
||||
WHERE
|
||||
loopcon = 1 AND
|
||||
master = 0 AND
|
||||
wid = ".$villageId.$updateCondition);
|
||||
}
|
||||
|
||||
// delete all processed entries
|
||||
if (count($dbIdsToDelete)) {
|
||||
$database->query( "DELETE FROM " . TB_PREFIX . "bdata WHERE id IN(" . implode( ',', $dbIdsToDelete ) . ")" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the side effects of completing a World Wonder (type 40) build:
|
||||
* launch the Natar attack waves, lock out further winners at level 100,
|
||||
* and record the last upgrade time.
|
||||
*/
|
||||
private function completeWorldWonder($indi) {
|
||||
global $database;
|
||||
|
||||
if (($indi['level'] % 5 == 0 || $indi['level'] > 95) && $indi['level'] != 100) {
|
||||
$this->startNatarAttack($indi['level'], $indi['wid'], $indi['timestamp']);
|
||||
}
|
||||
|
||||
//now can't be more than one winner if ww to level 100 is build by 2 users or more on same time
|
||||
if ($indi['level'] == 100) {
|
||||
mysqli_query($database->dblink,"TRUNCATE ".TB_PREFIX."bdata");
|
||||
}
|
||||
|
||||
// Update ww last finish upgrade
|
||||
$qW = "UPDATE ".TB_PREFIX."fdata set ww_lastupdate = ".time()." where vref = ".(int) $indi['wid'];
|
||||
$database->query($qW);
|
||||
}
|
||||
|
||||
private function researchComplete() {
|
||||
global $database;
|
||||
|
||||
$time = time();
|
||||
$deleteIDs = [];
|
||||
$tdata = [];
|
||||
$abdata = [];
|
||||
|
||||
$q = "SELECT tech, vref, id FROM ".TB_PREFIX."research where timestamp < $time";
|
||||
$dataarray = $database->query_return($q);
|
||||
|
||||
foreach($dataarray as $data) {
|
||||
$sort_type = substr($data['tech'],0,1);
|
||||
switch($sort_type) {
|
||||
case "t":
|
||||
if (!isset($tdata[$data['vref']])) $tdata[$data['vref']] = [];
|
||||
$tdata[$data['vref']][] = $data['tech'].' = 1';
|
||||
break;
|
||||
case "a":
|
||||
case "b":
|
||||
if (!isset($abdata[$data['vref']])) $abdata[$data['vref']] = [];
|
||||
$abdata[$data['vref']][] = $data['tech']." = ".$data['tech']." + 1";
|
||||
break;
|
||||
}
|
||||
$deleteIDs[] = (int) $data['id'];
|
||||
}
|
||||
|
||||
// execute queries with consolidated research data
|
||||
if (count($tdata)) {
|
||||
foreach ( $tdata as $vid => $preparedData ) {
|
||||
$q = "UPDATE ".TB_PREFIX."tdata SET ".implode(', ', $preparedData)." WHERE vref = ".$vid;
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($abdata)) {
|
||||
foreach ( $abdata as $vid => $preparedData ) {
|
||||
$q = "UPDATE ".TB_PREFIX."abdata SET ".implode(', ', $preparedData)." WHERE vref = ".$vid;
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
|
||||
if (count($deleteIDs)) {
|
||||
$q = "DELETE FROM " . TB_PREFIX . "research where id IN(" . implode( ', ', $deleteIDs ) . ")";
|
||||
$database->query( $q );
|
||||
}
|
||||
}
|
||||
|
||||
private function demolitionComplete() {
|
||||
global $database;
|
||||
|
||||
$varray = $database->getDemolition();
|
||||
foreach($varray as $vil) {
|
||||
if ($vil['lvl'] < 0) {
|
||||
$database->delDemolition($vil['vref'], true);
|
||||
continue;
|
||||
}
|
||||
if ($vil['timetofinish'] <= time()) {
|
||||
$type = $database->getFieldType($vil['vref'],$vil['buildnumber']);
|
||||
$level = $database->getFieldLevel($vil['vref'],$vil['buildnumber']);
|
||||
|
||||
$newLevel = max(0, $level - 1);
|
||||
|
||||
$buildarray = $GLOBALS["bid".$type];
|
||||
|
||||
if ($type == 10 || $type == 38) {
|
||||
$database->query("
|
||||
UPDATE ".TB_PREFIX."vdata
|
||||
SET
|
||||
`maxstore` = IF(`maxstore` - ".$buildarray[$level]['attri']." <= ".STORAGE_BASE.", ".STORAGE_BASE.", `maxstore` - ".$buildarray[$level]['attri'].")
|
||||
WHERE
|
||||
wref=".(int) $vil['vref']);
|
||||
}
|
||||
|
||||
if ($type == 11 || $type == 39) {
|
||||
$database->query("
|
||||
UPDATE ".TB_PREFIX."vdata
|
||||
SET
|
||||
`maxcrop` = IF(`maxcrop` - ".$buildarray[$level]['attri']." <= ".STORAGE_BASE.", ".STORAGE_BASE.", `maxcrop` - ".$buildarray[$level]['attri'].")
|
||||
WHERE
|
||||
wref=".(int) $vil['vref']);
|
||||
}
|
||||
|
||||
if ($level == 1) $clear = ",f".$vil['buildnumber']."t=0";
|
||||
else $clear = "";
|
||||
|
||||
if ($database->getVillageField($vil['vref'], 'natar') == 1 && $type == 40) $clear = ""; //fix by ronix - fixed by iopietro
|
||||
$q = "UPDATE ".TB_PREFIX."fdata SET f".$vil['buildnumber']."=".$newLevel." ".$clear." WHERE vref=".(int)$vil['vref'];
|
||||
$database->query($q);
|
||||
|
||||
$pop = $this->getPop($type, $newLevel);
|
||||
$database->modifyPop($vil['vref'], $pop[0], 1);
|
||||
$this->procClimbers($database->getVillageField($vil['vref'], 'owner'));
|
||||
$database->delDemolition($vil['vref'], true);
|
||||
|
||||
if ($type == 18) Automation::updateMax($database->getVillageField($vil['vref'], 'owner'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function MasterBuilder() {
|
||||
global $database;
|
||||
|
||||
$q = "SELECT id, wid, type, level, field, timestamp FROM ".TB_PREFIX."bdata WHERE master = 1";
|
||||
$array = $database->query_return($q);
|
||||
|
||||
foreach($array as $master) {
|
||||
$owner = $database->getVillageField($master['wid'], 'owner');
|
||||
$tribe = $database->getUserField($owner, 'tribe', 0);
|
||||
$villwood = $database->getVillageField($master['wid'], 'wood');
|
||||
$villclay = $database->getVillageField($master['wid'], 'clay');
|
||||
$villiron = $database->getVillageField($master['wid'], 'iron');
|
||||
$villcrop = $database->getVillageField($master['wid'], 'crop');
|
||||
$type = $master['type'];
|
||||
$level = $master['level'];
|
||||
$buildarray = $GLOBALS["bid".$type];
|
||||
$buildwood = $buildarray[$level]['wood'];
|
||||
$buildclay = $buildarray[$level]['clay'];
|
||||
$buildiron = $buildarray[$level]['iron'];
|
||||
$buildcrop = $buildarray[$level]['crop'];
|
||||
$ww = count($database->getBuildingByType($master['wid'], 40));
|
||||
|
||||
if($tribe == 1){
|
||||
if($master['field'] < 19){
|
||||
$bdata = $database->getDorf1Building($master['wid']);
|
||||
$bdataTotal = count($bdata);
|
||||
$bbdata = count($database->getDorf2Building($master['wid']));
|
||||
}else{
|
||||
$bdata = $database->getDorf2Building($master['wid']);
|
||||
$bdataTotal = count($bdata);
|
||||
$bbdata = count($database->getDorf1Building($master['wid']));
|
||||
}
|
||||
}else{
|
||||
$bdata = array_merge($database->getDorf1Building($master['wid']), $database->getDorf2Building($master['wid']));
|
||||
$bdataTotal = $bbdata = count($bdata);
|
||||
}
|
||||
|
||||
if($database->getUserField($owner, 'plus', 0) > time() || $ww > 0){
|
||||
if($bbdata < 2) $inbuild = 2;
|
||||
else $inbuild = 1;
|
||||
}
|
||||
else $inbuild = 1;
|
||||
|
||||
$usergold = $database->getUserField($owner, 'gold', 0);
|
||||
|
||||
if($bdataTotal < $inbuild && $buildwood <= $villwood && $buildclay <= $villclay && $buildiron <= $villiron && $buildcrop <= $villcrop && $usergold > 0){
|
||||
$time = $master['timestamp'] + time();
|
||||
|
||||
if(!empty($bdata)){
|
||||
foreach($bdata as $masterLoop) $time += ($masterLoop['timestamp'] - time());
|
||||
}
|
||||
|
||||
if($bdataTotal == 0) $database->updateBuildingWithMaster($master['id'], $time, 0);
|
||||
else $database->updateBuildingWithMaster($master['id'], $time, 1);
|
||||
|
||||
$database->updateUserField($owner, 'gold', --$usergold, 1);
|
||||
$database->modifyResource($master['wid'], $buildwood, $buildclay, $buildiron, $buildcrop, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationHero.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Hero adventures, regeneration, level-up, hero revival ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationHero {
|
||||
|
||||
|
||||
/**
|
||||
* T4 Hero port (Phase 3+4): process adventure arrivals (sort_type 20,
|
||||
* rewards + ntype 26 report + return movement), returns (sort_type 21,
|
||||
* hero re-enters units.hero, loot credited), top up offer lists, then
|
||||
* finalize ended auctions and restock the NPC merchant.
|
||||
* Fully feature-flagged - a no-op unless NEW_FUNCTIONS_HERO_T4 is enabled.
|
||||
*/
|
||||
private function heroAdventureComplete() {
|
||||
if (!defined('NEW_FUNCTIONS_HERO_T4') || !NEW_FUNCTIONS_HERO_T4) {
|
||||
return;
|
||||
}
|
||||
|
||||
$adventures = new HeroAdventure();
|
||||
$adventures->processArrivals();
|
||||
$adventures->processReturns();
|
||||
$adventures->generateOffersBatch();
|
||||
|
||||
$auctions = new HeroAuction();
|
||||
$auctions->processFinished();
|
||||
$auctions->seedNpcAuctions();
|
||||
}
|
||||
|
||||
private function updateHero() {
|
||||
global $database, $hero_levels;
|
||||
|
||||
$harray = $database->getHero();
|
||||
if(!empty($harray)){
|
||||
// first of all, prepare all unit data at once for these heroes
|
||||
$heroVillageIDs = [];
|
||||
foreach($harray as $hdata) {
|
||||
$heroVillageIDs[] = $hdata['wref'];
|
||||
}
|
||||
|
||||
// load data for those prepared IDs
|
||||
$unitData = $database->getUnit($heroVillageIDs);
|
||||
|
||||
// now do the math
|
||||
$lastUpdateIDs = [];
|
||||
$timeNow = time();
|
||||
foreach($harray as $hdata){
|
||||
$columns = [];
|
||||
$columnValues = [];
|
||||
$modes = [];
|
||||
$lastUpdateTime = $timeNow;
|
||||
|
||||
// 1. passive HP regeneration
|
||||
$newHealth = $this->calculateHealthRegen($hdata);
|
||||
|
||||
// 2. level-up + score points
|
||||
$this->mergeHeroColumns($columns, $columnValues, $modes, $this->calculateLevelUp($hdata));
|
||||
|
||||
// 3. revive completion (forces health to 100 and stamps the update time)
|
||||
$revive = $this->handleReviveCompletion($hdata);
|
||||
$this->mergeHeroColumns($columns, $columnValues, $modes, $revive);
|
||||
if ($revive['health'] !== null) $newHealth = $revive['health'];
|
||||
if ($revive['lastUpdate'] !== null) $lastUpdateTime = $revive['lastUpdate'];
|
||||
|
||||
// 4. training completion (does not touch health)
|
||||
$training = $this->handleTrainingCompletion($hdata);
|
||||
$this->mergeHeroColumns($columns, $columnValues, $modes, $training);
|
||||
if ($training['lastUpdate'] !== null) $lastUpdateTime = $training['lastUpdate'];
|
||||
|
||||
// update health, if needed
|
||||
if ($newHealth > -1) {
|
||||
$columns[] = 'health';
|
||||
$columnValues[] = $newHealth;
|
||||
$modes[] = null;
|
||||
}
|
||||
|
||||
if ($lastUpdateTime != $timeNow) {
|
||||
// last update timestamp
|
||||
$columns[] = 'lastupdate';
|
||||
$columnValues[] = $lastUpdateTime;
|
||||
$modes[] = null;
|
||||
} else {
|
||||
// leave same last update values for multiple heroes to the end
|
||||
$lastUpdateIDs[] = $hdata['heroid'];
|
||||
}
|
||||
|
||||
if (count($columns)) $database->modifyHero($columns, $columnValues, $hdata['heroid'], $modes);
|
||||
}
|
||||
|
||||
if (count($lastUpdateIDs)) {
|
||||
mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "hero SET lastupdate = $timeNow WHERE heroid IN(".implode(', ', $lastUpdateIDs).")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Append a hero column fragment (['columns'=>[], 'values'=>[], 'modes'=>[]])
|
||||
// onto the running modifyHero() arrays, preserving order.
|
||||
private function mergeHeroColumns(&$columns, &$columnValues, &$modes, $fragment) {
|
||||
foreach ($fragment['columns'] as $k => $col) {
|
||||
$columns[] = $col;
|
||||
$columnValues[] = $fragment['values'][$k];
|
||||
$modes[] = $fragment['modes'][$k];
|
||||
}
|
||||
}
|
||||
|
||||
// Passive HP regeneration: returns the new health value, or -1 if unchanged.
|
||||
private function calculateHealthRegen($hdata) {
|
||||
if((time()-$hdata['lastupdate']) >= 1){
|
||||
if($hdata['health'] < 100 and $hdata['health'] > 0){
|
||||
if(SPEED <= 10) $speed = SPEED;
|
||||
else if(SPEED <= 100) $speed = ceil(SPEED / 10);
|
||||
else $speed = ceil(SPEED / 100);
|
||||
|
||||
$reg = $hdata['health'] + $hdata['regeneration'] * 5 * $speed / 86400 * (time() - $hdata['lastupdate']);
|
||||
|
||||
return ($reg <= 100) ? $reg : 100;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Level-up + score points. Returns a column fragment.
|
||||
private function calculateLevelUp($hdata) {
|
||||
global $hero_levels;
|
||||
|
||||
$columns = [];
|
||||
$values = [];
|
||||
$modes = [];
|
||||
|
||||
$herolevel = $hdata['level'];
|
||||
$newLevel = - 1;
|
||||
$scorePoints = false;
|
||||
for ($i = $herolevel + 1; $i < 100; $i++){
|
||||
if($hdata['experience'] >= $hero_levels[$i]){
|
||||
$newLevel = $i;
|
||||
if ($i < 99) $scorePoints = true;
|
||||
}
|
||||
}
|
||||
|
||||
// upgrade hero to a new level, if needed
|
||||
if ($newLevel > -1) {
|
||||
$columns[] = 'level';
|
||||
$values[] = $newLevel;
|
||||
$modes[] = null;
|
||||
}
|
||||
|
||||
// add as many points as needed, if we're below level 100
|
||||
if ($scorePoints) {
|
||||
$columns[] = 'points';
|
||||
$values[] = (5 * ($newLevel - $herolevel));
|
||||
$modes[] = 1;
|
||||
}
|
||||
|
||||
return ['columns' => $columns, 'values' => $values, 'modes' => $modes, 'health' => null, 'lastUpdate' => null];
|
||||
}
|
||||
|
||||
// Revive completion: marks the hero unit alive and clears the revive flag.
|
||||
// Returns a column fragment plus the health (100) and lastUpdate overrides.
|
||||
private function handleReviveCompletion($hdata) {
|
||||
global $database;
|
||||
|
||||
if($hdata['trainingtime'] < time() && $hdata['inrevive'] == 1){
|
||||
mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "units SET hero = 1 WHERE vref = ".(int) $hdata['wref']."");
|
||||
|
||||
return [
|
||||
'columns' => ['dead', 'inrevive', 'inrevive'],
|
||||
'values' => [0, 0, 0],
|
||||
'modes' => [null, null, null],
|
||||
'health' => 100,
|
||||
'lastUpdate' => (int) $hdata['trainingtime'],
|
||||
];
|
||||
}
|
||||
|
||||
return ['columns' => [], 'values' => [], 'modes' => [], 'health' => null, 'lastUpdate' => null];
|
||||
}
|
||||
|
||||
// Training completion: marks the hero unit alive and clears the training flag.
|
||||
// Returns a column fragment plus the lastUpdate override (health untouched).
|
||||
private function handleTrainingCompletion($hdata) {
|
||||
global $database;
|
||||
|
||||
if($hdata['trainingtime'] < time() && $hdata['intraining'] == 1){
|
||||
mysqli_query($database->dblink,"UPDATE " . TB_PREFIX . "units SET hero = 1 WHERE vref = ".(int) $hdata['wref']);
|
||||
|
||||
return [
|
||||
'columns' => ['dead', 'intraining'],
|
||||
'values' => [0, 0],
|
||||
'modes' => [null, null],
|
||||
'health' => null,
|
||||
'lastUpdate' => (int) $hdata['trainingtime'],
|
||||
];
|
||||
}
|
||||
|
||||
return ['columns' => [], 'values' => [], 'modes' => [], 'health' => null, 'lastUpdate' => null];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationMarket.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Trade routes, marketplace deliveries, merchant returns ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationMarket {
|
||||
|
||||
|
||||
private function delTradeRoute() {
|
||||
global $database;
|
||||
|
||||
$database->delTradeRoute();
|
||||
}
|
||||
|
||||
private function TradeRoute() {
|
||||
global $database;
|
||||
$time = time();
|
||||
$q = "SELECT `from`, wood, clay, iron, crop, wid, deliveries, id FROM ".TB_PREFIX."route where timestamp < $time";
|
||||
$dataarray = $database->query_return($q);
|
||||
|
||||
$vilIDs = [];
|
||||
foreach($dataarray as $data) {
|
||||
$vilIDs[$data['wid']] = true;
|
||||
$vilIDs[$data['from']] = true;
|
||||
}
|
||||
$vilIDs = array_keys($vilIDs);
|
||||
$database->getVillageByWorldID($vilIDs);
|
||||
|
||||
foreach($dataarray as $data) {
|
||||
$targettribe = $database->getUserField($database->getVillageField($data['from'], "owner"), "tribe", 0);
|
||||
$this->sendResource2($data['wood'], $data['clay'], $data['iron'], $data['crop'], $data['from'], $data['wid'], $targettribe, $data['deliveries']);
|
||||
$database->editTradeRoute($data['id'], "timestamp", 86400, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private function marketComplete() {
|
||||
// Two independent phases share a single cutoff timestamp: sort_type = 0
|
||||
// new trade deliveries, then sort_type = 2 resending of resources.
|
||||
$time = microtime(true);
|
||||
$this->marketCompleteDeliveries($time);
|
||||
$this->marketCompleteResends($time);
|
||||
}
|
||||
|
||||
private function marketCompleteDeliveries($time) {
|
||||
global $database, $units;
|
||||
|
||||
$q = "SELECT s.wood, s.clay, s.iron, s.crop, `to`, `from`, endtime, merchant, send, moveid FROM ".TB_PREFIX."movement m, ".TB_PREFIX."send s WHERE m.ref = s.id AND m.proc = 0 AND sort_type = 0 AND endtime < $time";
|
||||
$dataarray = $database->query_return($q);
|
||||
|
||||
foreach($dataarray as $data) {
|
||||
$userData_from = $database->getUserFields($database->getVillageField($data['from'], "owner"), "alliance, tribe", 0);
|
||||
$userData_to = $database->getUserFields($database->getVillageField($data['to'], "owner"), "alliance, tribe", 0);
|
||||
|
||||
if($data['wood'] >= $data['clay'] && $data['wood'] >= $data['iron'] && $data['wood'] >= $data['crop']) $sort_type = 10;
|
||||
elseif($data['clay'] >= $data['wood'] && $data['clay'] >= $data['iron'] && $data['clay'] >= $data['crop']) $sort_type = 11;
|
||||
elseif($data['iron'] >= $data['wood'] && $data['iron'] >= $data['clay'] && $data['iron'] >= $data['crop']) $sort_type = 12;
|
||||
elseif($data['crop'] >= $data['wood'] && $data['crop'] >= $data['clay'] && $data['crop'] >= $data['iron']) $sort_type = 13;
|
||||
|
||||
$to = $database->getMInfo($data['to']);
|
||||
$from = $database->getMInfo($data['from']);
|
||||
|
||||
$ownally = $userData_from['alliance'];
|
||||
$targetally = $userData_to['alliance'];
|
||||
|
||||
// Report filter preferences (#198): skip merchant-transfer notices
|
||||
// according to the saved checkboxes of the involved players.
|
||||
// v4 -> recipient: no report for transfers to own villages
|
||||
// v6 -> recipient: no report for transfers from foreign villages
|
||||
// v5 -> sender: no report for transfers to foreign villages
|
||||
$ownTransfer = ($from['owner'] == $to['owner']);
|
||||
$skipRecipient = $ownTransfer ? !empty($userData_to['v4']) : !empty($userData_to['v6']);
|
||||
if(!$skipRecipient) {
|
||||
$database->addNotice($to['owner'],$to['wref'],$targetally,$sort_type,''.addslashes($from['name']).' send resources to '.addslashes($to['name']).'',''.$from['owner'].','.$from['wref'].','.$data['wood'].','.$data['clay'].','.$data['iron'].','.$data['crop'].'',$data['endtime']);
|
||||
}
|
||||
if(!$ownTransfer && empty($userData_from['v5'])) {
|
||||
$database->addNotice($from['owner'],$to['wref'],$ownally,$sort_type,''.addslashes($from['name']).' send resources to '.addslashes($to['name']).'',''.$from['owner'].','.$from['wref'].','.$data['wood'].','.$data['clay'].','.$data['iron'].','.$data['crop'].'',$data['endtime']);
|
||||
}
|
||||
$database->modifyResource($data['to'],$data['wood'],$data['clay'],$data['iron'],$data['crop'],1);
|
||||
|
||||
// Push protection: record completed cross-player deliveries so the
|
||||
// admin dashboard can compute 7-day resource balance. Best-effort;
|
||||
// skips own-village transfers internally.
|
||||
if (!$ownTransfer) {
|
||||
PushProtection::logTransfer(
|
||||
(int)$from['wref'], (int)$to['wref'],
|
||||
(int)$from['owner'], (int)$to['owner'],
|
||||
(int)$data['wood'], (int)$data['clay'], (int)$data['iron'], (int)$data['crop'],
|
||||
(int)$data['endtime']
|
||||
);
|
||||
}
|
||||
$targettribe = $userData_to["tribe"];
|
||||
$endtime = $units->getWalkingTroopsTime($data['from'], $data['to'], 0, 0, [$targettribe], 0) + $data['endtime'];
|
||||
$database->addMovement(2, $data['to'], $data['from'], $data['merchant'], time(), $endtime, $data['send'], $data['wood'], $data['clay'], $data['iron'], $data['crop']);
|
||||
$database->setMovementProc($data['moveid']);
|
||||
}
|
||||
}
|
||||
|
||||
private function marketCompleteResends($time) {
|
||||
global $database;
|
||||
|
||||
$q1 = "SELECT send, moveid, `to`, wood, clay, iron, crop, `from` FROM ".TB_PREFIX."movement WHERE proc = 0 and sort_type = 2 and endtime < $time";
|
||||
$dataarray1 = $database->query_return($q1);
|
||||
|
||||
$vilIDs = [];
|
||||
foreach($dataarray1 as $data1) {
|
||||
$vilIDs[$data1['to']] = true;
|
||||
$vilIDs[$data1['from']] = true;
|
||||
}
|
||||
$vilIDs = array_keys($vilIDs);
|
||||
$database->getVillageByWorldID($vilIDs);
|
||||
|
||||
foreach($dataarray1 as $data1) {
|
||||
$database->setMovementProc($data1['moveid']);
|
||||
if($data1['send'] > 1){
|
||||
$targettribe1 = $database->getUserFields($database->getVillageField($data1['to'],"owner"),"alliance, tribe",0)['tribe'];
|
||||
$send = $data1['send']-1;
|
||||
$this->sendResource2($data1['wood'],$data1['clay'],$data1['iron'],$data1['crop'],$data1['to'],$data1['from'],$targettribe1,$send);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function sendResource2($wtrans, $ctrans, $itrans, $crtrans, $from, $to, $tribe, $send) {
|
||||
global $bid17, $bid28, $database, $units;
|
||||
|
||||
$availableWood = $database->getWoodAvailable($from);
|
||||
$availableClay = $database->getClayAvailable($from);
|
||||
$availableIron = $database->getIronAvailable($from);
|
||||
$availableCrop = $database->getCropAvailable($from);
|
||||
|
||||
if($availableWood + $availableClay + $availableIron + $availableCrop > 0)
|
||||
{
|
||||
if($availableWood < $wtrans) $wtrans = $availableWood;
|
||||
if($availableClay < $ctrans) $ctrans = $availableClay;
|
||||
if($availableIron < $itrans) $itrans = $availableIron;
|
||||
if($availableCrop < $crtrans) $crtrans = $availableCrop;
|
||||
|
||||
$merchant2 = ($this->getTypeLevel(17, $from) > 0)? $this->getTypeLevel(17, $from) : 0;
|
||||
$used2 = $database->totalMerchantUsed($from, false);
|
||||
$merchantAvail2 = $merchant2 - $used2;
|
||||
$carrymap = array(1 => 500, 2 => 1000, 3 => 750, 6 => 500, 7 => 750, 8 => 500, 9 => 750);
|
||||
$maxcarry2 = isset($carrymap[$tribe]) ? $carrymap[$tribe] : 750;
|
||||
$maxcarry2 *= TRADER_CAPACITY;
|
||||
|
||||
if($this->getTypeLevel(28, $from) != 0) {
|
||||
$maxcarry2 *= $bid28[$this->getTypeLevel(28, $from)]['attri'] / 100;
|
||||
}
|
||||
|
||||
$resource = [$wtrans, $ctrans, $itrans, $crtrans];
|
||||
$reqMerc = ceil((array_sum($resource) - 0.1) / $maxcarry2);
|
||||
|
||||
if($merchantAvail2 > 0 && $reqMerc <= $merchantAvail2) {
|
||||
if($database->getVillageState($to)) {
|
||||
$timetaken = $units->getWalkingTroopsTime($from, $to, 0, 0, [$tribe], 0);
|
||||
$res = $resource[0] + $resource[1] + $resource[2] + $resource[3];
|
||||
if($res > 0){
|
||||
$reference = $database->sendResource($resource[0], $resource[1], $resource[2], $resource[3], $reqMerc, 0);
|
||||
$database->modifyResource($from, $resource[0], $resource[1], $resource[2], $resource[3], 0);
|
||||
$database->addMovement(0, $from, $to, $reference, microtime(true), microtime(true) + $timetaken, $send);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationMedals.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Weekly player/alliance medals, statistics reset ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationMedals {
|
||||
|
||||
|
||||
/**
|
||||
* Function for automate medals - by yi12345 and Shadow
|
||||
*
|
||||
*/
|
||||
|
||||
function medals() {
|
||||
global $database;
|
||||
|
||||
// Check the timing window; $time is the next "last awarded" stamp to write.
|
||||
$time = $this->shouldAwardMedalsNow();
|
||||
if ($time === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exclude BANNED (0), MH (8), ADMIN (9)
|
||||
$userFilter = "id > 5 AND access NOT IN (0,8,9)";
|
||||
|
||||
$week = $this->getNextMedalWeek('medal');
|
||||
$allyweek = $this->getNextMedalWeek('allimedal');
|
||||
|
||||
$this->awardPlayerMedals($week, $userFilter);
|
||||
$this->resetWeeklyStats('users', $userFilter, "ap=0, dp=0, Rc=0, clp=0, RR=0");
|
||||
$this->awardAllianceMedals($allyweek);
|
||||
$this->resetWeeklyStats('alidata', '', "ap=0, dp=0, RR=0, clp=0");
|
||||
|
||||
// Update last awarded time
|
||||
$database->query("UPDATE ".TB_PREFIX."config SET lastgavemedal=".(int)$time);
|
||||
}
|
||||
|
||||
// Returns the next "lastgavemedal" stamp to write if medals are due now, or
|
||||
// null to skip this run. On the very first run after server start it only
|
||||
// schedules the next run (and returns null).
|
||||
private function shouldAwardMedalsNow() {
|
||||
global $database;
|
||||
|
||||
$giveMedal = false;
|
||||
$time = null;
|
||||
$q = "SELECT lastgavemedal FROM ".TB_PREFIX."config";
|
||||
$result = mysqli_query($database->dblink, $q);
|
||||
if ($result) {
|
||||
$row = mysqli_fetch_assoc($result);
|
||||
$stime = strtotime(START_DATE) - strtotime(date('d.m.Y')) + strtotime(START_TIME);
|
||||
|
||||
if ($row['lastgavemedal'] == 0 && $stime < time()) {
|
||||
// First run after server start - schedule next run
|
||||
$setDays = round(MEDALINTERVAL / 86400);
|
||||
$newtime = $setDays < 7? strtotime(($setDays + 1).' day midnight') : strtotime('next monday');
|
||||
$database->query("UPDATE ".TB_PREFIX."config SET lastgavemedal = ".(int)$newtime);
|
||||
} elseif ($row['lastgavemedal']!= 0) {
|
||||
$time = $row['lastgavemedal'] + MEDALINTERVAL;
|
||||
$giveMedal = $row['lastgavemedal'] < time();
|
||||
}
|
||||
}
|
||||
|
||||
if (!($giveMedal && MEDALINTERVAL > 0)) {
|
||||
return null;
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
|
||||
// Next week number for a medal table (medal / allimedal).
|
||||
private function getNextMedalWeek($table) {
|
||||
global $database;
|
||||
|
||||
$q = "SELECT week FROM ".TB_PREFIX."$table ORDER BY week DESC LIMIT 1";
|
||||
$res = mysqli_query($database->dblink, $q);
|
||||
return $res && mysqli_num_rows($res)? (mysqli_fetch_assoc($res)['week'] + 1) : 1;
|
||||
}
|
||||
|
||||
// Insert a user medal row.
|
||||
private function insertUserMedal($userid, $category, $place, $week, $points, $img) {
|
||||
global $database;
|
||||
|
||||
$q = "INSERT INTO ".TB_PREFIX."medal (userid, categorie, plaats, week, points, img) VALUES (".
|
||||
(int)$userid.", ".(int)$category.", ".(int)$place.", ".(int)$week.", '".mysqli_real_escape_string($database->dblink, $points)."', '".mysqli_real_escape_string($database->dblink, $img)."')";
|
||||
mysqli_query($database->dblink, $q);
|
||||
}
|
||||
|
||||
// Insert an alliance medal row.
|
||||
private function insertAllianceMedal($allyid, $cat, $place, $week, $points, $img) {
|
||||
global $database;
|
||||
|
||||
$q = "INSERT INTO ".TB_PREFIX."allimedal (allyid, categorie, plaats, week, points, img) VALUES (".(int)$allyid.", '".(int)$cat."', ".(int)$place.", '".(int)$week."', '".mysqli_real_escape_string($database->dblink, $points)."', '".mysqli_real_escape_string($database->dblink, $img)."')";
|
||||
mysqli_query($database->dblink, $q);
|
||||
}
|
||||
|
||||
// Award the top 10 users for a stat field (one category).
|
||||
private function awardTopMedals($field, $category, $imgPrefix, $week, $userFilter) {
|
||||
global $database;
|
||||
|
||||
$q = "SELECT id, $field FROM ".TB_PREFIX."users WHERE $userFilter ORDER BY $field DESC, id DESC LIMIT 10";
|
||||
$res = mysqli_query($database->dblink, $q);
|
||||
$i = 0;
|
||||
while ($row = mysqli_fetch_array($res)) {
|
||||
$i++;
|
||||
$this->insertUserMedal($row['id'], $category, $i, $week, $row[$field], $imgPrefix.$i);
|
||||
}
|
||||
}
|
||||
|
||||
// Award milestone ribbons for 3/5/10 appearances in a top3 or top10 category.
|
||||
private function awardMilestoneMedals($field, $sourceCat, $topLimit, $targetCat, $imgBase, $week, $userFilter) {
|
||||
global $database;
|
||||
|
||||
$res = mysqli_query($database->dblink, "SELECT id FROM ".TB_PREFIX."users WHERE $userFilter ORDER BY $field DESC, id DESC LIMIT 10");
|
||||
while ($u = mysqli_fetch_array($res)) {
|
||||
$cnt = mysqli_fetch_row(mysqli_query($database->dblink,
|
||||
"SELECT COUNT(*) FROM ".TB_PREFIX."medal WHERE userid=".(int)$u['id']." AND categorie=".(int)$sourceCat." AND plaats<=".(int)$topLimit))[0];
|
||||
|
||||
$map = ['3' => ['Three', $imgBase.'0_1'], '5' => ['Five', $imgBase.'1_1'], '10' => ['Ten', $imgBase.'2_1']];
|
||||
if (isset($map[$cnt])) {
|
||||
$this->insertUserMedal($u['id'], $targetCat, 0, $week, $map[$cnt][0], $map[$cnt][1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Player medals: top 10 of each category, the attack+defense bonus, then milestones.
|
||||
private function awardPlayerMedals($week, $userFilter) {
|
||||
global $database;
|
||||
|
||||
// Top 10 for each category
|
||||
$this->awardTopMedals('ap', 1, 't2_', $week, $userFilter); // Attackers of the week (cat 1)
|
||||
$this->awardTopMedals('dp', 2, 't3_', $week, $userFilter); // Defenders of the week (cat 2)
|
||||
$this->awardTopMedals('Rc', 3, 't1_', $week, $userFilter); // Climbers of the week (cat 3)
|
||||
$this->awardTopMedals('clp', 10, 't6_', $week, $userFilter); // Rank climbers of the week (cat 10)
|
||||
$this->awardTopMedals('RR', 4, 't4_', $week, $userFilter); // Robbers of the week (cat 4)
|
||||
|
||||
// --- Bonus: player in both top10 attack AND defense (cat 5) ---
|
||||
$topAttackers = mysqli_query($database->dblink, "SELECT id FROM ".TB_PREFIX."users WHERE $userFilter ORDER BY ap DESC, id DESC LIMIT 10");
|
||||
while ($a = mysqli_fetch_array($topAttackers)) {
|
||||
$topDefenders = mysqli_query($database->dblink, "SELECT id FROM ".TB_PREFIX."users WHERE $userFilter ORDER BY dp DESC, id DESC LIMIT 10");
|
||||
while ($d = mysqli_fetch_array($topDefenders)) {
|
||||
if ($a['id'] == $d['id']) {
|
||||
$cnt = mysqli_fetch_row(mysqli_query($database->dblink, "SELECT COUNT(*) FROM ".TB_PREFIX."medal WHERE userid=".(int)$a['id']." AND categorie=5"))[0];
|
||||
if ($cnt <= 2) {
|
||||
$texts = [0 => '', 1 => 'twice ', 2 => 'three times '];
|
||||
$this->insertUserMedal($a['id'], 5, 0, $week, $texts[$cnt], 't22'.$cnt.'_1');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Milestone ribbons for 3/5/10 times in top3 or top10 ---
|
||||
// Attackers milestones
|
||||
$this->awardMilestoneMedals('ap', 1, 3, 6, 't12', $week, $userFilter); // top3 attackers
|
||||
$this->awardMilestoneMedals('ap', 1, 10, 12, 't13', $week, $userFilter); // top10 attackers
|
||||
// Defenders milestones
|
||||
$this->awardMilestoneMedals('dp', 2, 3, 7, 't14', $week, $userFilter);
|
||||
$this->awardMilestoneMedals('dp', 2, 10, 13, 't15', $week, $userFilter);
|
||||
// Climbers milestones
|
||||
$this->awardMilestoneMedals('Rc', 3, 3, 8, 't10', $week, $userFilter);
|
||||
$this->awardMilestoneMedals('Rc', 3, 10, 14, 't11', $week, $userFilter);
|
||||
// Rank climbers milestones
|
||||
$this->awardMilestoneMedals('clp', 10, 3, 11, 't20', $week, $userFilter);
|
||||
$this->awardMilestoneMedals('clp', 10, 10, 16, 't21', $week, $userFilter);
|
||||
// Robbers milestones
|
||||
$this->awardMilestoneMedals('RR', 4, 3, 9, 't16', $week, $userFilter);
|
||||
$this->awardMilestoneMedals('RR', 4, 10, 15, 't17', $week, $userFilter);
|
||||
}
|
||||
|
||||
// Alliance medals: top 10 of each category, then the attack+defense bonus.
|
||||
private function awardAllianceMedals($allyweek) {
|
||||
global $database;
|
||||
|
||||
$allyCats = [
|
||||
['ap', 1, 'a2_'],
|
||||
['dp', 2, 'a3_'],
|
||||
['RR', 4, 'a4_'],
|
||||
['clp', 3, 'a1_']
|
||||
];
|
||||
foreach ($allyCats as [$field, $cat, $img]) {
|
||||
$res = mysqli_query($database->dblink, "SELECT id, $field FROM ".TB_PREFIX."alidata ORDER BY $field DESC, id DESC LIMIT 10");
|
||||
$i = 0;
|
||||
while ($r = mysqli_fetch_array($res)) { $i++; $this->insertAllianceMedal($r['id'], $cat, $i, $allyweek, $r[$field], $img.$i); }
|
||||
}
|
||||
|
||||
// Alliance bonus for attack+defense
|
||||
$resA = mysqli_query($database->dblink, "SELECT id FROM ".TB_PREFIX."alidata ORDER BY ap DESC, id DESC LIMIT 10");
|
||||
while ($a = mysqli_fetch_array($resA)) {
|
||||
$resD = mysqli_query($database->dblink, "SELECT id FROM ".TB_PREFIX."alidata ORDER BY dp DESC, id DESC LIMIT 10");
|
||||
while ($d = mysqli_fetch_array($resD)) {
|
||||
if ($a['id'] == $d['id']) {
|
||||
$cnt = mysqli_fetch_row(mysqli_query($database->dblink, "SELECT COUNT(*) FROM ".TB_PREFIX."allimedal WHERE allyid=".(int)$a['id']." AND categorie=5"))[0];
|
||||
if ($cnt <= 2) {
|
||||
$texts = [0 => '', 1 => 'twice ', 2 => 'three times '];
|
||||
$this->insertAllianceMedal($a['id'], 5, 0, $allyweek, $texts[$cnt], 't22'.$cnt.'_1');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the weekly stat columns for every id in a table (optionally filtered).
|
||||
private function resetWeeklyStats($table, $where, $setClause) {
|
||||
global $database;
|
||||
|
||||
$ids = [];
|
||||
$sql = "SELECT id FROM ".TB_PREFIX.$table;
|
||||
if ($where !== '') $sql .= " WHERE ".$where;
|
||||
$res = mysqli_query($database->dblink, $sql);
|
||||
while ($r = mysqli_fetch_row($res)) { $ids[] = (int)$r[0]; }
|
||||
if ($ids) {
|
||||
mysqli_query($database->dblink, "UPDATE ".TB_PREFIX.$table." SET ".$setClause." WHERE id IN(".implode(',', $ids).")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationNatarsWW.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Natars, WW villages/plans, active artifacts ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationNatarsWW {
|
||||
|
||||
|
||||
private function startNatarAttack($level, $vid, $time) {
|
||||
global $database;
|
||||
|
||||
// bad, but should work :D
|
||||
// I took the data from my first ww (first .org world)
|
||||
// TODO: get the algo from the real travian with the 100 biggest offs
|
||||
|
||||
// select the troops^^
|
||||
$troops = $this->getNatarTroopTable();
|
||||
if (isset($troops[$level])) $units = $troops[$level];
|
||||
else return false;
|
||||
|
||||
// get the capital village from the natars
|
||||
$query = mysqli_query($database->dblink,'SELECT `wref` FROM `' . TB_PREFIX . 'vdata` WHERE `owner` = 3 and `capital` = 1 LIMIT 1') or die(mysqli_error($database->dblink));
|
||||
$row = mysqli_fetch_assoc($query);
|
||||
|
||||
// start the attacks
|
||||
$endtime = $time + round(86400 / INCREASE_SPEED);
|
||||
|
||||
// -.-
|
||||
$vid = (int) $vid;
|
||||
mysqli_query($database->dblink,'INSERT INTO `' . TB_PREFIX . 'ww_attacks` (`vid`, `attack_time`) VALUES (' . $vid . ', ' . $endtime . ')');
|
||||
mysqli_query($database->dblink,'INSERT INTO `' . TB_PREFIX . 'ww_attacks` (`vid`, `attack_time`) VALUES (' . $vid . ', ' . ($endtime + 1) . ')');
|
||||
|
||||
// two waves: the second one targets the WW (catapult target 40) one second later
|
||||
$this->launchNatarWave($row['wref'], $vid, $units[0], 0, $time, $endtime);
|
||||
$this->launchNatarWave($row['wref'], $vid, $units[1], 40, $time, $endtime + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire a single Natar attack wave at a World Wonder village.
|
||||
* $unitRow is one troop row [t2, t3, t5, t6, t7, t8]; $ctar1 is the
|
||||
* catapult target slot (0 for the first wave, 40 for the second).
|
||||
*/
|
||||
private function launchNatarWave($source, $vid, $unitRow, $ctar1, $time, $arrival) {
|
||||
global $database;
|
||||
|
||||
$ref = $database->addAttack($source, 0, $unitRow[0], $unitRow[1], 0, $unitRow[2], $unitRow[3], $unitRow[4], $unitRow[5], 0, 0, 0, 3, $ctar1, 0, 0, 0, 20, 20, 0, 20, 20, 20, 20);
|
||||
$database->addMovement(3, $source, $vid, $ref, $time, $arrival);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hard-coded Natar offensive waves indexed by World Wonder level.
|
||||
* Each level holds two waves, each a troop row [t2, t3, t5, t6, t7, t8].
|
||||
*/
|
||||
private function getNatarTroopTable() {
|
||||
return [5 => [[3412, 2814, 4156, 3553, 9, 0], [35, 0, 77, 33, 17, 10]],
|
||||
10 => [[4314, 3688, 5265, 4621, 13, 0], [65, 0, 175, 77, 28, 17]],
|
||||
15 => [[4645, 4267, 5659, 5272, 15, 0], [99, 0, 305, 134, 40, 25]],
|
||||
20 => [[6207, 5881, 7625, 7225, 22, 0], [144, 0, 456, 201, 56, 36]],
|
||||
25 => [[6004, 5977, 7400, 7277, 23, 0], [152, 0, 499, 220, 58, 37]],
|
||||
30 => [[7073, 7181, 8730, 8713, 27, 0], [183, 0, 607, 268, 69, 45]],
|
||||
35 => [[7090, 7320, 8762, 8856, 28, 0], [186, 0, 620, 278, 70, 45]],
|
||||
40 => [[7852, 6967, 9606, 8667, 25, 0], [146, 0, 431, 190, 60, 37]],
|
||||
45 => [[8480, 8883, 10490, 10719, 35, 0], [223, 0, 750, 331, 83, 54]],
|
||||
50 => [[8522, 9038, 10551, 10883, 35, 0], [224, 0, 757, 335, 83, 54]],
|
||||
55 => [[8931, 8690, 10992, 10624, 32, 0], [219, 0, 707, 312, 84, 54]],
|
||||
60 => [[12138, 13013, 15040, 15642, 51, 0], [318, 0, 1079, 477, 118, 76]],
|
||||
65 => [[13397, 14619, 16622, 17521, 58, 0], [345, 0, 1182, 522, 127, 83]],
|
||||
70 => [[16323, 17665, 20240, 21201, 70, 0], [424, 0, 1447, 640, 157, 102]],
|
||||
75 => [[20739, 22796, 25746, 27288, 91, 0], [529, 0, 1816, 803, 194, 127]],
|
||||
80 => [[21857, 24180, 27147, 28914, 97, 0], [551, 0, 1898, 839, 202, 132]],
|
||||
85 => [[22476, 25007, 27928, 29876, 100, 0], [560, 0, 1933, 855, 205, 134]],
|
||||
90 => [[31345, 35053, 38963, 41843, 141, 0], [771, 0, 2668, 1180, 281, 184]],
|
||||
95 => [[31720, 35635, 39443, 42506, 144, 0], [771, 0, 2671, 1181, 281, 184]],
|
||||
96 => [[32885, 37007, 40897, 44130, 150, 0], [795, 0, 2757, 1219, 289, 190]],
|
||||
97 => [[32940, 37099, 40968, 44235, 150, 0], [794, 0, 2755, 1219, 289, 190]],
|
||||
98 => [[33521, 37691, 41686, 44953, 152, 0], [812, 0, 2816, 1246, 296, 194]],
|
||||
99 => [[36251, 40861, 45089, 48714, 165, 0], [872, 0, 3025, 1338, 317, 208]]];
|
||||
}
|
||||
|
||||
private function checkWWAttacks() {
|
||||
global $database;
|
||||
|
||||
$query = mysqli_query($database->dblink,'SELECT vid, attack_time FROM `' . TB_PREFIX . 'ww_attacks` WHERE `attack_time` <= ' . time());
|
||||
while ($row = mysqli_fetch_assoc($query))
|
||||
{
|
||||
// delete the attack
|
||||
$query3 = mysqli_query($database->dblink,'DELETE FROM `' . TB_PREFIX . 'ww_attacks` WHERE `vid` = ' . (int) $row['vid'] . ' AND `attack_time` = ' . (int) $row['attack_time']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the Natars account and spawn artifacts
|
||||
*
|
||||
*/
|
||||
|
||||
private function spawnNatars(){
|
||||
global $database;
|
||||
|
||||
//Check if Natars account is already created and if the time
|
||||
//is come and we have to create Natars and spawn their artifacts
|
||||
if($database->areArtifactsSpawned() || strtotime(START_DATE) + (NATARS_SPAWN_TIME * 86400) > time()) return;
|
||||
|
||||
//Create the Natars account and his capital
|
||||
$this->artifacts->createNatars();
|
||||
|
||||
//Write the system message
|
||||
$database->displaySystemMessage(ARTEFACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn WW Villages
|
||||
*
|
||||
*/
|
||||
|
||||
private function spawnWWVillages(){
|
||||
global $database;
|
||||
|
||||
//Check if Natars account has already been created, if WW villages have already been spawned
|
||||
//and if it's the time to spawn them or not
|
||||
if(!$database->areArtifactsSpawned() || $database->areWWVillagesSpawned() || strtotime(START_DATE) + (NATARS_WW_SPAWN_TIME * 86400) > time()) return;
|
||||
|
||||
//Create WW villages
|
||||
$this->artifacts->createWWVillages();
|
||||
|
||||
//Write the system message
|
||||
$database->displaySystemMessage(WWVILLAGEMSG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn WW Building plans
|
||||
*
|
||||
*/
|
||||
|
||||
private function spawnWWBuildingPlans(){
|
||||
global $database;
|
||||
|
||||
//Check if Natars account is already spawned, if WW building plans have already been spawned
|
||||
//and if it's the time to spawn them or not
|
||||
if(!$database->areArtifactsSpawned() || $database->areArtifactsSpawned(true) || strtotime(START_DATE) + (NATARS_WW_BUILDING_PLAN_SPAWN_TIME * 86400) > time()) return;
|
||||
|
||||
//Create WW building plans
|
||||
$this->artifacts->createWWBuildingPlans();
|
||||
|
||||
//Set the system message to contain the infos of the WW building plans
|
||||
$database->displaySystemMessage(PLAN_INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically activate all artifacts that need to be activated
|
||||
*
|
||||
*/
|
||||
|
||||
private function activateArtifacts() {
|
||||
global $database;
|
||||
|
||||
//Check if there's at least one artifact, if not, return
|
||||
if(!$database->areArtifactsSpawned()) return;
|
||||
|
||||
//Activate the artifacts that need to be activated
|
||||
$this->artifacts->activateArtifacts();
|
||||
}
|
||||
|
||||
private function artefactOfTheFool() {
|
||||
global $database;
|
||||
|
||||
$time = time();
|
||||
$q = "SELECT id, size FROM " . TB_PREFIX . "artefacts where type = 8 AND active = 1 AND del = 0 AND lastupdate <= ".($time - (86400 / (SPEED == 2 ? 1.5 : (SPEED == 3 ? 2 : SPEED))));
|
||||
$array = $database->query_return($q);
|
||||
if ($array) {
|
||||
foreach($array as $artefact) {
|
||||
$kind = rand(1, 7);
|
||||
|
||||
while($kind == 6) $kind = rand(1, 7);
|
||||
|
||||
if($artefact['size'] != 3) $bad_effect = rand(0, 1);
|
||||
else $bad_effect = 0;
|
||||
|
||||
switch($kind) {
|
||||
case 1:
|
||||
$effect = rand(1, 5);
|
||||
break;
|
||||
case 2:
|
||||
$effect = rand(1, 3);
|
||||
break;
|
||||
case 3:
|
||||
$effect = rand(3, 10);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
$effect = rand(2, 4);
|
||||
break;
|
||||
case 7:
|
||||
$effect = rand(1, 6);
|
||||
break;
|
||||
}
|
||||
mysqli_query($database->dblink,"UPDATE ".TB_PREFIX."artefacts SET kind = ". (int) $kind. ", bad_effect = $bad_effect, effect2 = $effect, lastupdate = $time WHERE id = ".(int) $artefact['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationStarvation.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Complete starvation pipeline (starvation*) ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationStarvation {
|
||||
|
||||
|
||||
/**
|
||||
* Function for starvation - by brainiacX and Shadow
|
||||
* Rework by ronix
|
||||
* Refactored by iopietro
|
||||
*/
|
||||
|
||||
private function starvation() {
|
||||
global $database, $technology;
|
||||
|
||||
// Starvation is disabled during the peace period (holidays).
|
||||
if(PEACE) return;
|
||||
|
||||
$time = time();
|
||||
|
||||
// 1. Update starvation data for all villages.
|
||||
$this->starvationUpdateAllVillages();
|
||||
|
||||
// 2. Load villages with negative production.
|
||||
$starvarray = $this->starvationGetVillagesWithDeficit();
|
||||
if (empty($starvarray)) return;
|
||||
|
||||
$vilIDs = array_column($starvarray, 'wref');
|
||||
|
||||
// 3. Prepare caches to reduce queries.
|
||||
$this->starvationPrepareCaches($vilIDs);
|
||||
|
||||
foreach ($starvarray as $starv) {
|
||||
$this->starvationProcessVillage($starv, $time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the starvation table for all villages.
|
||||
**/
|
||||
|
||||
private function starvationUpdateAllVillages() {
|
||||
global $database;
|
||||
$starvarray = $database->getProfileVillages(0, 7);
|
||||
foreach($starvarray as $starv) {
|
||||
$database->addStarvationData($starv['wref']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return villages with crop deficit.
|
||||
**/
|
||||
|
||||
private function starvationGetVillagesWithDeficit() {
|
||||
global $database;
|
||||
return $database->getStarvation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare troop caches.
|
||||
**/
|
||||
|
||||
private function starvationPrepareCaches(array $vilIDs) {
|
||||
global $database;
|
||||
$database->getEnforceVillage($vilIDs, 0);
|
||||
$database->getOasisEnforce($vilIDs, 2);
|
||||
$database->getOasisEnforce($vilIDs, 3);
|
||||
$database->getPrisoners($vilIDs, 1);
|
||||
$database->getMovement(3, $vilIDs, 0);
|
||||
$database->getMovement(4, $vilIDs, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a single village for starvation.
|
||||
**/
|
||||
|
||||
private function starvationProcessVillage($starv, $time) {
|
||||
global $database, $technology;
|
||||
|
||||
$unitarrays = $this->getAllUnits($starv['wref']);
|
||||
// Original upkeep formula
|
||||
$upkeep = $starv['pop'] + $technology->getUpkeep($unitarrays, 0, $starv['wref']);
|
||||
|
||||
$troopData = $this->starvationFindFirstTroopGroup($starv);
|
||||
if (empty($troopData['troops'])) {
|
||||
// No troops exist, only check reset.
|
||||
$this->starvationCheckReset($starv, $upkeep);
|
||||
return;
|
||||
}
|
||||
|
||||
$starvingTroops = $troopData['troops'];
|
||||
$type = $troopData['type'];
|
||||
$subtype = $troopData['subtype'];
|
||||
|
||||
$timedif = $time - $starv['starvupdate'];
|
||||
$cropProd = $database->getCropProdstarv($starv['wref']) - $starv['starv'];
|
||||
|
||||
if($cropProd < 0){
|
||||
// Deficit calculation
|
||||
$starvsec = (abs($cropProd) / 3600);
|
||||
$difcrop = ($timedif * $starvsec);
|
||||
$oldcrop = $database->getVillageField($starv['wref'], 'crop');
|
||||
|
||||
// Use granary crop first for consumption.
|
||||
if ($oldcrop > 100) {
|
||||
$difcrop = $difcrop - $oldcrop;
|
||||
if($difcrop < 0){
|
||||
$difcrop = 0;
|
||||
$newcrop = $oldcrop - $difcrop;
|
||||
$database->setVillageField($starv['wref'], 'crop', $newcrop);
|
||||
}
|
||||
}
|
||||
|
||||
if($difcrop > 0 && $oldcrop <= 0){
|
||||
$this->starvationKillTroops($starv, $starvingTroops, $type, $subtype, $difcrop, $upkeep, $time);
|
||||
}
|
||||
}
|
||||
|
||||
$this->starvationCheckReset($starv, $upkeep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate the first troop group eligible for starvation.
|
||||
* Processing order: oasis enforcement → village enforcement → prisoners → own units → attacks.
|
||||
**/
|
||||
|
||||
private function starvationFindFirstTroopGroup($starv) {
|
||||
global $database;
|
||||
|
||||
$enforceArrays = [
|
||||
$database->getOasisEnforce($starv['wref'], 2),
|
||||
$database->getOasisEnforce($starv['wref'], 3),
|
||||
$database->getEnforceVillage($starv['wref'], 2),
|
||||
$database->getEnforceVillage($starv['wref'], 3)
|
||||
];
|
||||
|
||||
$prisonerArrays = [$database->getPrisoners($starv['wref'], 1)];
|
||||
$unitArrays = ($database->getUnitsNumber($starv['wref'], 0) > 0) ? [[$database->getUnit($starv['wref'])]] : [];
|
||||
$attackArrays = [
|
||||
$database->getMovement(3, $starv['wref'], 0),
|
||||
$database->getMovement(4, $starv['wref'], 1)
|
||||
];
|
||||
|
||||
$allTroopsArray = [$enforceArrays, $prisonerArrays, $unitArrays, $attackArrays];
|
||||
|
||||
foreach($allTroopsArray as $type => $allTroops) {
|
||||
if(!empty($allTroops)){
|
||||
foreach($allTroops as $subtype => $troops){
|
||||
if(!empty($troops)){
|
||||
return [
|
||||
'troops' => reset($troops),
|
||||
'type' => $type,
|
||||
'subtype' => $subtype
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ['troops' => [], 'type' => null, 'subtype' => null];
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill troops according to crop deficit.
|
||||
**/
|
||||
|
||||
private function starvationKillTroops($starv, &$starvingTroops, $type, $subtype, $difcrop, $upkeep, $time) {
|
||||
global $database;
|
||||
|
||||
$tribe = $database->getUserField(($type == 2) ? $starv['owner'] : $database->getVillageField($starvingTroops['from'], "owner"), "tribe", 0);
|
||||
$special = in_array($type, [1, 3]);
|
||||
$start = $special ? 1 : ($tribe - 1) * 10 + 1;
|
||||
$end = $special ? 10 : $tribe * 10;
|
||||
$utype = $special ? 't' : 'u';
|
||||
$heroType = $special ? 't11' : 'hero';
|
||||
|
||||
$killedUnits = [];
|
||||
$totalUnits = 0;
|
||||
$counting = true;
|
||||
|
||||
while($difcrop > 0) {
|
||||
$maxcount = $maxtype = 0;
|
||||
for($i = $start; $i <= $end; $i++) {
|
||||
$units = (isset($starvingTroops[$utype.$i]) ? $starvingTroops[$utype.$i] : 0);
|
||||
if($counting) $totalUnits += $units;
|
||||
if($units > $maxcount){
|
||||
$maxcount = $units;
|
||||
$maxtype = $i;
|
||||
}
|
||||
}
|
||||
if($counting) $counting = false;
|
||||
|
||||
if($maxtype > 0){
|
||||
$starvingTroops[$utype.$maxtype]--;
|
||||
$killedUnits[$maxtype] = ($killedUnits[$maxtype] ?? 0) + 1;
|
||||
// Original per-unit crop consumption formula unchanged.
|
||||
$unitIndex = $special ? $maxtype + ($tribe - 1) * 10 : $maxtype;
|
||||
$difcrop -= $GLOBALS['u'.$unitIndex]['crop'];
|
||||
} else break;
|
||||
}
|
||||
|
||||
$totalKilledUnits = array_sum($killedUnits);
|
||||
$newCrop = 0;
|
||||
|
||||
// Determine whether the hero dies.
|
||||
if($starvingTroops[$heroType] > 0 && ($totalUnits == 0 || $totalUnits == $totalKilledUnits)){
|
||||
$totalKilledUnits += $starvingTroops[$heroType];
|
||||
$totalUnits += $starvingTroops[$heroType];
|
||||
$heroOwner = ($type == 2) ? $starv['owner'] : $database->getVillageField(($type == 3 && $subtype == 1) ? $starvingTroops['to'] : $starvingTroops['from'], "owner");
|
||||
$heroInfo = $database->getHero($heroOwner)[0];
|
||||
$database->modifyHero("dead", 1, $heroInfo['heroid']);
|
||||
$database->modifyHero("health", 0, $heroInfo['heroid']);
|
||||
$newCrop = $GLOBALS['h'.$heroInfo['unit'].'_full'][min($heroInfo['level'], 60)]['crop'] + $difcrop;
|
||||
} else if($maxtype > 0) {
|
||||
$newCrop = $GLOBALS['u'.$maxtype]['crop'];
|
||||
}
|
||||
|
||||
if($totalKilledUnits > 0) {
|
||||
$this->starvationApplyDatabaseChanges($starv, $starvingTroops, $type, $killedUnits, $totalUnits, $totalKilledUnits, $newCrop, $upkeep, $time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply starvation changes to the database.
|
||||
**/
|
||||
|
||||
private function starvationApplyDatabaseChanges($starv, $starvingTroops, $type, $killedUnits, $totalUnits, $totalKilledUnits, $newCrop, $upkeep, $time) {
|
||||
global $database;
|
||||
|
||||
switch($type){
|
||||
case 0: // enforce
|
||||
if($totalKilledUnits < $totalUnits){
|
||||
$database->modifyEnforce($starvingTroops['id'], array_keys($killedUnits), array_values($killedUnits), 0);
|
||||
} else {
|
||||
$database->deleteReinf($starvingTroops['id']);
|
||||
}
|
||||
break;
|
||||
case 1: // prisoners
|
||||
if($totalKilledUnits < $totalUnits){
|
||||
$database->modifyPrisoners($starvingTroops['id'], array_keys($killedUnits), array_values($killedUnits), 0);
|
||||
$database->modifyUnit($starvingTroops['wref'], ["99o"], [$totalKilledUnits], [0]);
|
||||
} else {
|
||||
$database->deletePrisoners($starvingTroops['id']);
|
||||
$database->modifyUnit($starvingTroops['wref'], ["99o"], [$totalUnits], [0]);
|
||||
}
|
||||
break;
|
||||
case 2: // own units
|
||||
$database->modifyUnit($starv['wref'], array_keys($killedUnits), array_values($killedUnits), [0]);
|
||||
break;
|
||||
case 3: // moving attacks.
|
||||
if($totalKilledUnits < $totalUnits){
|
||||
$database->modifyAttack2($starvingTroops['id'], array_keys($killedUnits), array_values($killedUnits), 0);
|
||||
} else {
|
||||
$database->setMovementProc($starvingTroops['moveid']);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$database->modifyResource($starv['wref'], 0, 0, 0, max($newCrop, 0), 1);
|
||||
$database->setVillageField($starv['wref'], ['starv', 'starvupdate'], [$upkeep, $time]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify whether starvation reset is allowed.
|
||||
**/
|
||||
|
||||
private function starvationCheckReset($starv, $upkeep) {
|
||||
global $database;
|
||||
$crop = $database->getCropProdstarv($starv['wref'], false);
|
||||
if ($crop > $upkeep) {
|
||||
$database->setVillageFields($starv['wref'], ['starv', 'starvupdate'], [0, 0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationTraining.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Unit training, hospital/healing, celebrations ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationTraining {
|
||||
|
||||
|
||||
/**
|
||||
* Spital (gid 46) / Spital Mare (gid 48): o parte din trupele proprii moarte
|
||||
* in apararea satului devin ranite, in limita capacitatii spitalului.
|
||||
* Cota: 40% (Spital) / 50% (Spital Mare). Capacitate: nivel x 30 / nivel x 60.
|
||||
* Doar unitatile de lupta (X1-X8); chief, settler si eroul nu pot fi raniti.
|
||||
*/
|
||||
private function applyHospitalWounded($vref, array $deadByUnit) {
|
||||
global $database;
|
||||
|
||||
$hospital = $database->getFieldLevelInVillage($vref, '46');
|
||||
$bighospital = $database->getFieldLevelInVillage($vref, '48');
|
||||
if($hospital <= 0 && $bighospital <= 0) return;
|
||||
|
||||
$share = $bighospital > 0 ? 0.50 : 0.40;
|
||||
$capacity = $bighospital > 0 ? $bighospital * 60 : $hospital * 30;
|
||||
|
||||
$stored = 0;
|
||||
$current = $database->getWounded($vref);
|
||||
if(!empty($current)) {
|
||||
for($i = 1; $i <= 90; $i++) $stored += isset($current['u'.$i]) ? (int)$current['u'.$i] : 0;
|
||||
}
|
||||
$free = $capacity - $stored;
|
||||
if($free <= 0) return;
|
||||
|
||||
$units = []; $amounts = [];
|
||||
foreach($deadByUnit as $i => $deadAmt) {
|
||||
if(empty($deadAmt)) continue;
|
||||
$wounded = (int)floor($deadAmt * $share);
|
||||
if($wounded <= 0) continue;
|
||||
if($wounded > $free) $wounded = $free;
|
||||
$units[] = $i;
|
||||
$amounts[] = $wounded;
|
||||
$free -= $wounded;
|
||||
if($free <= 0) break;
|
||||
}
|
||||
if(!empty($units)) $database->addWounded($vref, $units, $amounts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceseaza coada de vindecare: unitatile vindecate se intorc in sat
|
||||
* incremental (una la fiecare 'eachtime' secunde), ca la antrenare.
|
||||
*/
|
||||
private function healingComplete() {
|
||||
global $database;
|
||||
|
||||
$time = time();
|
||||
$healinglist = $database->getHealingDue($time);
|
||||
foreach($healinglist as $heal) {
|
||||
$healed = 1;
|
||||
if($heal['eachtime'] > 0) {
|
||||
$healed += (int)floor(($time - $heal['timestamp2']) / $heal['eachtime']);
|
||||
}
|
||||
if($healed > $heal['amt']) $healed = (int)$heal['amt'];
|
||||
if($healed <= 0) continue;
|
||||
|
||||
$database->modifyUnit($heal['vref'], [$heal['unit']], [$healed], [1]);
|
||||
|
||||
$remaining = (int)$heal['amt'] - $healed;
|
||||
if($remaining <= 0) {
|
||||
$database->deleteHealing($heal['id']);
|
||||
} else {
|
||||
$database->updateHealing($heal['id'], $remaining, (int)$heal['timestamp2'] + $healed * (int)$heal['eachtime']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function trainingComplete() {
|
||||
global $database, $technology;
|
||||
|
||||
$time = time();
|
||||
$trainlist = $database->getTrainingList();
|
||||
if(count($trainlist) > 0){
|
||||
// preload village data
|
||||
$vilIDs = [];
|
||||
foreach($trainlist as $train){
|
||||
$vilIDs[$train['vref']] = true;
|
||||
}
|
||||
$vilIDs = array_keys($vilIDs);
|
||||
$database->getProfileVillages($vilIDs, 5);
|
||||
$database->cacheResourceLevels($vilIDs);
|
||||
$database->getUnit($vilIDs);
|
||||
$database->getEnforceVillage($vilIDs, 0 );
|
||||
$database->getMovement(3, $vilIDs, 0);
|
||||
$database->getMovement(4, $vilIDs, 1);
|
||||
$database->getMovement(5, $vilIDs, 0);
|
||||
$database->getOasisEnforce($vilIDs, 0);
|
||||
$database->getOasisEnforce($vilIDs, 1);
|
||||
$database->getPrisoners($vilIDs, 1);
|
||||
|
||||
// calculate training updates
|
||||
foreach($trainlist as $train){
|
||||
$timepast = $train['timestamp2'] - $time;
|
||||
$pop = $train['pop'];
|
||||
$valuesUpdated = false;
|
||||
if($timepast <= 0 && $train['amt'] > 0) {
|
||||
$valuesUpdated = true;
|
||||
if($train['eachtime'] > 0){
|
||||
$timepast2 = $time - $train['timestamp2'];
|
||||
$trained = 1;
|
||||
while($timepast2 >= $train['eachtime']){
|
||||
$timepast2 -= $train['eachtime'];
|
||||
$trained += 1;
|
||||
}
|
||||
|
||||
if($trained > $train['amt']) $trained = $train['amt'];
|
||||
}
|
||||
else $trained = $train['amt'];
|
||||
|
||||
if($train['unit'] > 1000 && $train['unit'] != 99){
|
||||
$database->modifyUnit($train['vref'], [$train['unit'] - 1000], [$trained], [1]);
|
||||
}
|
||||
else $database->modifyUnit($train['vref'], [$train['unit']], [$trained], [1]);
|
||||
|
||||
$database->updateTraining($train['id'], $trained, $trained * $train['eachtime']);
|
||||
|
||||
if($train['amt'] - $trained <= 0) $database->trainUnit($train['id'], 0, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
if ($valuesUpdated) call_user_func(get_class($database).'::clearUnitsCache');
|
||||
|
||||
//Update starvation data
|
||||
$database->addStarvationData($train['vref']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function celebrationComplete() {
|
||||
global $database;
|
||||
|
||||
$varray = $database->getCel();
|
||||
foreach($varray as $vil){
|
||||
$id = $vil['wref'];
|
||||
$type = $vil['type'];
|
||||
$user = $vil['owner'];
|
||||
$cp = ($type == 1) ? 500 : 2000;
|
||||
$database->clearCel($id);
|
||||
$database->setCelCp($user, $cp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Expires Mead-Festivals (Brewery, building 35). Unlike celebrationComplete()
|
||||
* this grants no reward — the festival only gated the temporary combat
|
||||
* bonus / chief penalty / catapult randomization while it was active.
|
||||
*/
|
||||
private function festivalComplete() {
|
||||
global $database;
|
||||
|
||||
$varray = $database->getFestivals();
|
||||
foreach($varray as $vil){
|
||||
$database->clearFestival($vil['wref']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationTroopMovements.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Reinforcements, troop returns, settlers ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationTroopMovements {
|
||||
|
||||
|
||||
private function sendreinfunitsComplete() {
|
||||
global $bid23, $database, $technology, $battle;
|
||||
|
||||
$time = time();
|
||||
$q = "
|
||||
SELECT
|
||||
`to`, `from`, moveid,
|
||||
t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11
|
||||
FROM
|
||||
".TB_PREFIX."movement,
|
||||
".TB_PREFIX."attacks
|
||||
WHERE
|
||||
".TB_PREFIX."movement.ref = ".TB_PREFIX."attacks.id
|
||||
AND
|
||||
".TB_PREFIX."movement.proc = 0
|
||||
AND
|
||||
".TB_PREFIX."movement.sort_type = 3
|
||||
AND
|
||||
".TB_PREFIX."attacks.attack_type = 2
|
||||
AND
|
||||
endtime < $time";
|
||||
$dataarray = $database->query_return($q);
|
||||
|
||||
if ($dataarray && count($dataarray)) {
|
||||
// preload village data
|
||||
$vilIDs = [];
|
||||
$tos = [];
|
||||
$froms = [];
|
||||
foreach($dataarray as $data) {
|
||||
$vilIDs[$data['from']] = true;
|
||||
$vilIDs[$data['to']] = true;
|
||||
$tos[$data['to']] = true;
|
||||
$froms[$data['from']] = true;
|
||||
}
|
||||
$vilIDs = array_keys($vilIDs);
|
||||
$database->getProfileVillages($vilIDs, 5);
|
||||
$database->getUnit($vilIDs);
|
||||
$database->getEnforce(array_keys($tos), array_keys($froms));
|
||||
$database->getVillageByWorldID($vilIDs);
|
||||
|
||||
// calculate reinforcements data
|
||||
foreach($dataarray as $data) {
|
||||
if (!$this->claimMovementRecord($data['moveid'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isoasis = $database->isVillageOases($data['to']);
|
||||
if($isoasis == 0){
|
||||
$to = $database->getMInfo($data['to']);
|
||||
$toF = $database->getVillage($data['to']);
|
||||
$DefenderID = $to['owner'];
|
||||
$targettribe = $database->getUserField($DefenderID, "tribe", 0);
|
||||
$conqureby = 0;
|
||||
}else{
|
||||
$to = $database->getOMInfo($data['to']);
|
||||
$toF = $database->getOasisV($data['to']);
|
||||
$DefenderID = $to['owner'];
|
||||
$targettribe = $database->getUserField($DefenderID, "tribe", 0);
|
||||
$conqureby = $toF['conqured'];
|
||||
}
|
||||
|
||||
if($data['from'] == 0){
|
||||
// flow 1: a "village of the elders" reinforcement returning home
|
||||
$this->completeReinforcementFromElders($data, $to);
|
||||
}else{
|
||||
// flow 2: a standard reinforcement delivery (hero transfer + enforce merge + report)
|
||||
$this->completeReinforcementDelivery($data, $to, $isoasis, $DefenderID);
|
||||
}
|
||||
|
||||
//Update starvation data
|
||||
$database->addStarvationData($data['to']);
|
||||
|
||||
//check empty reinforcement in rally point
|
||||
$e_units = '';
|
||||
for ($i = 1; $i <= 90; $i++) $e_units.= 'u'.$i.'= 0 AND ';
|
||||
|
||||
$e_units.= 'hero = 0';
|
||||
$q = "DELETE FROM ".TB_PREFIX."enforcement WHERE ".$e_units." AND (vref=".(int) $data['to']." OR `from`=".(int) $data['to'].")";
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flow 1 of sendreinfunitsComplete(): a "village of the elders" reinforcement
|
||||
// (from = 0) returning home. $targetally / $AttackArrivalTime are intentionally
|
||||
// left undefined here, exactly as in the original inline code.
|
||||
private function completeReinforcementFromElders($data, $to) {
|
||||
global $database;
|
||||
|
||||
$DefenderID = $database->getVillageField($data['to'], "owner");
|
||||
$database->addEnforce(['from' => $data['from'], 'to' => $data['to'], 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0, 't7' => 0, 't8' => 0, 't9' => 0, 't10' => 0, 't11' => 0]);
|
||||
$reinf = $database->getEnforce($data['to'], $data['from']);
|
||||
$database->modifyEnforce($reinf['id'], 31, 1, 1);
|
||||
$data_fail = '0,0,4,1,0,0,0,0,0,0,0,0,0,0';
|
||||
$database->addNotice($to['owner'], $to['wref'], (isset($targetally) ? $targetally : 0), 8, 'village of the elders reinforcement ' . addslashes($to['name']), $data_fail, isset($AttackArrivalTime) ? $AttackArrivalTime : time());
|
||||
}
|
||||
|
||||
// Flow 2 of sendreinfunitsComplete(): a standard reinforcement delivery. Handles
|
||||
// the lone-hero transfer between own villages, the enforcement merge-or-create,
|
||||
// and the reinforcement notices. $ownally / $targetally / $AttackArrivalTime are
|
||||
// intentionally left undefined (guarded by isset()), exactly as in the original.
|
||||
private function completeReinforcementDelivery($data, $to, $isoasis, $DefenderID) {
|
||||
global $database;
|
||||
|
||||
//set base things
|
||||
$from = $database->getMInfo($data['from']);
|
||||
$fromF = $database->getVillage($data['from']);
|
||||
$AttackerID = $from['owner'];
|
||||
$owntribe = $database->getUserField($AttackerID,"tribe",0);
|
||||
|
||||
$HeroTransfer = $troopsPresent = 0;
|
||||
for($i = 1;$i <= 10; $i++) {
|
||||
if($data['t'.$i] > 0) {
|
||||
$troopsPresent = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//check if the hero is present and we're not sending him to an occupied oasis
|
||||
//only add hero if we're sending him alone
|
||||
if($data['t11'] > 0 && !$isoasis && !$troopsPresent) {
|
||||
//check if we're sending a hero between own villages
|
||||
if($AttackerID == $DefenderID) {
|
||||
//check if there's a Mansion at target village
|
||||
if($this->getTypeLevel(37, $data['to']) > 0){
|
||||
//don't reinforce, addunit instead
|
||||
$database->modifyUnit($data['to'], ["hero"], [1], [1]);
|
||||
$heroid = $database->getHeroField($DefenderID, 'heroid');
|
||||
$database->modifyHero("wref", $data['to'], $heroid);
|
||||
$HeroTransfer = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($data['t11'] > 0 || $troopsPresent) {
|
||||
$this->mergeOrCreateEnforcement($data, $owntribe, $HeroTransfer);
|
||||
}
|
||||
|
||||
//send rapport
|
||||
$unitssend_att = ''.$data['t1'].','.$data['t2'].','.$data['t3'].','.$data['t4'].','.$data['t5'].','.$data['t6'].','.$data['t7'].','.$data['t8'].','.$data['t9'].','.$data['t10'].','.$data['t11'].'';
|
||||
$data_fail = ''.$from['wref'].','.$from['owner'].','.$owntribe.','.$unitssend_att.'';
|
||||
|
||||
|
||||
if($isoasis == 0) $to_name = $to['name'];
|
||||
else $to_name = "Oasis ".$database->getVillageField($to['conqured'],"name");
|
||||
|
||||
$database->addNotice($from['owner'],$from['wref'],(isset($ownally) ? $ownally : 0),8,''.addslashes($from['name']).' reinforcement '.addslashes($to_name).'',$data_fail,(isset($AttackArrivalTime) ? $AttackArrivalTime : time()));
|
||||
if($from['owner'] != $to['owner']) {
|
||||
$database->addNotice($to['owner'],$to['wref'],(isset($targetally) ? $targetally : 0),8,''.addslashes($from['name']).' reinforcement '.addslashes($to_name).'',$data_fail,(isset($AttackArrivalTime) ? $AttackArrivalTime : time()));
|
||||
}
|
||||
}
|
||||
|
||||
// Flow 3 of sendreinfunitsComplete(): merge the incoming troops into an existing
|
||||
// enforcement record at the target, or create a new one. When the hero was already
|
||||
// transferred as a unit ($HeroTransfer), his t11 is temporarily zeroed for the
|
||||
// merge and restored afterwards, exactly as in the original.
|
||||
private function mergeOrCreateEnforcement($data, $owntribe, $HeroTransfer) {
|
||||
global $database;
|
||||
|
||||
$temphero = $data['t11'];
|
||||
if ($HeroTransfer) $data['t11'] = 0;
|
||||
//check if there is defence from town in to town
|
||||
$check = $database->getEnforce($data['to'], $data['from']);
|
||||
if (!isset($check['id'])) $database->addEnforce($data);
|
||||
else
|
||||
{
|
||||
//yes
|
||||
$start = ($owntribe - 1) * 10 + 1;
|
||||
$end = ($owntribe * 10);
|
||||
|
||||
//add unit.
|
||||
$t_units = '';
|
||||
for($i = $start, $j = 1; $i <= $end; $i++, $j++)
|
||||
{
|
||||
$t_units .= "u".$i." = u".$i." + ".$data['t'.$j].(($j > 9) ? '' : ', ');
|
||||
}
|
||||
|
||||
$q = "UPDATE ".TB_PREFIX."enforcement set $t_units where id =".(int) $check['id'];
|
||||
$database->query($q);
|
||||
$database->modifyEnforce($check['id'], 'hero', $data['t11'], 1);
|
||||
}
|
||||
$data['t11'] = $temphero;
|
||||
}
|
||||
|
||||
private function returnunitsComplete() {
|
||||
global $database, $technology;
|
||||
|
||||
$time = time();
|
||||
$q = "
|
||||
SELECT
|
||||
`to`, `from`, moveid, starttime, endtime, wood, clay, iron, crop,
|
||||
t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11
|
||||
FROM
|
||||
".TB_PREFIX."movement,
|
||||
".TB_PREFIX."attacks
|
||||
WHERE
|
||||
".TB_PREFIX."movement.ref = ".TB_PREFIX."attacks.id
|
||||
AND
|
||||
".TB_PREFIX."movement.proc = 0
|
||||
AND
|
||||
".TB_PREFIX."movement.sort_type = 4
|
||||
AND
|
||||
endtime < $time";
|
||||
$dataarray = $database->query_return($q);
|
||||
|
||||
if ($dataarray && count($dataarray)) {
|
||||
// preload village data
|
||||
$vilIDs = [];
|
||||
foreach($dataarray as $data) {
|
||||
$vilIDs[$data['from']] = true;
|
||||
$vilIDs[$data['to']] = true;
|
||||
}
|
||||
$database->getProfileVillages(array_keys($vilIDs), 5);
|
||||
$database->getOasisEnforce($vilIDs, 0);
|
||||
$database->getOasisEnforce($vilIDs, 1);
|
||||
|
||||
foreach($dataarray as $data) {
|
||||
if (!$this->claimMovementRecord($data['moveid'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tribe = $database->getUserField($database->getVillageField($data['to'], "owner"), "tribe", 0);
|
||||
$u = $tribe == 1 ? "" : $tribe - 1;
|
||||
$database->modifyUnit(
|
||||
$data['to'],
|
||||
[$u."1", $u."2", $u."3", $u."4", $u."5", $u."6", $u."7", $u."8", $u."9", $tribe."0", "hero"],
|
||||
[$data['t1'], $data['t2'], $data['t3'], $data['t4'], $data['t5'], $data['t6'], $data['t7'], $data['t8'], $data['t9'], $data['t10'], $data['t11']],
|
||||
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||
);
|
||||
|
||||
//If there's at least 1 resource, add it to the village
|
||||
if($data['wood'] + $data['clay'] + $data['iron'] + $data['crop'] > 0){
|
||||
$database->modifyResource($data['to'], $data['wood'], $data['clay'], $data['iron'], $data['crop'], 1);
|
||||
}
|
||||
|
||||
//Update starvation data
|
||||
$database->addStarvationData($data['to']);
|
||||
}
|
||||
|
||||
$this->pruneResource();
|
||||
}
|
||||
|
||||
// Settlers
|
||||
$q = "SELECT `to`, moveid FROM ".TB_PREFIX."movement where ref = 0 and proc = '0' and sort_type = '4' and endtime < $time";
|
||||
$dataarray = $database->query_return($q);
|
||||
if ($dataarray && count($dataarray)) {
|
||||
foreach($dataarray as $data) {
|
||||
if (!$this->claimMovementRecord($data['moveid'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tribe = $database->getUserField($database->getVillageField($data['to'], "owner"), "tribe", 0);
|
||||
$database->modifyUnit($data['to'], [$tribe."0"], [3], [1]);
|
||||
|
||||
//If a settling is canceled, add 750 for each resource type
|
||||
$database->modifyResource($data['to'], 750, 750, 750, 750, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function sendSettlersComplete() {
|
||||
global $database;
|
||||
|
||||
$time = microtime(true);
|
||||
$q = "SELECT `to`, `from`, moveid, starttime, ref FROM ".TB_PREFIX."movement where proc = 0 and sort_type = 5 and endtime < $time";
|
||||
|
||||
$dataarray = $database->query_return($q);
|
||||
$fieldIDs = [];
|
||||
$addUnitsWrefs = [];
|
||||
$addTechWrefs = [];
|
||||
$addABTechWrefs = [];
|
||||
$time = microtime(true);
|
||||
$types = [];
|
||||
$froms = [];
|
||||
$tos = [];
|
||||
$refs = [];
|
||||
$times = [];
|
||||
$endtimes = [];
|
||||
|
||||
// preload village data
|
||||
$vilIDs = [];
|
||||
foreach($dataarray as $data) {
|
||||
$vilIDs[$data['from']] = true;
|
||||
$vilIDs[$data['to']] = true;
|
||||
}
|
||||
$vilIDs = array_keys($vilIDs);
|
||||
$database->getProfileVillages($vilIDs, 5);
|
||||
$database->getVillageByWorldID($vilIDs);
|
||||
|
||||
foreach($dataarray as $data) {
|
||||
if (!$this->claimMovementRecord($data['moveid'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ownerID = $database->getUserField($database->getVillageField($data['from'], "owner"), "id", 0);
|
||||
$to = $database->getMInfo($data['from']);
|
||||
$user = addslashes($database->getUserField($to['owner'], 'username', 0));
|
||||
$taken = $database->getVillageState($data['to']);
|
||||
if($taken != 1){
|
||||
$fieldIDs[] = $data['to'];
|
||||
$database->addVillage($data['to'], $to['owner'], $user, '0');
|
||||
$database->addResourceFields($data['to'], $database->getVillageType($data['to']));
|
||||
$addUnitsWrefs[] = $data['to'];
|
||||
$addTechWrefs[] = $data['to'];
|
||||
$addABTechWrefs[] = $data['to'];
|
||||
|
||||
$exp1 = $database->getVillageField($data['from'], 'exp1');
|
||||
$exp2 = $database->getVillageField($data['from'], 'exp2');
|
||||
$exp3 = $database->getVillageField($data['from'], 'exp3');
|
||||
|
||||
if($exp1 == 0){
|
||||
$exp = 'exp1';
|
||||
$value = $data['to'];
|
||||
}elseif($exp2 == 0){
|
||||
$exp = 'exp2';
|
||||
$value = $data['to'];
|
||||
}else{
|
||||
$exp = 'exp3';
|
||||
$value = $data['to'];
|
||||
}
|
||||
|
||||
$database->setVillageField($data['from'], $exp, $value);
|
||||
|
||||
// Report: new village founded (issue #178)
|
||||
$ncoor = $database->getCoor($data['to']);
|
||||
$database->addNotice($to['owner'], $data['to'], 0, 24, 'New village founded', ($ncoor['x'] ?? 0) . ',' . ($ncoor['y'] ?? 0), time());
|
||||
|
||||
// Milestone: first player ever to settle their 2nd village.
|
||||
// Checked right after the new village row exists, so the
|
||||
// COUNT below already includes it.
|
||||
if (defined('NEW_FUNCTIONS_MILESTONES') && NEW_FUNCTIONS_MILESTONES) {
|
||||
$villageCount = $database->countVillages($to['owner']);
|
||||
if ($villageCount == 2) {
|
||||
$database->recordMilestoneIfFirst('second_village', $to['owner'], $data['to']);
|
||||
}
|
||||
if ($villageCount == 5) {
|
||||
$database->recordMilestoneIfFirst('five_villages', $to['owner'], $data['to']);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// here must come movement from returning settlers
|
||||
$types[] = 4;
|
||||
$froms[] = $data['to'];
|
||||
$tos[] = $data['from'];
|
||||
$refs[] = $data['ref'];
|
||||
$times[] = $time;
|
||||
$endtimes[] = $time + ($time - $data['starttime']);
|
||||
|
||||
// Report: valley already occupied, settlers returning (issue #178)
|
||||
$fcoor = $database->getCoor($data['to']);
|
||||
$database->addNotice($to['owner'], $data['to'], 0, 25, 'Settlers returned - valley occupied', ($fcoor['x'] ?? 0) . ',' . ($fcoor['y'] ?? 0), time());
|
||||
}
|
||||
}
|
||||
|
||||
$database->addMovement($types, $froms, $tos, $refs, $times, $endtimes);
|
||||
$database->setFieldTaken($fieldIDs);
|
||||
$database->addUnits($addUnitsWrefs);
|
||||
$database->addTech($addTechWrefs);
|
||||
$database->addABTech($addABTechWrefs);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Project: TravianZ ##
|
||||
## Filename: AutomationVillageUpkeep.php ##
|
||||
## Split&Refactor Shadow ##
|
||||
## Purpose: Population recalculation, resources, warehouses, loyalty, ##
|
||||
## oases ##
|
||||
## ##
|
||||
## Phase S2: Trait extracted from GameEngine/Automation.php ##
|
||||
## (Automation class). ##
|
||||
## Methods were moved IDENTICALLY, with no logic changes. ##
|
||||
## ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
#################################################################################
|
||||
|
||||
trait AutomationVillageUpkeep {
|
||||
|
||||
|
||||
|
||||
public function procResType($ref, $mode = 0) {
|
||||
//Capital or only 1 village left = cannot be destroyed
|
||||
return addslashes(empty($build = Building::procResType($ref)) && !$mode ? RC_VILLAGE_CANT_BE : $build);
|
||||
}
|
||||
|
||||
function recountPop($vid, $use_cache = true){
|
||||
global $database;
|
||||
|
||||
$vid = (int) $vid;
|
||||
$fdata = $database->getResourceLevel($vid, $use_cache);
|
||||
$popTot = 0;
|
||||
|
||||
for ($i = 1; $i <= 40; $i++) {
|
||||
$lvl = $fdata["f".$i];
|
||||
$building = $fdata["f".$i."t"];
|
||||
if($building) $popTot += $this->buildingPOP($building, $lvl);
|
||||
}
|
||||
|
||||
Building::recountCP($database, $vid);
|
||||
$q = "UPDATE ".TB_PREFIX."vdata set pop = $popTot where wref = $vid";
|
||||
mysqli_query($database->dblink, $q);
|
||||
$owner = $database->getVillageField($vid, "owner");
|
||||
|
||||
// Milestone: first player ever to reach 1000 total population,
|
||||
// summed across all their villages. recountPop() is the single
|
||||
// funnel every population-changing event (building, demolishing,
|
||||
// founding/conquering a village) already passes through, so this
|
||||
// is the one place that's guaranteed to catch the threshold being
|
||||
// crossed regardless of which village/action caused it.
|
||||
// Excludes owner 3 (Natars) — see Artifacts::NATARS_UID — same
|
||||
// convention already used elsewhere in this file (e.g. the
|
||||
// "fix natar report by ronix" check a few hundred lines below).
|
||||
if (defined('NEW_FUNCTIONS_MILESTONES') && NEW_FUNCTIONS_MILESTONES && $owner > 0 && $owner != 3) {
|
||||
$totalPop = (int) $database->getVSumField($owner, 'pop', false);
|
||||
if ($totalPop >= 1000) {
|
||||
$database->recordMilestoneIfFirst('population_1000', $owner, $vid);
|
||||
}
|
||||
}
|
||||
|
||||
$this->procClimbers($owner);
|
||||
|
||||
return $popTot;
|
||||
}
|
||||
|
||||
function buildingPOP($f, $lvl){
|
||||
$name = "bid".$f;
|
||||
global $$name;
|
||||
|
||||
$popT = 0;
|
||||
$dataarray = $$name;
|
||||
|
||||
for ($i = 0; $i <= $lvl; $i++) {
|
||||
$popT += ((isset($dataarray[$i]) && isset($dataarray[$i]['pop'])) ? $dataarray[$i]['pop'] : 0);
|
||||
}
|
||||
return $popT;
|
||||
}
|
||||
|
||||
private function loyaltyRegeneration() {
|
||||
global $database;
|
||||
|
||||
$array = [];
|
||||
$array = $database->getProfileVillages(0, 6);
|
||||
if(!empty($array)) {
|
||||
foreach($array as $loyalty) {
|
||||
if (($t25_level = $this->getTypeLevel(25, $loyalty['wref'])) >= 1) {
|
||||
$value = $t25_level;
|
||||
}elseif(($t26_level = $this->getTypeLevel(26, $loyalty['wref'])) >= 1){
|
||||
$value = $t26_level;
|
||||
}
|
||||
else $value = 0;
|
||||
|
||||
if($value > 0){
|
||||
$newloyalty = min(100, $loyalty['loyalty'] + $value * (time() - $loyalty['lastupdate2']) / 3600);
|
||||
$q = "UPDATE ".TB_PREFIX."vdata SET loyalty = $newloyalty, lastupdate2=".time()." WHERE wref = '".$loyalty['wref']."'";
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$array = [];
|
||||
$q = "SELECT conqured, loyalty, lastupdated, wref FROM ".TB_PREFIX."odata WHERE loyalty < 100";
|
||||
$array = $database->query_return($q);
|
||||
if(!empty($array)) {
|
||||
foreach($array as $loyalty) {
|
||||
$value = $this->getTypeLevel(37, $loyalty['conqured']);
|
||||
|
||||
if($value > 0){
|
||||
$newloyalty = min(100, $loyalty['loyalty'] + $value * (time() - $loyalty['lastupdated']) / 3600);
|
||||
$q = "UPDATE ".TB_PREFIX."odata SET loyalty = $newloyalty, lastupdated=".time()." WHERE wref = '".$loyalty['wref']."'";
|
||||
$database->query($q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTypeLevel($tid, $vid) {
|
||||
global $database;
|
||||
|
||||
$keyholder = [];
|
||||
|
||||
$resourcearray = $database->getResourceLevel($vid);
|
||||
foreach(array_keys($resourcearray, $tid) as $key) {
|
||||
if(strpos($key,'t')) {
|
||||
$key = preg_replace("/[^0-9]/", '', $key);
|
||||
array_push($keyholder, $key);
|
||||
}
|
||||
}
|
||||
|
||||
$element = count($keyholder);
|
||||
if($element >= 2) {
|
||||
if($tid <= 4) {
|
||||
$temparray = [];
|
||||
for($i = 0; $i <= $element - 1; $i++) {
|
||||
array_push($temparray,$resourcearray['f'.$keyholder[$i]]);
|
||||
}
|
||||
foreach ($temparray as $key => $val) {
|
||||
if ($val == max($temparray)) $target = $key;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$target = 0;
|
||||
for($i = 1; $i <= $element - 1; $i++) {
|
||||
if($resourcearray['f'.$keyholder[$i]] > $resourcearray['f'.$keyholder[$target]]) {
|
||||
$target = $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if($element == 1) $target = 0;
|
||||
else return 0;
|
||||
|
||||
if(!empty($keyholder[$target])) return $resourcearray['f'.$keyholder[$target]];
|
||||
else return 0;
|
||||
}
|
||||
|
||||
// Clamp resources/storage up to their minimums for the given table (vdata or
|
||||
// odata): negative resources back to 0 and maxstore/maxcrop back to
|
||||
// STORAGE_BASE. This floor pass is identical for both tables, so both
|
||||
// pruneResource() (vdata) and pruneOResource() (odata) share it. The $table
|
||||
// argument is an internal constant string, never user input.
|
||||
private function pruneResourceMinimums($table) {
|
||||
global $database;
|
||||
|
||||
$database->query("UPDATE
|
||||
".TB_PREFIX.$table."
|
||||
SET
|
||||
wood = IF(wood < 0, 0, wood),
|
||||
clay = IF(clay < 0, 0, clay),
|
||||
iron = IF(iron < 0, 0, iron),
|
||||
crop = IF(crop < 0, 0, crop),
|
||||
maxstore = IF(maxstore < ".STORAGE_BASE.", ".STORAGE_BASE.", maxstore),
|
||||
maxcrop = IF(maxcrop < ".STORAGE_BASE.", ".STORAGE_BASE.", maxcrop)
|
||||
WHERE
|
||||
maxstore < ".STORAGE_BASE." OR
|
||||
maxcrop < ".STORAGE_BASE." OR
|
||||
wood < 0 OR
|
||||
clay < 0 OR
|
||||
iron < 0 OR
|
||||
crop < 0");
|
||||
}
|
||||
|
||||
private function pruneOResource() {
|
||||
if(!ALLOW_BURST) {
|
||||
$this->pruneResourceMinimums('odata');
|
||||
}
|
||||
}
|
||||
private function pruneResource() {
|
||||
global $database;
|
||||
|
||||
if(!ALLOW_BURST) {
|
||||
$this->pruneResourceMinimums('vdata');
|
||||
|
||||
$database->query("UPDATE
|
||||
".TB_PREFIX."vdata
|
||||
SET
|
||||
wood = IF(wood > maxstore, maxstore, wood),
|
||||
clay = IF(clay > maxstore, maxstore, clay),
|
||||
iron = IF(iron > maxstore, maxstore, iron),
|
||||
crop = IF(crop > maxcrop, maxcrop, crop)
|
||||
WHERE
|
||||
wood > maxstore OR
|
||||
clay > maxstore OR
|
||||
iron > maxstore OR
|
||||
crop > maxcrop");
|
||||
}
|
||||
}
|
||||
|
||||
private function culturePoints() {
|
||||
global $database;
|
||||
|
||||
$database->updateVSumField('cp');
|
||||
}
|
||||
|
||||
/**
|
||||
* Recompute a warehouse/granary capacity after a build completion.
|
||||
* Returns [$fieldDbName, $max]: the vdata column to update and its new value.
|
||||
*/
|
||||
private function updateStorageCapacity($type, $level, $villageData) {
|
||||
global $bid10, $bid11, $bid38, $bid39;
|
||||
|
||||
$fieldDbName = (in_array($type, [10, 38]) ? 'maxstore' : 'maxcrop');
|
||||
$max = $villageData[$fieldDbName];
|
||||
|
||||
if($level == 1 && $max == STORAGE_BASE) $max = STORAGE_BASE;
|
||||
|
||||
if ($level != 1) $max -= ${'bid'.$type}[$level - 1]['attri'] * STORAGE_MULTIPLIER;
|
||||
|
||||
$max += ${'bid'.$type}[$level]['attri'] * STORAGE_MULTIPLIER;
|
||||
|
||||
return [$fieldDbName, $max];
|
||||
}
|
||||
|
||||
private function getPop($tid, $level) {
|
||||
$name = "bid".$tid;
|
||||
global $$name;
|
||||
|
||||
$dataarray = $$name;
|
||||
$pop = $dataarray[($level + 1)]['pop'];
|
||||
$cp = $dataarray[($level + 1)]['cp'];
|
||||
return [$pop, $cp];
|
||||
}
|
||||
|
||||
private function updateORes($bountywid) {
|
||||
global $database;
|
||||
|
||||
$oasisInfoArray = $database->getOasisV($bountywid);
|
||||
$timepast = time() - $oasisInfoArray['lastupdated'];
|
||||
$nwood = (OASIS_WOOD_PRODUCTION / 3600) * $timepast;
|
||||
$nclay = (OASIS_CLAY_PRODUCTION / 3600) * $timepast;
|
||||
$niron = (OASIS_IRON_PRODUCTION / 3600) * $timepast;
|
||||
$ncrop = (OASIS_CROP_PRODUCTION / 3600) * $timepast;
|
||||
$database->modifyOasisResource($bountywid, $nwood, $nclay, $niron, $ncrop, 1);
|
||||
$database->updateOasis($bountywid);
|
||||
}
|
||||
|
||||
private function updateRes($bountywid) {
|
||||
global $database, $technology;
|
||||
|
||||
//Get village infos
|
||||
$villageInfoArray = $database->getVillage($bountywid);
|
||||
|
||||
//Get building and resource fields array
|
||||
$resArray = $database->getResourceLevel($bountywid, false);
|
||||
|
||||
//Get oasis array
|
||||
$oasisArray = $database->getOasis($bountywid);
|
||||
|
||||
//Get an array with the numbers of the oasis
|
||||
$numberOfOasis = $this->bountysortOasis($oasisArray);
|
||||
|
||||
//Set the village population (if WW Villages, it's halved)
|
||||
$villagePopulation = !$villageInfoArray['natar'] ? $villageInfoArray['pop'] : round($villageInfoArray['pop'] / 2);
|
||||
|
||||
//Get the upkeep of the village
|
||||
$upkeep = $technology->getUpkeep($this->getAllUnits($bountywid), 0, $bountywid);
|
||||
|
||||
//Calculate the produced resources
|
||||
$timepast = time() - $villageInfoArray['lastupdate'];
|
||||
$nwood = ($this->bountyGetResourceProd($resArray, $numberOfOasis, 1) / 3600) * $timepast;
|
||||
$nclay = ($this->bountyGetResourceProd($resArray, $numberOfOasis, 2) / 3600) * $timepast;
|
||||
$niron = ($this->bountyGetResourceProd($resArray, $numberOfOasis, 3) / 3600) * $timepast;
|
||||
$ncrop = (($this->bountyGetResourceProd($resArray, $numberOfOasis, 4) - $villagePopulation - $upkeep) / 3600) * $timepast;
|
||||
$database->modifyResource($bountywid, $nwood, $nclay, $niron, $ncrop, 1);
|
||||
$database->updateVillage($bountywid);
|
||||
}
|
||||
|
||||
private function getsort_typeLevel($tid, $resarray) {
|
||||
$keyholder = [];
|
||||
|
||||
foreach(array_keys($resarray, $tid) as $key) {
|
||||
if(strpos($key, 't')) {
|
||||
$key = preg_replace("/[^0-9]/", '', $key);
|
||||
array_push($keyholder, $key);
|
||||
}
|
||||
}
|
||||
|
||||
$element = count($keyholder);
|
||||
if($element >= 2) {
|
||||
if($tid <= 4) {
|
||||
$temparray = [];
|
||||
|
||||
for($i = 0; $i <= $element - 1; $i++) {
|
||||
array_push($temparray, $resarray['f'.$keyholder[$i]]);
|
||||
}
|
||||
|
||||
foreach ($temparray as $key => $val) {
|
||||
if ($val == max($temparray)) $target = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if($element == 1) $target = 0;
|
||||
else return 0;
|
||||
|
||||
if(!empty($keyholder[$target])) return $resarray['f'.$keyholder[$target]];
|
||||
else return 0;
|
||||
}
|
||||
|
||||
private function updateStore() {
|
||||
global $database, $bid10, $bid38, $bid11, $bid39;
|
||||
|
||||
$result = mysqli_query($database->dblink, 'SELECT * FROM `' . TB_PREFIX . 'fdata`');
|
||||
|
||||
mysqli_begin_transaction($database->dblink);
|
||||
while ($row = mysqli_fetch_assoc($result))
|
||||
{
|
||||
$ress = $crop = 0;
|
||||
for ($i = 19; $i < 40; ++$i)
|
||||
{
|
||||
//Warehouse
|
||||
if ($row['f' . $i . 't'] == 10)
|
||||
{
|
||||
$ress += ((isset($bid10[$row['f' . $i]]) && isset($bid10[$row['f' . $i]]['attri'])) ? $bid10[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
|
||||
//Great warehouse
|
||||
if ($row['f' . $i . 't'] == 38)
|
||||
{
|
||||
$ress += ((isset($bid38[$row['f' . $i]]) && isset($bid38[$row['f' . $i]]['attri'])) ? $bid38[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
|
||||
//Granary
|
||||
if ($row['f' . $i . 't'] == 11)
|
||||
{
|
||||
$crop += ((isset($bid11[$row['f' . $i]]) && isset($bid11[$row['f' . $i]]['attri'])) ? $bid11[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
|
||||
//Great granary
|
||||
if ($row['f' . $i . 't'] == 39)
|
||||
{
|
||||
$crop += ((isset($bid39[$row['f' . $i]]) && isset($bid39[$row['f' . $i]]['attri'])) ? $bid39[$row['f' . $i]]['attri'] * STORAGE_MULTIPLIER : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// no need for update, since we didn't find any warehouses or granaries
|
||||
// and maximums would have been set to correct values inside prune* functions already
|
||||
if ($ress == 0 && $crop == 0) continue;
|
||||
|
||||
// maxstore nor maxcrop can go below the minimum threshold
|
||||
if ($ress < STORAGE_BASE) $ress = STORAGE_BASE;
|
||||
if ($crop < STORAGE_BASE) $crop = STORAGE_BASE;
|
||||
|
||||
mysqli_query($database->dblink,'UPDATE `' . TB_PREFIX . 'vdata` SET `maxstore` = ' . (int) $ress . ', `maxcrop` = ' . (int) $crop . ' WHERE `wref` = ' . (int) $row['vref']);
|
||||
}
|
||||
mysqli_commit($database->dblink);
|
||||
}
|
||||
|
||||
private function regenerateOasisTroops() {
|
||||
global $database;
|
||||
|
||||
$timeFinal = time() - NATURE_REGTIME;
|
||||
$q = "SELECT wref FROM " . TB_PREFIX . "odata where conqured = 0 and lastupdated2 < $timeFinal";
|
||||
$array = $database->query_return($q);
|
||||
if (count($array)) {
|
||||
$ids = [];
|
||||
foreach($array as $oasis) $ids[] = $oasis['wref'];
|
||||
$database->regenerateOasisUnits($ids, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
#################################################################################
|
||||
## -= YOU MAY NOT REMOVE OR CHANGE THIS NOTICE =- ##
|
||||
## --------------------------------------------------------------------------- ##
|
||||
## Filename index.php ##
|
||||
## Developed by: aggenkeech ##
|
||||
## License: TravianZ Project ##
|
||||
## Copyright: TravianZ (c) 2010-2026. All rights reserved. ##
|
||||
## URLs: https://travianz.org ##
|
||||
## https://github.com/Shadowss/TravianZ ##
|
||||
## ##
|
||||
#################################################################################
|
||||
|
||||
// prevent direct misuse in weird contexts (optional but safe)
|
||||
if (!defined('IN_GAME')) {
|
||||
// keep it harmless, just allow display
|
||||
}
|
||||
|
||||
$basePath = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
|
||||
?>
|
||||
|
||||
<div style="margin-top: 50px;">
|
||||
<div style="text-align: center">
|
||||
|
||||
<h1>404 - File not found</h1>
|
||||
|
||||
<img
|
||||
src="<?php echo $basePath; ?>/../../gpack/travian_default/img/misc/404.gif"
|
||||
title="Not Found"
|
||||
alt="Not Found"
|
||||
><br />
|
||||
|
||||
<p>We looked 404 times already but can't find anything, Not even an X marking the spot.</p>
|
||||
|
||||
<p>This system is not complete yet. So the page probably does not exist.</p>
|
||||
|
||||
<br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user