]> ruin.nu Git - ndwebbie.git/commitdiff
Converted raids page
authorMichael Andreen <harv@ruin.nu>
Fri, 11 Jul 2008 21:46:37 +0000 (23:46 +0200)
committerMichael Andreen <harv@ruin.nu>
Fri, 11 Jul 2008 21:46:37 +0000 (23:46 +0200)
18 files changed:
NDWeb/Pages/Raids.pm [deleted file]
database/group_roles.sql
database/raids.sql [new file with mode: 0644]
lib/NDWeb/Controller/JSRPC.pm [new file with mode: 0644]
lib/NDWeb/Controller/Raids.pm [new file with mode: 0644]
root/lib/inc/targetlist.tt2
root/lib/site/leftbar.tt2
root/lib/site/wrapper.tt2
root/lib/site/xml.tt2 [new file with mode: 0644]
root/src/jsrpc/update.tt2 [new file with mode: 0644]
root/src/raids/index.tt2 [new file with mode: 0644]
root/src/raids/view.tt2 [new file with mode: 0644]
root/static/default.css
root/static/js/raid.js
t/controller_JSRPC.t [new file with mode: 0644]
t/controller_Raids.t [new file with mode: 0644]
templates/raids.tmpl [deleted file]
templates/raids.xml.tmpl [deleted file]

