feature(rally-point): mark incoming attacks + show per-troop travel time [#245] (#248)

This commit is contained in:
Ferywir
2026-06-22 05:54:41 +02:00
committed by GitHub
parent afbba3f841
commit f581add125
7 changed files with 86 additions and 4 deletions
+19 -2
View File
@@ -5895,7 +5895,7 @@ $q = "INSERT INTO ".TB_PREFIX."demolition VALUES (
$pairs[] = '(0, '.(int) $typeValue.', '.(int) $from[$index].', '.(int) $to[$index].', '.(int) $ref[$index].', '.(int) $ref2[$index].', '.(int) $time[$index].', '.(int) $endtime[$index].', 0, '.(int) $send[$index].', '.(int) $wood[$index].', '.(int) $clay[$index].', '.(int) $iron[$index].', '.(int) $crop[$index].')';
if ($counter++ > 25) {
$q = "INSERT INTO " . TB_PREFIX . "movement VALUES ".implode(', ', $pairs);
$q = "INSERT INTO " . TB_PREFIX . "movement (moveid, sort_type, `from`, `to`, ref, ref2, starttime, endtime, proc, send, wood, clay, iron, crop) VALUES ".implode(', ', $pairs);
mysqli_query($this->dblink,$q);
$pairs = [];
@@ -5904,7 +5904,7 @@ $q = "INSERT INTO ".TB_PREFIX."demolition VALUES (
}
if ($counter > 0) {
$q = "INSERT INTO " . TB_PREFIX . "movement VALUES " . implode( ', ', $pairs );
$q = "INSERT INTO " . TB_PREFIX . "movement (moveid, sort_type, `from`, `to`, ref, ref2, starttime, endtime, proc, send, wood, clay, iron, crop) VALUES " . implode( ', ', $pairs );
return mysqli_query( $this->dblink, $q );
} else {
return true;
@@ -8039,6 +8039,23 @@ $q = "INSERT INTO ".TB_PREFIX."demolition VALUES (
return $array;
}
// Rally-point attack marker (issue #245): a defender can tag an incoming
// attack green/yellow/red. The WHERE clause restricts the update to a
// movement whose target village (`to`) belongs to $uid, so a player can
// only mark attacks incoming on their own villages.
function setMovementMarker($moveid, $marker, $uid) {
$moveid = (int) $moveid;
$marker = (int) $marker;
$uid = (int) $uid;
if ($marker < 0 || $marker > 3 || $moveid <= 0 || $uid <= 0) {
return false;
}
$q = "UPDATE ".TB_PREFIX."movement SET marker = ".$marker.
" WHERE moveid = ".$moveid.
" AND `to` IN (SELECT wref FROM ".TB_PREFIX."vdata WHERE owner = ".$uid.")";
return mysqli_query($this->dblink, $q) && mysqli_affected_rows($this->dblink) > 0;
}
// no need to cache this method
function getLinks($id) {
list($id) = $this->escape_input((int) $id);
+1
View File
@@ -805,6 +805,7 @@ tz_def('RETURNFROM', 'Return from');
tz_def('REINFORCEMENTFOR', 'Reinforcement to');
tz_def('ATTACK_ON', 'Attack to');
tz_def('RAID_ON', 'Raid to');
tz_def('MARK_ATTACK', 'Mark this attack (severity)');
tz_def('SCOUTING', 'Scouting');
tz_def('PRISONERS', 'Prisoners');
tz_def('PRISONERSIN', 'Prisoners in');
+1
View File
@@ -801,6 +801,7 @@ define('RETURNFROM', 'Retour de');
define('REINFORCEMENTFOR', 'Renfort vers');
define('ATTACK_ON', 'Attaque sur');
define('RAID_ON', 'Pillage sur');
define('MARK_ATTACK', 'Marquer cette attaque (gravité)');
define('SCOUTING', 'Espionnage');
define('PRISONERS', 'Prisonniers');
define('PRISONERSIN', 'Prisonniers à');
+1
View File
@@ -801,6 +801,7 @@ define('RETURNFROM', 'Întoarcere din');
define('REINFORCEMENTFOR', 'Întărire către');
define('ATTACK_ON', 'Atac către');
define('RAID_ON', 'Raid către');
define('MARK_ATTACK', 'Marchează acest atac (gravitate)');
define('SCOUTING', 'Explorare');
define('PRISONERS', 'Prizonieri');
define('PRISONERSIN', 'Prizonieri în');
+44 -1
View File
@@ -8,6 +8,33 @@ $units = $database->getMovement(34, $village->wid, 1);
$artifactsSum = $database->getArtifactsSumByKind($session->uid, $village->wid, 3);
?>
<style>
.atk_marker{position:relative;float:right;width:14px;height:14px;border-radius:50%;border:1px solid #666;margin:0 0 0 6px;cursor:pointer;box-shadow:inset 0 0 0 2px rgba(255,255,255,.55)}
.atk_marker.marker0{background:#dddddd}
.atk_marker.marker1{background:#3cb043}
.atk_marker.marker2{background:#f2c200}
.atk_marker.marker3{background:#e23b3b}
.atk_marker:hover{box-shadow:inset 0 0 0 2px rgba(255,255,255,.55),0 0 0 1px #333}
</style>
<script type="text/javascript">
function cycleMarker(moveid, el){
var cur = parseInt(el.getAttribute('data-marker') || '0', 10);
var next = (cur + 1) % 4;
var body = 'moveid=' + encodeURIComponent(moveid) + '&marker=' + encodeURIComponent(next);
fetch('ajax.php?f=marker', {
method: 'POST',
credentials: 'same-origin',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: body
}).then(function(r){ return r.json(); }).then(function(d){
if (d && d.ok) {
el.setAttribute('data-marker', next);
el.className = 'atk_marker marker' + next;
}
});
}
</script>
<?php foreach ($units as $u):
$session->timer++;
$sort = (int)$u['sort_type'];
@@ -24,6 +51,19 @@ $artifactsSum = $database->getArtifactsSumByKind($session->uid, $village->wid, 3
$start = ($tribe - 1) * 10 + 1;
$end = $tribe * 10;
$dt = $generator->procMtime($u['endtime']);
// Base travel time per troop type (issue #245): distance / unit speed,
// WITHOUT tournament square or artefact effects. INCREASE_SPEED is the
// server speed multiplier, matching MyGenerator::procDistanceTime().
$mtimes = [];
if (!$isElders) {
$fromInfo = $database->getMInfo($from);
$toInfo = $database->getMInfo($u['to']);
$dist = $database->getDistance($fromInfo['x'], $fromInfo['y'], $toInfo['x'], $toInfo['y']);
for ($i = $start; $i <= $end; $i++) {
$spd = isset($GLOBALS['u'.$i]['speed']) ? $GLOBALS['u'.$i]['speed'] : 0;
$mtimes[$i] = $spd > 0 ? $generator->getTimeFormat((int) round(($dist / $spd) * 3600 / INCREASE_SPEED)) : '-';
}
}
?>
<table class="troop_details" cellpadding="1" cellspacing="1">
<thead><tr>
@@ -33,6 +73,9 @@ $artifactsSum = $database->getArtifactsSumByKind($session->uid, $village->wid, 3
<?php else:?><a><?php echo VILLAGE_OF_THE_ELDERS; ?></a><?php endif;?>
</td>
<td colspan="<?= $colspan?>">
<?php if (($atk == 3 || $atk == 4) && !$isElders): $marker = (int)($u['marker'] ?? 0); $mid = (int)$u['moveid'];?>
<span class="atk_marker marker<?= $marker?>" data-marker="<?= $marker?>" title="<?= MARK_ATTACK?>" onclick="cycleMarker(<?= $mid?>,this)"></span>
<?php endif;?>
<?php if (!$isElders):?>
<a href="karte.php?d=<?= $u['to']?>&c=<?= $generator->getMapCheck($u['to'])?>"><?= $action?> <?= $database->getVillageField($u['to'],'name')?></a>
<?php else:?><a><?= VILLAGE_OF_THE_ELDERS_TROOPS?></a><?php endif;?>
@@ -40,7 +83,7 @@ $artifactsSum = $database->getArtifactsSumByKind($session->uid, $village->wid, 3
</tr></thead>
<tbody class="units">
<tr><th>&nbsp;</th>
<?php for ($i=$start;$i<=$end;$i++):?><td><img src="img/x.gif" class="unit u<?= $i?>" title="<?= $technology->getUnitName($i)?>"></td><?php endfor;?>
<?php for ($i=$start;$i<=$end;$i++):?><td><img src="img/x.gif" class="unit u<?= $i?>" title="<?= $technology->getUnitName($i)?><?= isset($mtimes[$i])? ': '.$mtimes[$i] : ''?>"></td><?php endfor;?>
<?php if ($u['t11'] && $isMine):?><td><img src="img/x.gif" class="unit uhero" title="<?php echo U0; ?>"></td><?php endif;?>
</tr>
<tr><th><?= TROOPS?></th>
+19 -1
View File
@@ -73,7 +73,25 @@ switch($_GET['f']) {
include("Templates/Ajax/quest_core.tpl");
}else{
include("Templates/Ajax/quest_core25.tpl");
}
}
break;
// Rally-point attack marker (issue #245): persist the green/yellow/red tag
// a defender sets on an incoming attack. setMovementMarker() enforces that
// the targeted village belongs to the logged-in user.
case 'marker':
header('Content-Type: application/json');
if (!isset($_SESSION)) {
session_start();
}
include_once($autoprefix.'GameEngine/Database.php');
$uid = (int) ($_SESSION['id_user'] ?? 0);
if (!$uid) {
http_response_code(403);
echo json_encode(['ok' => 0]);
break;
}
$ok = $database->setMovementMarker($_POST['moveid'] ?? 0, $_POST['marker'] ?? 0, $uid);
echo json_encode(['ok' => $ok ? 1 : 0]);
break;
}
?>
+1
View File
@@ -1137,6 +1137,7 @@ CREATE TABLE IF NOT EXISTS `%PREFIX%movement` (
`clay` int(11) DEFAULT NULL,
`iron` int(11) DEFAULT NULL,
`crop` int(11) DEFAULT NULL,
`marker` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`moveid`),
KEY `ref` (`ref`),
KEY `from-proc-sort_type` (`from`,`proc`,`sort_type`),