diff --git a/NDWeb/Pages/Raids.pm b/NDWeb/Pages/Raids.pm
deleted file mode 100644 (file)
index 31be782..0000000
+++ /dev/null
@@ -1,377 +0,0 @@
-#**************************************************************************
-#   Copyright (C) 2006 by Michael Andreen <harvATruinDOTnu>               *
-#                                                                         *
-#   This program is free software; you can redistribute it and/or modify  *
-#   it under the terms of the GNU General Public License as published by  *
-#   the Free Software Foundation; either version 2 of the License, or     *
-#   (at your option) any later version.                                   *
-#                                                                         *
-#   This program is distributed in the hope that it will be useful,       *
-#   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
-#   GNU General Public License for more details.                          *
-#                                                                         *
-#   You should have received a copy of the GNU General Public License     *
-#   along with this program; if not, write to the                         *
-#   Free Software Foundation, Inc.,                                       *
-#   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
-#**************************************************************************/
-
-package NDWeb::Pages::Raids;
-use strict;
-use warnings;
-use ND::Include;
-use POSIX;
-use CGI qw/:standard/;
-use NDWeb::Include;
-
-use base qw/NDWeb::XMLPage/;
-
-$NDWeb::Page::PAGES{raids} = __PACKAGE__;
-
-sub process {
-       my $self = shift;
-       $self->{XML} = 1 if param('xml');
-}
-
-
-sub generateClaimXml : method {
-       my $self = shift;
-       my ($BODY,$raid, $from, $target) = @_;
-       my $DBH = $self->{DBH};
-
-       my ($timestamp) = $DBH->selectrow_array("SELECT MAX(modified)::timestamp AS modified FROM raid_targets");
-       $BODY->param(Timestamp => $timestamp);
-       if ($target){
-               $target = "r.id = $target";
-               $_ = $self->listTargets;
-               $BODY->param(TargetList => $_);
-       }else{
-               $target = "r.raid = $raid->{id}";
-       }
-
-       if ($from){
-               $from = "AND modified > '$from'";
-       }else{
-               $from = '';
-       }
-       my $targets = $DBH->prepare(qq{SELECT r.id,r.planet FROM raid_targets r WHERE $target $from});
-       $targets->execute or print p($DBH->errstr);
-       my $claims =  $DBH->prepare(qq{ SELECT username,joinable,launched FROM raid_claims
-               NATURAL JOIN users WHERE target = ? AND wave = ?});
-       my @targets;
-       while (my $target = $targets->fetchrow_hashref){
-               my %target;
-               $target{Id} = $target->{id};
-               my @waves;
-               for (my $i = 1; $i <= $raid->{waves}; $i++){
-                       my %wave;
-                       $wave{Id} = $i;
-                       $claims->execute($target->{id},$i);
-                       my $joinable = 0;
-                       my $claimers;
-                       if ($claims->rows != 0){
-                               my $owner = 0;
-                               my @claimers;
-                               while (my $claim = $claims->fetchrow_hashref){
-                                       $owner = 1 if ($self->{USER} eq $claim->{username});
-                                       $joinable = 1 if ($claim->{joinable});
-                                       $claim->{username} .= '*' if ($claim->{launched});
-                                       push @claimers,$claim->{username};
-                               }
-                               $claimers = join '/', @claimers;
-                               if ($owner){
-                                       $wave{Command} = 'Unclaim';
-                               }elsif ($joinable){
-                                       $wave{Command} = 'Join';
-                               }else{
-                                       $wave{Command} = 'none';
-                               }
-                       }else{
-                               #if (!isset($planet) || ($target->value/$planet->value > 0.4 || $target->score/$planet->score > 0.4))
-                               $wave{Command} = 'Claim';
-                       }
-                       $wave{Claimers} = $claimers;
-                       $wave{Joinable} = $joinable;
-                       push @waves,\%wave;
-               }
-               $target{Waves} = \@waves;
-               push @targets,\%target;
-       }
-       $BODY->param(Targets => \@targets);
-       return $BODY;
-}
-
-sub render_body {
-       my $self = shift;
-       my ($BODY) = @_;
-       $self->{TITLE} = 'Raids';
-       my $DBH = $self->{DBH};
-
-
-       my $raid;
-       if (defined param('raid')){
-               my $query = $DBH->prepare(q{SELECT id,tick,waves,message,released_coords FROM raids WHERE id = ? AND open AND not removed AND id IN (SELECT raid FROM raid_access NATURAL JOIN groupmembers WHERE uid = ?)});
-               $raid = $DBH->selectrow_hashref($query,undef,param('raid'),$ND::UID);
-       }
-
-       if (defined param('cmd') && defined param('target') && defined param('wave') && param('target') =~ /^(\d+)$/ && param('wave') =~ /^(\d+)$/){
-               my $target = param('target');
-               my $wave = param('wave');
-
-               $DBH->begin_work;
-               my $findtarget = $DBH->prepare(q{SELECT rt.id FROM raid_targets rt 
-                       NATURAL JOIN raid_access ra NATURAL JOIN groupmembers 
-                       WHERE uid = ? AND id = ?
-                       FOR UPDATE
-               });
-               my $result = $DBH->selectrow_array($findtarget,undef,$ND::UID,$target);
-               if ($result != $target){
-                       $DBH->rollback;
-                       return $self->noAccess; 
-               }
-
-               if (param('cmd') eq 'Claim'){
-                       my $claims = $DBH->prepare(qq{SELECT username FROM raid_claims NATURAL JOIN users WHERE target = ? AND wave = ?});
-                       $claims->execute($target,$wave);
-                       if ($claims->rows == 0){
-                               my $query = $DBH->prepare(q{INSERT INTO raid_claims (target,uid,wave) VALUES(?,?,?)});
-                               if($query->execute($target,$ND::UID,$wave)){
-                                       log_message $ND::UID,"Claimed target $target wave $wave.";
-                               }
-                       }
-               }
-               if (param('cmd') eq 'Join'){
-                       my $claims = $DBH->prepare(qq{SELECT username FROM raid_claims
-                               NATURAL JOIN users WHERE target = ? AND wave = ? AND
-                               joinable = TRUE});
-                       $claims->execute($target,$wave);
-                       if ($claims->rows != 0){
-                               my $query = $DBH->prepare(q{INSERT INTO raid_claims (target,uid,wave,joinable) VALUES(?,?,?,TRUE)});
-                               if($query->execute($target,$ND::UID,$wave)){
-                                       log_message $ND::UID,"Joined target $target wave $wave.";
-                               }
-                       }
-               }
-               if (param('cmd') eq 'set' && defined param('joinable') && param('joinable') =~ /(TRUE|FALSE)/){
-                       my $claims = $DBH->prepare(qq{SELECT username FROM raid_claims NATURAL JOIN users WHERE target = ? AND wave = ? AND uid = ?});
-                       $claims->execute($target,$wave,$ND::UID);
-                       if ($claims->rows != 0){
-                               $DBH->do(q{UPDATE raid_claims SET joinable = ? WHERE target = ? AND wave = ?},undef,$1,$target,$wave)
-                       }
-               }
-               if (param('cmd') eq 'Unclaim'){
-                       my $query = $DBH->prepare(qq{DELETE FROM raid_claims WHERE target = ? AND uid = ? AND wave = ?});
-                       if ($query->execute($target,$ND::UID,$wave)){
-                               log_message $ND::UID,"Unclaimed target $target wave $wave.";
-                       }
-               }
-               $DBH->commit;
-               if ($self->{XML} && $raid){
-                       return $self->generateClaimXml($BODY,$raid,undef,$target);
-               }
-       }
-       if ($self->{XML} && $raid && param('cmd') eq 'update' ){
-               my $from;
-               if (param('from') =~ /^[-\d\ \:\.]+$/){
-                       $from = param('from');
-               }
-               return $self->generateClaimXml($BODY,$raid,$from);
-       }
-       if ($self->{XML} && param('cmd') eq 'gettargets' ){
-               $_ = $self->listTargets();
-               $BODY->param(TargetList => $_);
-       }
-
-       return $BODY if $self->{XML};
-
-       if ($raid){#We have a raid, so list all targets
-               $BODY->param(Raid => $raid->{id});
-               $BODY->param(Ajax => $self->{AJAX});
-               my $noingal = '';
-               my $planet;
-               if ($self->{PLANET}){
-                       my $query = $DBH->prepare("SELECT value, score,x,y FROM current_planet_stats WHERE id = ?");
-                       $planet = $DBH->selectrow_hashref($query,undef,$self->{PLANET});
-                       $noingal = "AND NOT (x = $planet->{x} AND y = $planet->{y})";
-               }
-               $BODY->param(Message => parseMarkup($raid->{message}));
-               $BODY->param(LandingTick => $raid->{tick});
-               my $targetquery = $DBH->prepare(qq{SELECT r.id, r.planet, size, score, value
-                       , p.x,p.y,p.z, race
-                       , p.value - p.size*200 - 
-                               COALESCE(ps.metal+ps.crystal+ps.eonium,0)/150 - 
-                               COALESCE(ss.total ,(SELECT
-                                       COALESCE(avg(total),0) FROM
-                                       structure_scans)::int)*1500 AS fleetvalue
-                       ,(metal+crystal+eonium)/100 AS resvalue, comment
-                       , hidden, light, medium, heavy
-                       FROM current_planet_stats p 
-                       JOIN raid_targets r ON p.id = r.planet 
-                       LEFT OUTER JOIN planet_scans ps ON p.id = ps.planet
-                       LEFT OUTER JOIN structure_scans ss ON p.id = ss.planet
-                       WHERE r.raid = ?
-                       $noingal
-                       ORDER BY size});
-               $targetquery->execute($raid->{id});
-               my @targets;
-               my %production = (0 => 'None', 35 => 'Light', 65 => 'Medium', 100 => 'High');
-               while (my $target = $targetquery->fetchrow_hashref){
-                       my %target;
-                       if ($planet){
-                               if ($planet->{x} == $target->{x}){
-                                       $target{style} = 'incluster';
-                               }
-                               $target{ScoreBash} = 'bash' if ($target->{score}/$planet->{score} < 0.4);
-                               $target{ValueBash} = 'bash' if ($target->{value}/$planet->{value} < 0.4);
-                               #next if ($target->{score}/$planet->{score} < 0.4) && ($target->{value}/$planet->{value} < 0.4);
-                       }
-                       $target{Id} = $target->{id};
-                       $target{Race} = $target->{race};
-                       my $num = pow(10,length($target->{score})-2);
-                       $target{Score} = "Hidden"; #ceil($target->{score}/$num)*$num;
-                       $num = pow(10,length($target->{value})-2);
-                       $target{Value} = "Hidden"; #ceil($target->{value}/$num)*$num;
-                       $num = pow(10,length($target->{size})-2);
-                       $target{Size} = floor($target->{size}/$num)*$num;
-                       $num = pow(10,length($target->{fleetvalue})-2);
-                       $target{FleetValue} = floor($target->{fleetvalue}/$num)*$num;
-                       if (defined $target->{resvalue}){
-                               $num = pow(10,length($target->{resvalue})-2);
-                               $target{ResValue} = floor($target->{resvalue}/$num)*$num;
-                       }
-                       $target{comment} = parseMarkup($target->{comment}) if ($target->{comment});
-                       
-                       $target{Hidden} = int($target->{hidden} / 100);
-                       $target{Light} = $production{$target->{light}};
-                       $target{Medium} = $production{$target->{medium}};
-                       $target{Heavy} = $production{$target->{heavy}};
-
-                       my $unitscans = $DBH->prepare(q{ 
-                               SELECT DISTINCT ON (name) i.id,i.name, i.tick, i.amount 
-                               FROM fleets i
-                               WHERE  i.uid = -1
-                                       AND i.sender = ?
-                                       AND i.mission = 'Full fleet'
-                               GROUP BY i.id,i.tick,i.name,i.amount
-                               ORDER BY name,i.tick DESC
-                       });
-                       $unitscans->execute($target->{planet}) or warn $DBH->errstr;
-                       my $ships = $DBH->prepare(q{SELECT ship,amount FROM fleet_ships
-                               WHERE id = ? ORDER BY num
-                       });
-                       my @missions;
-                       while (my $mission = $unitscans->fetchrow_hashref){
-                               my @ships;
-                               $ships->execute($mission->{id});
-                               while (my $ship = $ships->fetchrow_hashref){
-                                       push @ships,$ship;
-                               }
-                               push @ships, {ship => 'No', amount => 'ships'} if @ships == 0;
-                               $mission->{ships} = \@ships;
-                               $mission->{amount} =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; #Add comma for ever 3 digits, i.e. 1000 => 1,000
-                               delete $mission->{id};
-                               push @missions,$mission;
-                       }
-                       $target{missions} = \@missions;
-
-                       my $query = $DBH->prepare(q{SELECT DISTINCT ON(rid) tick,category,name,amount
-                               FROM planet_data pd JOIN planet_data_types pdt ON pd.rid = pdt.id
-                               WHERE pd.id = $1 AND rid in (1,2,3,4,5,6,9,10,14,15,16,17,18)
-                               ORDER BY rid,tick DESC
-                       });
-                       $query->execute($target->{planet});
-                       while (my $data = $query->fetchrow_hashref){
-                               $data->{amount} =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; #Add comma for ever 3 digits, i.e. 1000 => 1,000
-                               $target{$data->{category}.$data->{name}} = $data->{amount};
-                       }
-
-                       my @roids;
-                       my @claims;
-                       my $size = $target{Size};
-                       for (my $i = 1; $i <= $raid->{waves}; $i++){
-                               my $roids = floor(0.25*$size);
-                               $size -= $roids;
-                               my $xp = 0;
-                               if ($planet){
-                                       $xp = pa_xp($roids,$planet->{score},$planet->{value},$target->{score},$target->{value});
-                               }
-                               push @roids,{Wave => $i, Roids => $roids, XP => $xp};
-                               if ($self->{AJAX}){
-                                       push @claims,{Wave => $i, Target => $target{Id}}
-                               }else{
-                                       push @claims,{Wave => $i, Target => $target{Id}, Command => 'Claim'
-                                               , Owner => 1, Raid => $raid->{id}, Joinable => 0};
-                               }
-                       }
-                       $target{Roids} = \@roids;
-                       $target{Claims} = \@claims;
-
-                       push @targets,\%target;
-               }
-               @targets = sort {$b->{Roids}[0]{XP} <=> $a->{Roids}[0]{XP} or $b->{Size} <=> $a->{Size}} @targets;
-
-               $BODY->param(Targets => \@targets);
-       }else{#list raids if we haven't chosen one yet
-               my $launched = 0;
-               my $query = $DBH->prepare(q{SELECT r.id AS raid,released_coords AS releasedcoords,tick,waves*COUNT(DISTINCT rt.id) AS waves,
-                               COUNT(rc.uid) AS claims, COUNT(nullif(rc.launched,false)) AS launched,COUNT(NULLIF(rc.uid > 0,true)) AS blocked
-                       FROM raids r JOIN raid_targets rt ON r.id = rt.raid
-                               LEFT OUTER JOIN raid_claims rc ON rt.id = rc.target
-                       WHERE open AND not removed AND r.id 
-                               IN (SELECT raid FROM raid_access NATURAL JOIN groupmembers WHERE uid = ?)
-                       GROUP BY r.id,released_coords,tick,waves});
-               $query->execute($ND::UID);
-               my @raids;
-               while (my $raid = $query->fetchrow_hashref){
-                       $raid->{waves} -= $raid->{blocked};
-                       $raid->{claims} -= $raid->{blocked};
-                       delete $raid->{blocked};
-                       $launched += $raid->{launched};
-                       push @raids,$raid;
-               }
-               $BODY->param(Raids => \@raids);
-
-               if ($self->isBC){
-                       $BODY->param(isBC => 1);
-                       my $query = $DBH->prepare(q{SELECT r.id AS raid,open ,tick,waves*COUNT(DISTINCT rt.id) AS waves,
-                               COUNT(rc.uid) AS claims, COUNT(nullif(rc.launched,false)) AS launched ,COUNT(NULLIF(uid > 0,true)) AS blocked
-                       FROM raids r JOIN raid_targets rt ON r.id = rt.raid
-                               LEFT OUTER JOIN raid_claims rc ON rt.id = rc.target
-                       WHERE not removed AND (not open 
-                               OR r.id NOT IN (SELECT raid FROM raid_access NATURAL JOIN groupmembers WHERE uid = ?))
-                       GROUP BY r.id,open,tick,waves});
-                       $query->execute($ND::UID);
-                       my @raids;
-                       while (my $raid = $query->fetchrow_hashref){
-                               $raid->{waves} -= $raid->{blocked};
-                               $raid->{claims} -= $raid->{blocked};
-                               delete $raid->{blocked};
-                               $launched += $raid->{launched};
-                               push @raids,$raid;
-                       }
-                       $BODY->param(ClosedRaids => \@raids);
-
-
-                       $query = $DBH->prepare(q{SELECT r.id AS raid,tick,waves*COUNT(DISTINCT rt.id) AS waves,
-                               COUNT(rc.uid) AS claims, COUNT(nullif(rc.launched,false)) AS launched ,COUNT(NULLIF(uid > 0,true)) AS blocked
-                       FROM raids r JOIN raid_targets rt ON r.id = rt.raid
-                               LEFT OUTER JOIN raid_claims rc ON rt.id = rc.target
-                       WHERE removed
-                       GROUP BY r.id,tick,waves});
-                       $query->execute;
-                       my @oldraids;
-                       while (my $raid = $query->fetchrow_hashref){
-                               $raid->{waves} -= $raid->{blocked};
-                               $raid->{claims} -= $raid->{blocked};
-                               delete $raid->{blocked};
-                               $launched += $raid->{launched};
-                               push @oldraids,$raid;
-                       }
-                       $BODY->param(RemovedRaids => \@oldraids);
-                       $BODY->param(Launched => $launched);
-               }
-       }
-       return $BODY;
-}
-1;
index 088af44ebdde9598e48e4c2510d90564757b7492..16d6c7caa4925a57730cd3980d4b5ffb6ac8a1c0 100644 (file)
@@ -24,6 +24,8 @@ INSERT INTO roles VALUES('members_points_nolimit');
 INSERT INTO roles VALUES('covop');
 INSERT INTO roles VALUES('calls_list');
 INSERT INTO roles VALUES('calls_edit');
+INSERT INTO roles VALUES('raids_info');
+INSERT INTO roles VALUES('raids_edit');
 
 INSERT INTO group_roles (gid,role) VALUES(2,'member_menu');
 INSERT INTO group_roles (gid,role) VALUES(2,'attack_menu');
@@ -35,6 +37,8 @@ INSERT INTO group_roles (gid,role) VALUES(6,'calls_list');
 INSERT INTO group_roles (gid,role) VALUES(6,'calls_edit');
 
 INSERT INTO group_roles (gid,role) VALUES(4,'bc_menu');
+INSERT INTO group_roles (gid,role) VALUES(4,'raids_info');
+INSERT INTO group_roles (gid,role) VALUES(4,'raids_edit');
 
 INSERT INTO group_roles (gid,role) VALUES(5,'intel_menu');
 
@@ -52,6 +56,8 @@ INSERT INTO group_roles (gid,role) VALUES(1,'alliances_resources');
 INSERT INTO group_roles (gid,role) VALUES(1,'graphs_intel');
 INSERT INTO group_roles (gid,role) VALUES(1,'calls_list');
 INSERT INTO group_roles (gid,role) VALUES(1,'calls_edit');
+INSERT INTO group_roles (gid,role) VALUES(1,'raids_info');
+INSERT INTO group_roles (gid,role) VALUES(1,'raids_edit');
 
 INSERT INTO group_roles (gid,role) VALUES(3,'dc_menu');
 INSERT INTO group_roles (gid,role) VALUES(3,'bc_menu');
@@ -63,3 +69,5 @@ INSERT INTO group_roles (gid,role) VALUES(3,'alliances_resources');
 INSERT INTO group_roles (gid,role) VALUES(3,'graphs_intel');
 INSERT INTO group_roles (gid,role) VALUES(3,'calls_list');
 INSERT INTO group_roles (gid,role) VALUES(3,'calls_edit');
+INSERT INTO group_roles (gid,role) VALUES(3,'raids_info');
+INSERT INTO group_roles (gid,role) VALUES(3,'raids_edit');
diff --git a/database/raids.sql b/database/raids.sql
new file mode 100644 (file)
index 0000000..3df4bd1
--- /dev/null
@@ -0,0 +1,23 @@
+INSERT INTO forum_boards (fcid,fbid,board) VALUES(9,-5,'Raid logs');
+
+ALTER TABLE raids ADD COLUMN ftid INTEGER;
+
+
+CREATE OR REPLACE FUNCTION add_raid() RETURNS trigger
+AS $$
+DECLARE
+       rec RECORD;
+BEGIN
+       INSERT INTO forum_threads (ftid,fbid,subject,uid) VALUES
+               (DEFAULT,-5,'Raid ' || NEW.id,-3) RETURNING ftid INTO rec;
+       NEW.ftid := rec.ftid;
+       return NEW;
+END;
+$$
+       LANGUAGE plpgsql;
+
+
+CREATE TRIGGER add_raid
+       BEFORE INSERT ON raids
+       FOR EACH ROW
+       EXECUTE PROCEDURE add_raid();
diff --git a/lib/NDWeb/Controller/JSRPC.pm b/lib/NDWeb/Controller/JSRPC.pm
new file mode 100644 (file)
index 0000000..41c7c3d
--- /dev/null
@@ -0,0 +1,222 @@
+package NDWeb::Controller::JSRPC;
+
+use strict;
+use warnings;
+use parent 'Catalyst::Controller';
+
+=head1 NAME
+
+NDWeb::Controller::JSRPC - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+
+=head2 index 
+
+=cut
+
+sub index :Path :Args(0) {
+       my ( $self, $c ) = @_;
+
+       $c->response->body('Matched NDWeb::Controller::JSRPC in JSRPC.');
+}
+
+sub update : Local {
+       my ($self, $c, $raid, $from, $target) = @_;
+       my $dbh = $c->model;
+
+       $c->forward('/raids/findRaid');
+       $raid = $c->stash->{raid};
+
+       my $targets;;
+       if ($from){
+               my ($timestamp) = $dbh->selectrow_array("SELECT MAX(modified)::timestamp AS modified FROM raid_targets");
+               $c->stash(timestamp => $timestamp);
+               $targets = $dbh->prepare(q{SELECT r.id,r.planet FROM raid_targets r
+                       WHERE r.raid = ? AND modified > ?
+               });
+               $targets->execute($raid->{id},$from);
+       }elsif($target){
+               $targets = $dbh->prepare(q{SELECT r.id,r.planet FROM raid_targets r
+                       WHERE r.raid = $1 AND r.id = $2
+               });
+               $targets->execute($raid->{id},$target);
+       }
+
+       my $claims =  $dbh->prepare(qq{ SELECT username,joinable,launched FROM raid_claims
+               NATURAL JOIN users WHERE target = ? AND wave = ?});
+       my @targets;
+       while (my $target = $targets->fetchrow_hashref){
+               my %target;
+               $target{id} = $target->{id};
+               my @waves;
+               for (my $i = 1; $i <= $raid->{waves}; $i++){
+                       my %wave;
+                       $wave{id} = $i;
+                       $claims->execute($target->{id},$i);
+                       my $joinable = 0;
+                       my $claimers;
+                       if ($claims->rows != 0){
+                               my $owner = 0;
+                               my @claimers;
+                               while (my $claim = $claims->fetchrow_hashref){
+                                       $owner = 1 if ($c->user->username eq $claim->{username});
+                                       $joinable = 1 if ($claim->{joinable});
+                                       $claim->{username} .= '*' if ($claim->{launched});
+                                       push @claimers,$claim->{username};
+                               }
+                               $claimers = join '/', @claimers;
+                               if ($owner){
+                                       $wave{command} = 'unclaim';
+                               }elsif ($joinable){
+                                       $wave{command} = 'join';
+                               }else{
+                                       $wave{command} = 'taken';
+                               }
+                       }else{
+                               $wave{command} = 'claim';
+                       }
+                       $wave{claimers} = $claimers;
+                       $wave{joinable} = $joinable;
+                       push @waves,\%wave;
+               }
+               $target{waves} = \@waves;
+               push @targets,\%target;
+       }
+       $c->stash(targets => \@targets);
+
+}
+
+sub claim : Local {
+       my ($self, $c, $raid, $from, $target, $wave) = @_;
+       my $dbh = $c->model;
+
+       $dbh->begin_work;
+       $c->forward('assertTarget');
+
+       my $claims = $dbh->prepare(qq{SELECT username FROM raid_claims
+               NATURAL JOIN users WHERE target = ? AND wave = ?
+               });
+       $claims->execute($target,$wave);
+       if ($claims->rows == 0){
+               my $query = $dbh->prepare(q{INSERT INTO raid_claims (target,uid,wave) VALUES(?,?,?)});
+               $query->execute($target,$c->user->id,$wave);
+               $c->forward('/raids/log',[$raid, "Claimed target $target wave $wave"]);
+               $c->forward('/listTargets');
+       }
+       $dbh->commit;
+
+       $c->stash(template => 'jsrpc/update.tt2');
+       $c->forward('update');
+}
+
+
+sub join : Local {
+       my ($self, $c, $raid, $from, $target, $wave) = @_;
+       my $dbh = $c->model;
+
+       $dbh->begin_work;
+       $c->forward('assertTarget');
+
+       my $claims = $dbh->prepare(q{SELECT username FROM raid_claims
+               NATURAL JOIN users WHERE target = ? AND wave = ? AND joinable = TRUE
+               });
+       $claims->execute($target,$wave);
+       if ($claims->rows != 0){
+               my $query = $dbh->prepare(q{INSERT INTO raid_claims (target,uid,wave,joinable)
+                       VALUES(?,?,?,TRUE)
+               });
+               $query->execute($target,$c->user->id,$wave);
+               $c->forward('/raids/log',[$raid, "Joined target $target wave $wave"]);
+               $c->forward('/listTargets');
+       }
+       $dbh->commit;
+
+       $c->stash(template => 'jsrpc/update.tt2');
+       $c->forward('update');
+}
+
+sub unclaim : Local {
+       my ($self, $c, $raid, $from, $target, $wave) = @_;
+       my $dbh = $c->model;
+
+       $dbh->begin_work;
+       my $query = $dbh->prepare(q{DELETE FROM raid_claims WHERE target = ?
+               AND uid = ? AND wave = ?
+               });
+       $query->execute($target,$c->user->id,$wave);
+       $c->forward('/raids/log',[$raid, "Unclaimed target $target wave $wave"]);
+       $dbh->commit;
+
+       $c->stash(template => 'jsrpc/update.tt2');
+       $c->forward('/listTargets');
+       $c->forward('update');
+}
+
+sub joinable : Local {
+       my ($self, $c, $raid, $from, $target, $wave,$joinable) = @_;
+       my $dbh = $c->model;
+
+       my $claims = $dbh->prepare(q{SELECT username FROM raid_claims NATURAL JOIN users
+               WHERE target = ? AND wave = ? AND uid = ?
+               });
+       $claims->execute($target,$wave,$c->user->id);
+       if ($claims->rows != 0){
+               my $query = $dbh->prepare(q{UPDATE raid_claims SET joinable = NOT ?
+                       WHERE target = ? AND wave = ?
+               });
+               $query->execute($joinable,$target,$wave);
+               $c->forward('/listTargets');
+       }
+
+       $c->stash(template => 'jsrpc/update.tt2');
+       $c->forward('/listTargets');
+       $c->forward('update');
+}
+
+sub listTargets : Local {
+       my ($self, $c) = @_;
+
+       $c->stash(template => 'jsrpc/update.tt2');
+       $c->forward('/listTargets');
+}
+
+sub assertTarget : Private {
+       my ($self, $c, $raid, $from, $target, $wave) = @_;
+       my $dbh = $c->model;
+
+       my $findtarget = $dbh->prepare(q{SELECT rt.id FROM raid_targets rt
+               NATURAL JOIN raid_access ra NATURAL JOIN groupmembers
+               WHERE uid = ? AND id = ?
+               FOR UPDATE
+       });
+
+       my $result = $dbh->selectrow_array($findtarget,undef,$c->user->id,$target);
+       if ($result != $target){
+               $dbh->rollback;
+               die 'Access denied';
+       }
+}
+
+sub end : ActionClass('RenderView') {
+       my ($self,$c) = @_;
+       $c->res->content_type('application/xml');
+}
+
+=head1 AUTHOR
+
+Michael Andreen (harv@ruin.nu)
+
+=head1 LICENSE
+
+GPL 2.0, or later
+
+=cut
+
+1;
diff --git a/lib/NDWeb/Controller/Raids.pm b/lib/NDWeb/Controller/Raids.pm
new file mode 100644 (file)
index 0000000..13a2956
--- /dev/null
@@ -0,0 +1,255 @@
+package NDWeb::Controller::Raids;
+
+use strict;
+use warnings;
+use parent 'Catalyst::Controller';
+
+use POSIX;
+use NDWeb::Include;
+use ND::Include;
+
+=head1 NAME
+
+NDWeb::Controller::Raids - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+
+=head2 index 
+
+=cut
+
+sub index :Path :Args(0) {
+       my ( $self, $c ) = @_;
+       my $dbh = $c->model;
+
+       my $launched = 0;
+       my $query = $dbh->prepare(q{SELECT r.id,released_coords AS releasedcoords,tick,waves*COUNT(DISTINCT rt.id) AS waves,
+                       COUNT(rc.uid) AS claims, COUNT(nullif(rc.launched,false)) AS launched,COUNT(NULLIF(rc.uid > 0,true)) AS blocked
+               FROM raids r JOIN raid_targets rt ON r.id = rt.raid
+                       LEFT OUTER JOIN raid_claims rc ON rt.id = rc.target
+               WHERE open AND not removed AND r.id 
+                       IN (SELECT raid FROM raid_access NATURAL JOIN groupmembers WHERE uid = ?)
+               GROUP BY r.id,released_coords,tick,waves});
+       $query->execute($c->user->id);
+       my @raids;
+       while (my $raid = $query->fetchrow_hashref){
+               $raid->{waves} -= $raid->{blocked};
+               $raid->{claims} -= $raid->{blocked};
+               delete $raid->{blocked};
+               $launched += $raid->{launched};
+               push @raids,$raid;
+       }
+       $c->stash(raids => \@raids);
+
+       if ($c->check_user_roles(qw/raids_info/)){
+               my $query = $dbh->prepare(q{SELECT r.id,open ,tick,waves*COUNT(DISTINCT rt.id) AS waves,
+                       COUNT(rc.uid) AS claims, COUNT(nullif(rc.launched,false)) AS launched ,COUNT(NULLIF(uid > 0,true)) AS blocked
+               FROM raids r JOIN raid_targets rt ON r.id = rt.raid
+                       LEFT OUTER JOIN raid_claims rc ON rt.id = rc.target
+               WHERE not removed AND (not open 
+                       OR r.id NOT IN (SELECT raid FROM raid_access NATURAL JOIN groupmembers WHERE uid = ?))
+               GROUP BY r.id,open,tick,waves});
+               $query->execute($c->user->id);
+               my @raids;
+               while (my $raid = $query->fetchrow_hashref){
+                       $raid->{waves} -= $raid->{blocked};
+                       $raid->{claims} -= $raid->{blocked};
+                       delete $raid->{blocked};
+                       $launched += $raid->{launched};
+                       push @raids,$raid;
+               }
+               $c->stash(closedraids => \@raids);
+
+
+               $query = $dbh->prepare(q{SELECT r.id,tick,waves*COUNT(DISTINCT rt.id) AS waves,
+                       COUNT(rc.uid) AS claims, COUNT(nullif(rc.launched,false)) AS launched ,COUNT(NULLIF(uid > 0,true)) AS blocked
+               FROM raids r JOIN raid_targets rt ON r.id = rt.raid
+                       LEFT OUTER JOIN raid_claims rc ON rt.id = rc.target
+               WHERE removed
+               GROUP BY r.id,tick,waves});
+               $query->execute;
+               my @oldraids;
+               while (my $raid = $query->fetchrow_hashref){
+                       $raid->{waves} -= $raid->{blocked};
+                       $raid->{claims} -= $raid->{blocked};
+                       delete $raid->{blocked};
+                       $launched += $raid->{launched};
+                       push @oldraids,$raid;
+               }
+               $c->stash(removedraids => \@oldraids);
+               $c->stash(launched => $launched);
+       }
+
+}
+
+sub view : Local {
+       my ( $self, $c, $raid ) = @_;
+       my $dbh = $c->model;
+
+       $c->forward('findRaid');
+       $raid = $c->stash->{raid};
+
+
+       $c->stash(raid => $raid->{id});
+       my $noingal = '';
+       my $planet;
+       if ($c->user->planet){
+               my $query = $dbh->prepare("SELECT value, score,x,y FROM current_planet_stats WHERE id = ?");
+               $planet = $dbh->selectrow_hashref($query,undef,$c->user->planet);
+               $noingal = "AND NOT (x = $planet->{x} AND y = $planet->{y})";
+       }
+       $c->stash(message => parseMarkup($raid->{message}));
+       $c->stash(landingtick => $raid->{tick});
+       my $targetquery = $dbh->prepare(qq{SELECT r.id, r.planet, size, score, value
+               , p.x,p.y,p.z, race
+               , p.value - p.size*200 - 
+                       COALESCE(ps.metal+ps.crystal+ps.eonium,0)/150 - 
+                       COALESCE(ss.total ,(SELECT
+                               COALESCE(avg(total),0) FROM
+                               structure_scans)::int)*1500 AS fleetvalue
+               ,(metal+crystal+eonium)/100 AS resvalue, comment
+               , hidden, light, medium, heavy
+               FROM current_planet_stats p 
+               JOIN raid_targets r ON p.id = r.planet 
+               LEFT OUTER JOIN planet_scans ps ON p.id = ps.planet
+               LEFT OUTER JOIN structure_scans ss ON p.id = ss.planet
+               WHERE r.raid = ?
+               $noingal
+               ORDER BY size});
+       $targetquery->execute($raid->{id});
+       my @targets;
+       my %production = (0 => 'None', 35 => 'Light', 65 => 'Medium', 100 => 'High');
+       while (my $target = $targetquery->fetchrow_hashref){
+               my %target;
+               if ($planet){
+                       if ($planet->{x} == $target->{x}){
+                               $target{style} = 'incluster';
+                       }
+                       $target{scorebash} = 'bash' if ($target->{score}/$planet->{score} < 0.4);
+                       $target{valuebash} = 'bash' if ($target->{value}/$planet->{value} < 0.4);
+                       #next if ($target->{score}/$planet->{score} < 0.4) && ($target->{value}/$planet->{value} < 0.4);
+               }
+               $target{id} = $target->{id};
+               $target{race} = $target->{race};
+               my $num = pow(10,length($target->{score})-2);
+               $target{score} = "Hidden"; #ceil($target->{score}/$num)*$num;
+               $num = pow(10,length($target->{value})-2);
+               $target{value} = "Hidden"; #ceil($target->{value}/$num)*$num;
+               $num = pow(10,length($target->{size})-2);
+               $target{size} = floor($target->{size}/$num)*$num;
+               $num = pow(10,length($target->{fleetvalue})-2);
+               $target{fleetvalue} = floor($target->{fleetvalue}/$num)*$num;
+               if (defined $target->{resvalue}){
+                       $num = pow(10,length($target->{resvalue})-2);
+                       $target{resvalue} = floor($target->{resvalue}/$num)*$num;
+               }
+               $target{comment} = parseMarkup($target->{comment}) if ($target->{comment});
+               
+               $target{hidden} = int($target->{hidden} / 100);
+               $target{light} = $production{$target->{light}};
+               $target{medium} = $production{$target->{medium}};
+               $target{heavy} = $production{$target->{heavy}};
+
+               my $unitscans = $dbh->prepare(q{ 
+                       SELECT DISTINCT ON (name) i.id,i.name, i.tick, i.amount 
+                       FROM fleets i
+                       WHERE  i.uid = -1
+                               AND i.sender = ?
+                               AND i.mission = 'Full fleet'
+                       GROUP BY i.id,i.tick,i.name,i.amount
+                       ORDER BY name,i.tick DESC
+               });
+               $unitscans->execute($target->{planet});
+               my $ships = $dbh->prepare(q{SELECT ship,amount FROM fleet_ships
+                       WHERE id = ? ORDER BY num
+               });
+               my @missions;
+               while (my $mission = $unitscans->fetchrow_hashref){
+                       my @ships;
+                       $ships->execute($mission->{id});
+                       while (my $ship = $ships->fetchrow_hashref){
+                               push @ships,$ship;
+                       }
+                       push @ships, {ship => 'No', amount => 'ships'} if @ships == 0;
+                       $mission->{ships} = \@ships;
+                       $mission->{amount} =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; #Add comma for ever 3 digits, i.e. 1000 => 1,000
+                       delete $mission->{id};
+                       push @missions,$mission;
+               }
+               $target{missions} = \@missions;
+
+               my $query = $dbh->prepare(q{SELECT DISTINCT ON(rid) tick,category,name,amount
+                       FROM planet_data pd JOIN planet_data_types pdt ON pd.rid = pdt.id
+                       WHERE pd.id = $1 AND rid in (1,2,3,4,5,6,9,10,14,15,16,17,18)
+                       ORDER BY rid,tick DESC
+               });
+               $query->execute($target->{planet});
+               while (my $data = $query->fetchrow_hashref){
+                       $data->{amount} =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; #Add comma for ever 3 digits, i.e. 1000 => 1,000
+                       $data->{name} =~ s/ /_/g;
+                       $target{$data->{category}.$data->{name}} = $data->{amount};
+               }
+
+               my @roids;
+               my @claims;
+               my $size = $target{size};
+               for (my $i = 1; $i <= $raid->{waves}; $i++){
+                       my $roids = floor(0.25*$size);
+                       $size -= $roids;
+                       my $xp = 0;
+                       if ($planet){
+                               $xp = pa_xp($roids,$planet->{score},$planet->{value},$target->{score},$target->{value});
+                       }
+                       push @roids,{wave => $i, roids => $roids, xp => $xp};
+                       push @claims,{wave => $i}
+               }
+               $target{roids} = \@roids;
+               $target{claims} = \@claims;
+
+               push @targets,\%target;
+       }
+       @targets = sort {$b->{roids}[0]{xp} <=> $a->{roids}[0]{xp} or $b->{size} <=> $a->{size}} @targets;
+
+       $c->stash(targets => \@targets);
+}
+
+sub log : Private {
+       my ($self, $c, $raid, $message) = @_;
+       my $dbh = $c->model;
+
+       my $log = $dbh->prepare(q{INSERT INTO forum_posts (uid,ftid,message)
+               VALUES($1,(SELECT ftid FROM raids WHERE id = $2),$3)
+               });
+       $log->execute($c->user->id,$raid,$message);
+}
+
+sub findRaid : Private {
+       my ( $self, $c, $raid ) = @_;
+       my $dbh = $c->model;
+
+       my $query = $dbh->prepare(q{SELECT id,tick,waves,message,released_coords
+               FROM raids WHERE id = ? AND open AND not removed AND id IN
+                       (SELECT raid FROM raid_access NATURAL JOIN groupmembers WHERE uid = ?)
+               });
+       $raid = $dbh->selectrow_hashref($query,undef,$raid,$c->user->id);
+       $c->stash(raid => $raid);
+}
+
+=head1 AUTHOR
+
+Michael Andreen (harv@ruin.nu)
+
+=head1 LICENSE
+
+GPL 2.0, or later.
+
+=cut
+
+1;
index 4f8cced40415ab2b905d7c8bc732bbd5f4561b05..43431ce9f812f0b966da3458b243e8b179727198 100644 (file)
@@ -1,18 +1,19 @@
-[% IF targets%]
+[% IF claimedtargets.size > 0 %]
 <table>
        <tr><th>Target</th><th>Tick</th></tr>
        [% FOR target IN claimedtargets %]
        <tr>
-               <td><a href="[% target.released_coords and c.uri_for('/check',target.coords)%]">
-                       [% target.released_coords and target.coords%][% IF target.launched%]*[% END %]</a></td>
-               <td><a href="[% c.uri_for('/raid',target.raid)%]#target[% target.id %]">
+               <td>[% IF target.released_coords %]<a href="[% c.uri_for('/stats/find',target.coords)%]">
+                               [% target.coords%][% IF target.launched%]*[% END %]</a>
+                       [%ELSE%]Target [%target.id%][% END %]</td>
+               <td><a href="[% c.uri_for('/raids/view',target.raid)%]#target[% target.id %]">
                        [% target.landingtick %]</a></td>
                <td>
-                       <input title="Unclaim target" type="button" value="U" class="small" onclick = 
-                       "claim('/raids?xml=1&amp;raid=[% target.raid %]',[% target.id %],[% target.wave %],'Unclaim')" />
+                       <input title="Unclaim target" type="button" value="U" class="small" onclick =
+                       "$.get('/jsrpc/unclaim/[% target.raid %]//[% target.id %]/[% target.wave %]',{},parseUpdate)">
                        <input title="[% IF target.joinable %]Disable joinable[% ELSE %]Make target joinable[% END %]"
                                type="button" class="small" value="[% IF target.joinable %]N[% ELSE %]J[% END %]" onclick = 
-                       "claim('/raids?xml=1&amp;raid=[% target.raid %]',[% target.id %],[% target.wave %],'set&amp;joinable=[% target.joinable %]')" />
+                       "$.get('/jsrpc/joinable/[% target.raid %]//[% target.id %]/[% target.wave %]/[% target.joinable %]',{},parseUpdate)">
                </td>
        </tr>
        [% END %]
index 6c1aea1dc8bc1b5f8695ddb35e778f79b275069e..733ac21db8c5d8a038daa1a3b62adbc4c3d69ecb 100644 (file)
@@ -58,7 +58,7 @@
        <li><a href="/raids">Web raids</a></li>
 </ul>
 <p><input type="button" value="Update target list"
-               onclick = "listTargets('/jsrpc/targetList')">
+               onclick = "listTargets()">
 </p>
 <div id="targets">[% PROCESS inc/targetlist.tt2 %]</div>
 [% END %]
index 3a7af0765dcb20b656797323305f190df844df75..6da016bffd2c9e070dc84d20bcfbdf71a814ac3d 100644 (file)
@@ -4,6 +4,9 @@
 ELSIF template.name.match('graphs/');
        debug("Passing page through graph: $template.name");
        content;
+ELSIF template.name.match('jsrpc/');
+       debug("Passing page through xml: $template.name");
+       content WRAPPER site/xml.tt2;
 ELSE;
        debug("Applying HTML page layout wrappers to $template.name\n");
        content WRAPPER site/html.tt2 + site/layout.tt2;
diff --git a/root/lib/site/xml.tt2 b/root/lib/site/xml.tt2
new file mode 100644 (file)
index 0000000..f752df8
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<response>
+[% content %]
+</response>
diff --git a/root/src/jsrpc/update.tt2 b/root/src/jsrpc/update.tt2
new file mode 100644 (file)
index 0000000..ff6e91a
--- /dev/null
@@ -0,0 +1,19 @@
+[% IF timestamp %]
+       <timestamp>[% timestamp %]</timestamp>
+[% END %]
+[% FOR t IN targets %]
+       <target id="[% t.id %]">
+       [% FOR w IN t.waves %]
+               <wave id="[% w.id %]">
+                       <command>[% w.command %]</command>
+                       <claimers>[% w.claimers %]</claimers>
+                       <joinable>[% w.joinable %]</joinable>
+               </wave>
+       [% END %]
+       </target>
+[% END %]
+[% IF claimedtargets %]
+<targetlist>
+[% PROCESS inc/targetlist.tt2 | html %]
+</targetlist>
+[% END %]
diff --git a/root/src/raids/index.tt2 b/root/src/raids/index.tt2
new file mode 100644 (file)
index 0000000..485ebde
--- /dev/null
@@ -0,0 +1,55 @@
+[% META title = 'List raids' %]
+[% IF launched %]
+       <p>Total launched fleets: [% launched %]</p>
+[% END %]
+<h3> Open raids </h3>
+[% FOR r IN raids %]
+       <p><a href="[% c.uri_for('view',r.id) %]">Raid [% r.id %]</a>
+       Landing tick: [% r.tick %]
+       [% IF c.check_user_roles('raids_edit') %]
+               <a href="[% c.uri_for('edit',r.id) %]">Edit</a>
+               <a href="[% c.uri_for('close',r.id) %]">Close raid.</a>
+               [% UNLESS r.releasedcoords %]
+               <a href="[% c.uri_for('showcoords',r.id) %]">Show coords.</a>
+               [% END %]
+       [% END %]
+       [% IF c.check_user_roles('raids_info') %]
+               Waves: [% r.waves %]
+               Claims: [% r.claims %]
+               Launched: [% r.launched %]
+       [% END %]
+       </p>
+[% END %]
+
+[% IF c.check_user_roles('raids_info') %]
+<h3> Closed raids </h3>
+       [% FOR r IN closedraids %]
+       <p>
+               [% IF c.check_user_roles('raids_edit') %]
+               <a href="[% c.uri_for('edit',r.id) %]">Edit Raid [% r.id %]</a>
+               <a href="[% c.uri_for('open',r.id) %]">Open raid.</a>
+                       [% UNLESS r.releasedcoords %]
+               <a href="[% c.uri_for('showcoords',r.id) %]">Show coords.</a>
+                       [% END %]
+               [% END %]
+               Landing tick: [% r.tick %]
+               Waves: [% r.waves %]
+               Claims: [% r.claims %]
+               Launched: [% r.launched %]
+       </p>
+       [% END %]
+
+<h3> Removed raids </h3>
+       [% FOR r IN removedraids %]
+       <p>
+               [% IF c.check_user_roles('raids_edit') %]
+               <a href="[% c.uri_for('edit',r.id) %]">Edit Raid [% r.id %]</a>
+               <a href="[% c.uri_for('open',r.id) %]">Open raid.</a>
+               [% END %]
+               Landing tick: [% r.tick %]
+               Waves: [% r.waves %]
+               Claims: [% r.claims %]
+               Launched: [% r.launched %]
+       </p>
+       [% END %]
+[% END %]
diff --git a/root/src/raids/view.tt2 b/root/src/raids/view.tt2
new file mode 100644 (file)
index 0000000..e163b9d
--- /dev/null
@@ -0,0 +1,147 @@
+[% META title = 'Raid claiming' %]
+
+<fieldset> <legend>Message</legend>
+       <p><b>REMEMBER TO PASTE LAUNCH CONFIRMATION IF YOU WANT AN ATTACK POINT</b></p>
+       <p><b style="color: red;">DO NOT JOIN A WAVE UNLESS YOU HAVE PERMISSION FROM THE PERSON WHO CLAIMED IT</b></p>
+       <p><b style="color: purple;">COORDS ARE NOT SHOWN UNTIL AT LEAST 10 MIN AFTER YOUR CLAIM</b></p>
+       <p>Landing tick first wave: [% landingtick %]</p>
+       [% message %]
+</fieldset>
+
+<div id="floatmenu" style="right: 1em; top: 50px; position: absolute; marigin-left:120px;">
+<form action="" method="post">
+       <ul class="linkbar">
+               <li><input type="button" value="Update claims"
+                       onclick = "update()">
+               <li><input type="button" value="Update target list"
+                       onclick = "listTargets()">
+       </ul>
+</form>
+</div>
+
+[% FOR t IN targets %]
+<fieldset class="[% t.style %]"> <legend><a name="target[% t.id %]">Target: #[% t.id %]</a></legend>
+       <div class="leftinfo"><ul>
+               <li>Size: [% t.size %]</li>
+               <li class="[% t.scorebash %]">Score: [% t.score %]</li>
+               <li class="[% t.valuebash %]">Value: [% t.value %]</li>
+               <li>Fleet value: [% t.fleetvalue %]</li>
+               <li>Resource value: [% t.resvalue %]</li>
+               <li>Hidden value: [% t.hidden %]</li>
+               <li>Factory Usage: [% t.light %], [% t.medium %], [% t.heavy %]</li>
+               <li>Race: [% t.race %]</li>
+               [% FOR r IN t.roids %]
+                       <li>Roids wave [% r.wave %]: [% r.roids %] ([% r.xp %] xp)</li>
+               [% END %]
+       </ul>
+       [% IF t.comment %]
+               <fieldset> <legend>Comment</legend>
+                       [% t.comment %]
+               </fieldset>
+       [% END %]
+       <table>
+       <tr><th></th><th>Metal</th><th>Crystal</th><th>Eonium</th></tr>
+       <tr align="center">
+               <th>Roids</th>
+               <td>[% t.roidMetal %]</td>
+               <td>[% t.roidCrystal %]</td>
+               <td>[% t.roidEonium %]</td>
+       </tr>
+       <tr align="center">
+               <th>Resources</th>
+               <td>[% t.resourceMetal %]</td>
+               <td>[% t.resourceCrystal %]</td>
+               <td>[% t.resourceEonium %]</td>
+       </tr>
+
+       </table>
+       </div>
+       <div class="leftinfo">
+       <table>
+       <tr><th>Waves</th></tr>
+       <tr>
+               <td>Research</td>
+               <td>[% t.techWaves %]</td>
+       </tr>
+       <tr>
+               <td>Amps</td>
+               <td>[% t.strucWave_Amplifier %]</td>
+       </tr>
+       <tr>
+               <td>Dists</td>
+               <td>[% t.strucWave_Distorter %]</td>
+       </tr>
+       <tr><th>Production</th></tr>
+       <tr>
+               <td>Research</td>
+               <td>[% t.techHulls %]</td>
+       </tr>
+       <tr>
+               <td>Light factory</td>
+               <td>[% t.strucLight_Factory %]</td>
+       </tr>
+       <tr>
+               <td>Medium factory</td>
+               <td>[% t.strucMedium_Factory %]</td>
+       </tr>
+       <tr>
+               <td>Heavy factory</td>
+               <td>[% t.strucHeavy_Factory %]</td>
+       </tr>
+       </table>
+       </div>
+       [% FOR m IN t.missions %]
+       <div class="leftinfo">
+
+               <p>[% m.name %]<br>
+                       Tick: [% m.tick %]<br>
+                       Ships: [% m.amount %]
+               </p>
+               <table>
+               [% FOR s IN m.ships %]
+               <tr class="[% loop.count % 2 == 0 ? 'even' : 'odd' %]">
+                       <td>[% s.ship %]</td><td>[% s.amount %]</td>
+               </tr>
+               [% END %]
+               </table>
+       </div>
+       [% END %]
+       <div class="clear"> &nbsp;</div>
+       <form action="" method="post">
+       <p class="claimlinks">
+       <span id="claim[% t.id %]">
+       [% FOR w IN t.claims %]
+       <input type="button" value="Claim wave [% w.wave %]"
+               onclick = "claim([% t.id %], [% w.wave %], 'claim')">
+       [% END %]
+       </span>
+       </p>
+       </form>
+</fieldset>
+[% END %]
+
+<script type="text/javascript">
+function update(){
+       $.get("/jsrpc/update/[% raid %]/"+modified,{},parseUpdate);
+}
+
+function claim(target,wave,command){
+       $.get("/jsrpc/"+command+"/"+[% raid %]+"/"+modified+"/"+target+"/"+wave,{},parseUpdate);
+}
+
+function join(target,wave,joinable){
+       $.get("/jsrpc/joinable/"+[% raid %]+"/"+modified+"/"+target+"/"+wave+"/"+joinable,{},parseUpdate);
+}
+
+$(document).ready(function(){
+       update();
+       var targets = $('#targets');
+       $('#targets').remove();
+       $('#floatmenu').append(targets);
+       var menuYloc = parseInt($("#floatmenu").css("top").substring(0,$("#floatmenu").css("top").indexOf("px")))
+       $(window).scroll(function () {
+               var offset = menuYloc+$(document).scrollTop()+"px";
+               $('#floatmenu').animate({top:offset},{duration:500,queue:false});
+    });
+});
+</script>
index 3275e9f11cc2098815a0d9710f10313234f245ca..84d6b4b47e42b47b4215e39a0a17e7340f6d9833 100644 (file)
@@ -129,20 +129,19 @@ td.Attack{
        color: black;
 }
 
-a.Unclaim{
-       color: green;
-}
-input.Unclaim{
+input.unclaim{
        background: green;
 }
-a.Claim{
-       color: blue;
+input.join{
+       background: #00AAAA;
 }
-a.Join{
-       color: #00AAAA;
+input.taken{
+       background: #AA0000;
 }
-input.Join{
-       background: #00AAAA;
+
+input.blocked{
+       background: black;
+       color: gray;
 }
 
 td.Friendly{
index 8bec240b57e1689932cfe721bf490b2618e3b091..89a06b6c05c6bfd9f7354f83a62ab2ae7011df13 100644 (file)
-function getHTTPObject() {
-  var xmlhttp;
-  /*@cc_on
-  @if (@_jscript_version >= 5)
-    try {
-      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
-    } catch (e) {
-      try {
-        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
-      } catch (E) {
-        xmlhttp = false;
-      }
-    }
-  @else
-  xmlhttp = false;
-  @end @*/
+modified = "0000-01-01";
 
-  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
-    try {
-      xmlhttp = new XMLHttpRequest();
-    } catch (e) {
-      xmlhttp = false;
-    }
-  }
-  return xmlhttp;
-}
-
-var modified = '_';
-
-function claim(dataSource, target, wave,cmd){
-       var HTTP = getHTTPObject();
-       if(HTTP) {
-               var url = dataSource + '&cmd='+cmd+'&target=' + target + '&wave=' + wave + '&rand='+ Math.random();
-               //obj.innerHTML = "test";
-               HTTP.open("GET", url,true);
-               HTTP.onreadystatechange = function(){
-                       if (HTTP.readyState == 4 &&
-                                       HTTP.status == 200) {
-                               updateClaims(dataSource,HTTP.responseXML,false);
-                               var obj = document.getElementById("targets");
-                               if (obj){
-                                       clearObject(obj);
-                                       var re = new RegExp("targetlist>((.|\\n)*)</targetlist");
-                                       if(re.test(HTTP.responseText))
-                                               obj.innerHTML = RegExp.$1;
-                               }
-                       }
-               }
-               HTTP.send(null);
-       }
-}
-
-function clearObject(obj){
-       while (obj.hasChildNodes()){
-               obj.removeChild(obj.firstChild);
-       }
-}
-
-function listTargets(dataSource){
-       var http = getHTTPObject();
-       http.open("GET",dataSource+'&cmd=gettargets' + '&rand='+ Math.random(),true);
-       http.onreadystatechange = function(){
-               if (http.readyState == 4 &&
-                               http.status == 200) {
-                       var obj = document.getElementById("targets");
-                       if (obj){
-                               clearObject(obj);
-                               var re = new RegExp("targetlist>((.|\\n)*)</targetlist");
-                               if(re.test(http.responseText))
-                                       obj.innerHTML = RegExp.$1;
-                       }
-               }
-       }
-       http.send(null);
-}
-
-function update(dataSource){
-       var HTTP = getHTTPObject();
-       if(HTTP) {
-               HTTP.open("GET",dataSource+"&cmd=update&from="+modified + '&rand='+ Math.random(),true);
-               HTTP.onreadystatechange = function(){
-                       if (HTTP.readyState == 4 &&
-                                       HTTP.status == 200) {
-                               updateClaims(dataSource,HTTP.responseXML,true);
+function parseUpdate(xml){
+       if ($('timestamp',xml).text())
+               modified = $('timestamp',xml).text();
+       $('target',xml).each(function(i){
+               var target = $(this).attr('id');
+               var div = $('#claim'+target).empty();
+               $('wave',$(this)).each(function(i){
+                       var wave = $(this).attr('id');
+                       var b = $('<input type="button">');
+                       var command = $(this).find('command').text();
+                       b.addClass(command);
+                       b.click(function(){
+                               claim(target,wave,command);
+                       });
+                       div.append(b);
+                       switch ($(this).find('command').text()){
+                               case 'taken':
+                                       b.attr('disabled','disabled');
+                                       b.val('Taken by '+$(this).find('claimers').text());
+                                       if ($(this).find('claimers').text() == 'BLOCKED'){
+                                               b.val($(this).find('claimers').text());
+                                               b.addClass('blocked');
+                                       }
+                                       break;
+                               case 'claim':
+                                       b.val('Claim wave '+wave);
+                                       break;
+                               case 'join':
+                                       b.val('Join wave '+wave
+                                               +' ('+$(this).find('claimers').text()+')');
+                                       break;
+                               case 'unclaim':
+                                       b.val('Unclaim wave '+wave
+                                               +' ('+$(this).find('claimers').text()+')');
+                                       var j = $('<input type="button">');
+                                       var joinable = $(this).find('joinable').text();
+                                       j.click(function(){
+                                               join(target,wave,joinable);
+                                       });
+                                       div.append(j);
+                                       switch(joinable){
+                                               case '0':
+                                                       j.val('J');
+                                                       j.attr('title','Make target joinable');
+                                                       break;
+                                               case '1':
+                                                       j.val('N');
+                                                       j.attr('title','Disable joinable');
+                                               break;
+                                       }
+                                       break;
                        }
-               }
-               HTTP.send(null);
+               });
+       });
+       if ($('targetlist',xml).text()){
+               $('#targets').empty().html($('targetlist',xml).text());
        }
 }
 
-function updateClaims(dataSource,xmlthingy,timestamp){
-       var targets = xmlthingy.getElementsByTagName("target");
-       for (var i = 0; i < targets.length; i++){
-               var target = targets[i].attributes.getNamedItem("id").nodeValue;
-               var obj = document.getElementById("claim"+target);
-               if (!obj)
-                       continue;
-               //obj.innerHTML = '';
-               clearObject(obj);
-               var waves = targets[i].getElementsByTagName("wave");;
-               for (var j = 0; j < waves.length; j++){
-                       var command = waves[j].getElementsByTagName("command")[0];
-                       var claimers = waves[j].getElementsByTagName("claimers")[0];
-                       var joinable = waves[j].getElementsByTagName("joinable")[0];
-                       var wave = waves[j].attributes.getNamedItem("id").nodeValue;
-                       command = command.firstChild.nodeValue;
-                       if(claimers.firstChild){
-                               claimers = '('+claimers.firstChild.nodeValue+')';
-                       }else
-                               claimers = '';
-                       joinable = joinable.firstChild.nodeValue;
 
-                       if (command == 'none'){
-                               var s = document.createElement("b");
-                               s.appendChild(document.createTextNode("Claimed by "+claimers));
-                               obj.appendChild(s);
-                       }else{
-                               var b = document.createElement("input");
-                               b.type = 'button';
-                               b.setAttribute("class", command);
-                               b.value = command +' wave '+wave+' '+claimers;
-                               b.setAttribute("onclick", "claim('"+dataSource+"',"+target+","+wave+",'"+command+"');");
-                               /*b.onclick = function(){
-                                       claim(dataSource,t,wave,command);
-                               }*/
-                               obj.appendChild(b);
-                       }
-                       if (command == 'Unclaim'){
-                               var b = document.createElement("input");
-                               b.type = 'button';
-                               b.value = 'J';
-                               b.title = 'Make target joinable';
-                               command = 'set&joinable=TRUE';
-                               if (joinable == 1){
-                                       b.value = 'N';
-                                       b.title = 'Disable join';
-                                       command = 'set&joinable=FALSE';
-                               }
-                               b.setAttribute("onclick", "claim('"+dataSource+"',"+target+","+wave+",'"+command+"');");
-                               obj.appendChild(b);
-                       }
-                       /*@cc_on
-                       obj.innerHTML = obj.innerHTML; // IE doesn't understand unless you tell it twice
-                       @*/
-               }
-               /*
-               obj = document.getElementById("coords"+target);
-               var coords = targets[i].getElementsByTagName("coords");;
-               if (obj)
-                       obj.innerHTML = coords[0].firstChild.nodeValue;
-               */
-       }
-       if (timestamp){
-               timestamp = xmlthingy.getElementsByTagName("timestamp");
-               if (timestamp)
-                       modified = timestamp[0].firstChild.nodeValue;
-       }
+function listTargets(){
+       $.get("/jsrpc/listTargets",{},parseUpdate);
 }
diff --git a/t/controller_JSRPC.t b/t/controller_JSRPC.t
new file mode 100644 (file)
index 0000000..8a4f0db
--- /dev/null
@@ -0,0 +1,10 @@
+use strict;
+use warnings;
+use Test::More tests => 3;
+
+BEGIN { use_ok 'Catalyst::Test', 'NDWeb' }
+BEGIN { use_ok 'NDWeb::Controller::JSRPC' }
+
+ok( request('/jsrpc')->is_success, 'Request should succeed' );
+
+
diff --git a/t/controller_Raids.t b/t/controller_Raids.t
new file mode 100644 (file)
index 0000000..129d23b
--- /dev/null
@@ -0,0 +1,10 @@
+use strict;
+use warnings;
+use Test::More tests => 3;
+
+BEGIN { use_ok 'Catalyst::Test', 'NDWeb' }
+BEGIN { use_ok 'NDWeb::Controller::Raids' }
+
+ok( request('/raids')->is_success, 'Request should succeed' );
+
+
diff --git a/templates/raids.tmpl b/templates/raids.tmpl
deleted file mode 100644 (file)
index 4b88667..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-<TMPL_IF isBC>
-       <p>Total launched fleets: <TMPL_VAR NAME=Launched></p>
-</TMPL_IF>
-<p> Open raids </p>
-<TMPL_LOOP Raids>
-       <p><a href="/<TMPL_VAR NAME=PAGE>?raid=<TMPL_VAR NAME=Raid>">Raid <TMPL_VAR NAME=Raid></a>
-       Landing tick: <TMPL_VAR NAME=tick>
-       <TMPL_IF isBC>
-               <a href="editRaid?raid=<TMPL_VAR NAME=Raid>">Edit</a>
-               <a href="editRaid?raid=<TMPL_VAR NAME=Raid>&amp;cmd=Close">Close raid.</a>
-               <TMPL_UNLESS ReleasedCoords>
-               <a href="editRaid?raid=<TMPL_VAR NAME=Raid>&amp;cmd=showcoords">Show coords.</a>
-               </TMPL_UNLESS>
-               Waves: <TMPL_VAR NAME=Waves>
-               Claims: <TMPL_VAR NAME=Claims>
-               Launched: <TMPL_VAR NAME=Launched>
-       </TMPL_IF>
-       </p>
-</TMPL_LOOP>
-<TMPL_IF ClosedRaids>
-<p> Closed raids </p>
-<TMPL_LOOP ClosedRaids>
-               <p>
-                       <a href="editRaid?raid=<TMPL_VAR NAME=Raid>">Edit raid <TMPL_VAR NAME=Raid></a>
-                       Landing tick: <TMPL_VAR NAME=tick>
-                       <TMPL_UNLESS Open>
-                       <a href="editRaid?raid=<TMPL_VAR NAME=Raid>&amp;cmd=Open">Open raid.</a>
-                       </TMPL_UNLESS>
-                       Waves: <TMPL_VAR NAME=Waves>
-                       Claims: <TMPL_VAR NAME=Claims>
-                       Launched: <TMPL_VAR NAME=Launched>
-               </p>
-</TMPL_LOOP>
-</TMPL_IF>
-
-<TMPL_IF RemovedRaids>
-<p> Removed raids </p>
-<TMPL_LOOP RemovedRaids>
-               <p>
-                       <a href="editRaid?raid=<TMPL_VAR NAME=Raid>">Edit raid <TMPL_VAR NAME=Raid></a>
-                       Landing tick: <TMPL_VAR NAME=tick>
-                       Waves: <TMPL_VAR NAME=Waves>
-                       Claims: <TMPL_VAR NAME=Claims>
-                       Launched: <TMPL_VAR NAME=Launched>
-               </p>
-</TMPL_LOOP>
-</TMPL_IF>
-
-<TMPL_IF Raid>
-<fieldset> <legend>Message</legend>
-       <p><b>REMEMBER TO PASTE LAUNCH CONFIRMATION IF YOU WANT AN ATTACK POINT</b></p>
-       <p><b style="color: red;">DO NOT JOIN A WAVE UNLESS YOU HAVE PERMISSION FROM THE PERSON WHO CLAIMED IT</b></p>
-       <p><b style="color: purple;">COORDS ARE NOT SHOWN UNTIL AT LEAST 10 MIN AFTER YOUR CLAIM</b></p>
-       <p>Landing tick first wave: <TMPL_VAR NAME=LandingTick></p>
-       <TMPL_VAR ESCAPE=NONE NAME=Message>
-</fieldset>
-
-<TMPL_IF Ajax>
-<form action="<TMPL_VAR NAME=PAGE>" method="post">
-       <p>
-               <input type="button" value="Update claims"
-                       onclick = "update('/<TMPL_VAR NAME=PAGE>?xml=1;raid=<TMPL_VAR NAME=Raid>')"/>
-               <input type="button" value="Update target list"
-                       onclick = "listTargets('/<TMPL_VAR NAME=PAGE>?xml=1;raid=<TMPL_VAR NAME=Raid>')"/>
-       </p>
-</form>
-</TMPL_IF>
-<TMPL_LOOP Targets>
-<fieldset class="<TMPL_VAR Name=Style>"> <legend><a name="target<TMPL_VAR NAME=Id>">Target: #<TMPL_VAR NAME=Id></a></legend>
-
-       <div class="leftinfo"><ul>
-               <li>Size: <TMPL_VAR NAME=Size></li>
-               <li class="<TMPL_VAR NAME=ScoreBash>">Score: <TMPL_VAR NAME=Score></li>
-               <li class="<TMPL_VAR NAME=ValueBash>">Value: <TMPL_VAR NAME=Value></li>
-               <li>Fleet value: <TMPL_VAR NAME=FleetValue></li>
-               <li>Resource value: <TMPL_VAR NAME=ResValue></li>
-               <li>Hidden value: <TMPL_VAR NAME=Hidden></li>
-               <li>Factory Usage: <TMPL_VAR NAME=Light>, <TMPL_VAR NAME=Medium>, <TMPL_VAR NAME=Heavy></li>
-               <li>Race: <TMPL_VAR NAME=Race></li>
-               <TMPL_LOOP Roids>
-                       <li>Roids wave <TMPL_VAR NAME=Wave>: <TMPL_VAR NAME=Roids> (<TMPL_VAR NAME=XP> xp)</li>
-               </TMPL_LOOP>
-       </ul>
-       <TMPL_IF Comment>
-               <fieldset> <legend>Comment</legend>
-                       <TMPL_VAR ESCAPE=NONE NAME=Comment>
-               </fieldset>
-       </TMPL_IF>
-       <table>
-       <tr><th></th><th>Metal</th><th>Crystal</th><th>Eonium</th></tr>
-       <tr align="center">
-               <th>Roids</th>
-               <td><TMPL_VAR NAME=roidMetal></td>
-               <td><TMPL_VAR NAME=roidCrystal></td>
-               <td><TMPL_VAR NAME=roidEonium></td>
-       </tr>
-       <tr align="center">
-               <th>Resources</th>
-               <td><TMPL_VAR NAME=resourceMetal></td>
-               <td><TMPL_VAR NAME=resourceCrystal></td>
-               <td><TMPL_VAR NAME=resourceEonium></td>
-       </tr>
-
-       </table>
-       </div>
-       <div class="leftinfo">
-       <table>
-       <tr><th>Waves</th></tr>
-       <tr>
-               <td>Research</td>
-               <td><TMPL_VAR NAME=techWaves></td>
-       </tr>
-       <tr>
-               <td>Amps</td>
-               <td><TMPL_VAR NAME="strucWave Amplifier"></td>
-       </tr>
-       <tr>
-               <td>Dists</td>
-               <td><TMPL_VAR NAME="strucWave Distorter"></td>
-       </tr>
-       <tr><th>Production</th></tr>
-       <tr>
-               <td>Research</td>
-               <td><TMPL_VAR NAME=techHulls></td>
-       </tr>
-       <tr>
-               <td>Light factory</td>
-               <td><TMPL_VAR NAME="strucLight Factory"></td>
-       </tr>
-       <tr>
-               <td>Medium factory</td>
-               <td><TMPL_VAR NAME="strucMedium Factory"></td>
-       </tr>
-       <tr>
-               <td>Heavy factory</td>
-               <td><TMPL_VAR NAME="strucHeavy Factory"></td>
-       </tr>
-       </table>
-       </div>
-       <TMPL_LOOP Missions>
-       <div class="leftinfo">
-
-               <p><TMPL_VAR NAME=Name><br/>
-                       Tick: <TMPL_VAR NAME=Tick><br/>
-                       Ships:<TMPL_VAR NAME=Amount>
-               </p>
-               <table>
-               <TMPL_LOOP Ships>
-               <tr class="<TMPL_IF __odd__>odd<TMPL_ELSE>even</TMPL_IF>">
-                       <td><TMPL_VAR NAME=Ship></td><td><TMPL_VAR NAME=Amount></td>
-               </tr>
-               </TMPL_LOOP>
-               </table>
-       </div>
-       </TMPL_LOOP>
-       <div class="clear"> &nbsp;</div>
-       <form action="<TMPL_VAR NAME=PAGE>" method="post">
-       <p class="claimlinks">
-       <span id="claim<TMPL_VAR NAME=Id>">
-       <TMPL_IF Ajax>
-       <TMPL_LOOP Claims>
-     <input type="button" value="Claim wave <TMPL_VAR NAME=Wave>"
-        onclick = "claim('/<TMPL_VAR NAME=PAGE>?xml=1;raid=<TMPL_VAR NAME=Raid>',<TMPL_VAR NAME=Target>,<TMPL_VAR NAME=Wave>,'Claim')"/>
-       </TMPL_LOOP>
-       <TMPL_ELSE>
-       <TMPL_LOOP Claims>
-       <a class="<TMPL_VAR NAME=Command>" href="/<TMPL_VAR NAME=PAGE>?raid=<TMPL_VAR NAME=Raid>&amp;cmd=<TMPL_VAR NAME=Command>&amp;target=<TMPL_VAR NAME=Target>&amp;wave=<TMPL_VAR NAME=Wave>#<TMPL_VAR NAME=Target>"><TMPL_VAR NAME=Command> wave <TMPL_VAR NAME=Wave><TMPL_IF Claimers> (<TMPL_VAR NAME=Claimers>)</TMPL_IF></a>
-       <TMPL_IF Owner><a href="/<TMPL_VAR NAME=PAGE>?raid=<TMPL_VAR NAME=Raid>&amp;target=<TMPL_VAR NAME=Target>&amp;cmd=set&amp;joinable=<TMPL_IF Joinable>FALSE<TMPL_ELSE>TRUE</TMPL_IF>&amp;wave=<TMPL_VAR NAME=Wave>#<TMPL_VAR NAME=Target>"><TMPL_IF Joinable>N<TMPL_ELSE>J</TMPL_IF></a></TMPL_IF>
-       </TMPL_LOOP>
-       </TMPL_IF>
-       </span>
-       </p>
-       </form>
-</fieldset>
-</TMPL_LOOP>
-<TMPL_IF Ajax>
-       <script type="text/javascript">
-       update('/<TMPL_VAR NAME=PAGE>?xml=1;raid=<TMPL_VAR NAME=Raid>');
-       </script>
-</TMPL_IF>
-
-</TMPL_IF>
diff --git a/templates/raids.xml.tmpl b/templates/raids.xml.tmpl
deleted file mode 100644 (file)
index 804a379..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<targets>
-       <timestamp><TMPL_VAR NAME=Timestamp></timestamp>
-<TMPL_IF TargetList>
-       <targetlist><TMPL_VAR NAME=TargetList></targetlist>
-</TMPL_IF>
-<TMPL_LOOP Targets>
-       <target id="<TMPL_VAR NAME=Id>">
-       <TMPL_LOOP Waves>
-               <wave id="<TMPL_VAR NAME=Id>">
-                       <command><TMPL_VAR NAME=Command></command>
-                       <claimers><TMPL_VAR NAME=Claimers></claimers>
-                       <joinable><TMPL_VAR NAME=Joinable></joinable>
-               </wave>
-       </TMPL_LOOP>
-       </target>
-</TMPL_LOOP>
-</targets>