Commit 3a9d947c authored by Roque's avatar Roque

Capture the flag game new features

See merge request !1824
parents 41270486 36b5ce60
......@@ -6,10 +6,11 @@ var EnemyDroneAPI = /** @class */ (function () {
"use strict";
var DEFAULT_ACCELERATION = 1,
VIEW_SCOPE = 50,
VIEW_SCOPE = 25,
DEFAULT_SPEED = 16.5,
MIN_SPEED = 12,
MAX_SPEED = 26;
MAX_SPEED = 26,
COLLISION_SECTOR = 10;
//** CONSTRUCTOR
function EnemyDroneAPI(gameManager, drone_info, flight_parameters, id) {
......@@ -21,6 +22,7 @@ var EnemyDroneAPI = /** @class */ (function () {
this._drone_info = drone_info;
this._drone_dict_list = [];
this._acceleration = DEFAULT_ACCELERATION;
this._collision_sector = COLLISION_SECTOR;
}
/*
** Function called on start phase of the drone, just before onStart AI script
......@@ -189,15 +191,16 @@ var EnemyDroneAPI = /** @class */ (function () {
EnemyDroneAPI.prototype.getDroneViewInfo = function (drone) {
var context = this, result = [], distance,
drone_position = drone.position, other_position;
function calculateDistance(a, b) {
return Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2) +
Math.pow((a.z - b.z), 2));
function calculateDistance(a, b, _3D) {
var z = (_3D ? Math.pow((a.z - b.z), 2) : 0);
return Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2) + z);
}
context._gameManager._droneList_user.forEach(function (other) {
if (other.can_play) {
other_position = other.position;
distance = calculateDistance(drone_position, other_position);
if (distance <= VIEW_SCOPE) {
//the higher the drone, the easier to detect
if (distance / (other_position.z * 0.05) <= VIEW_SCOPE) {
result.push({
position: other_position,
direction: other.direction,
......@@ -213,8 +216,7 @@ var EnemyDroneAPI = /** @class */ (function () {
};
EnemyDroneAPI.prototype.getDroneAI = function () {
//interception math based on https://www.codeproject.com/Articles/990452/Interception-of-Two-Moving-Objects-in-D-Space
return 'var BASE_DISTANCE = 300;\n' +
'function calculateInterception(hunter_position, prey_position, hunter_speed, prey_speed, prey_velocity_vector) {\n' +
return 'function calculateInterception(hunter_position, prey_position, hunter_speed, prey_speed, prey_velocity_vector) {\n' +
' var vector_from_drone, distance_to_prey, distance_to_prey_vector, a, b, c, t1, t2, interception_time, interception_point;\n' +
' function dot(a, b) {\n' +
' return a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n);\n' +
......@@ -242,7 +244,6 @@ var EnemyDroneAPI = /** @class */ (function () {
'}\n' +
'\n' +
'me.onStart = function () {\n' +
' me.base = me.position;\n' +
' me.setDirection(0,0,0);\n' +
' return;\n' +
'\n' +
......@@ -251,20 +252,6 @@ var EnemyDroneAPI = /** @class */ (function () {
'me.onUpdate = function (timestamp) {\n' +
' me.current_position = me.position;\n' +
' var drone_position, drone_velocity_vector, interception_point, drone_view,\n' +
' dist = distance(\n' +
' me.current_position,\n' +
' me.base\n' +
' );\n' +
// return to base point if drone is too far
' if (dist >= BASE_DISTANCE) {\n' +
' me.chasing = false;\n' +
' me.setTargetCoordinates(\n' +
' me.base.x,\n' +
' me.base.y,\n' +
' me.base.z\n' +
' );\n' +
' return;\n' +
' }\n' +
' drone_view = me.getDroneViewInfo();\n' +
' if (drone_view.length) {\n' +
' drone_position = drone_view[0].position;\n' +
......@@ -273,13 +260,8 @@ var EnemyDroneAPI = /** @class */ (function () {
' if (!interception_point) {\n' +
' return;\n' +
' }\n' +
' me.chasing = true;\n' +
' me.setTargetCoordinates(interception_point[0], interception_point[1], interception_point[2]);\n' +
' }\n' +
// return to base point if drone is too far
' if (!me.chasing && dist <= 10) {\n' +
' me.setDirection(0,0,0);\n' +
' }\n' +
'};';
};
EnemyDroneAPI.prototype.getMinSpeed = function () {
......@@ -330,5 +312,8 @@ var EnemyDroneAPI = /** @class */ (function () {
EnemyDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters;
};
EnemyDroneAPI.prototype.getCollisionSector = function () {
return this._collision_sector;
};
return EnemyDroneAPI;
}());
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1009.37360.49772.3874</string> </value>
<value> <string>1011.20054.25134.60962</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1688571911.82</float>
<float>1695397984.38</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -36,7 +36,6 @@ var FixedWingDroneAPI = /** @class */ (function () {
** Function called on start phase of the drone, just before onStart AI script
*/
FixedWingDroneAPI.prototype.internal_start = function (drone) {
drone._targetCoordinates = drone.getCurrentPosition();
drone._maxDeceleration = this.getMaxDeceleration();
if (drone._maxDeceleration <= 0) {
throw new Error('max deceleration must be superior to 0');
......@@ -194,6 +193,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
distance,
distanceCos,
distanceSin,
distanceToTarget,
currentSinLat,
currentLonRad,
groundSpeed,
......@@ -205,11 +205,19 @@ var FixedWingDroneAPI = /** @class */ (function () {
verticalSpeed,
yawToDirection;
if (this._loiter_mode && Math.sqrt(
Math.pow(drone._targetCoordinates.x - drone.position.x, 2) +
Math.pow(drone._targetCoordinates.y - drone.position.y, 2)
) <= this._loiter_radius) {
newYaw = bearing - 90;
if (this._loiter_mode) {
distanceToTarget = Math.sqrt(
Math.pow(drone._targetCoordinates.x - drone.position.x, 2)
+ Math.pow(drone._targetCoordinates.y - drone.position.y, 2)
);
if (Math.abs(distanceToTarget - this._loiter_radius) <= 1) {
newYaw = bearing - 90;
} else if (distanceToTarget < this._loiter_radius) {
newYaw = bearing - 135;
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
} else {
newYaw = this._getNewYaw(drone, bearing, delta_time);
}
......@@ -414,16 +422,16 @@ var FixedWingDroneAPI = /** @class */ (function () {
distance = calculateDistance(drone_position, other_position, context);
if (distance <= VIEW_SCOPE) {
result.drones.push({
position: drone.getCurrentPosition(),
direction: drone.direction,
rotation: drone.rotation,
speed: drone.speed,
team: drone.team
position: other.getCurrentPosition(),
direction: other.direction,
rotation: other.rotation,
speed: other.speed,
team: other.team
});
}
}
});
context._map_dict.geo_obstacle_list.forEach(function (obstacle) {
context._map_dict.obstacle_list.forEach(function (obstacle) {
distance = calculateDistance(drone_position, obstacle.position, context);
if (distance <= VIEW_SCOPE) {
result.obstacles.push(obstacle);
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.35063.25322.10700</string> </value>
<value> <string>1011.5610.25987.56473</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1692366624.83</float>
<float>1695395371.67</float>
<string>UTC</string>
</tuple>
</state>
......
/*global BABYLON, RSVP, console, FixedWingDroneAPI, EnemyDroneAPI, document*/
/*global BABYLON, RSVP, console, FixedWingDroneAPI, EnemyDroneAPI, document, MapUtils*/
/*jslint nomen: true, indent: 2, maxlen: 80, todo: true,
unparam: true */
......@@ -135,6 +135,7 @@ var DroneManager = /** @class */ (function () {
configurable: true
});
DroneManager.prototype.internal_start = function () {
this._targetCoordinates = this.position;
this._API.internal_start(this);
this._canPlay = true;
this._canCommunicate = true;
......@@ -175,14 +176,15 @@ var DroneManager = /** @class */ (function () {
return;
};
DroneManager.prototype.internal_update = function (delta_time) {
var context = this;
var context = this, milliseconds;
if (this._controlMesh) {
context._API.internal_update(context, delta_time);
if (context._canUpdate) {
context._canUpdate = false;
return new RSVP.Queue()
.push(function () {
return context.onUpdate(context._API._gameManager._game_duration);
milliseconds = Math.floor(context._API._gameManager._game_duration);
return context.onUpdate(milliseconds);
})
.push(function () {
context._canUpdate = true;
......@@ -288,6 +290,9 @@ var DroneManager = /** @class */ (function () {
DroneManager.prototype.getInitialAltitude = function () {
return this._API.getInitialAltitude();
};
DroneManager.prototype.getCollisionSector = function () {
return this._API.getCollisionSector();
};
DroneManager.prototype.getAltitudeAbs = function () {
if (this._controlMesh) {
var altitude = this._controlMesh.position.y;
......@@ -403,20 +408,44 @@ var DroneManager = /** @class */ (function () {
/******************************************************************************/
/******************************** MAP MANAGER *********************************/
var MapManager = /** @class */ (function () {
"use strict";
var EPSILON = 9.9,
START_Z = 15,
R = 6371e3;
var SEED = '6!',
//default square map
MAP_HEIGHT = 700,
START_AMSL = 595,
MIN_LAT = 45.6419,
MAX_LAT = 45.65,
MIN_LON = 14.265,
MAX_LON = 14.2766,
MAP = {
"height": MAP_HEIGHT,
"start_AMSL": START_AMSL,
"map_seed": SEED,
"min_lat": MIN_LAT,
"max_lat": MAX_LAT,
"min_lon": MIN_LON,
"max_lon": MAX_LON
};
//** CONSTRUCTOR
function MapManager(scene) {
function MapManager(scene, map_param) {
var _this = this, max_sky, skybox, skyboxMat, largeGroundMat, flag_material,
largeGroundBottom, width, depth, terrain, max, flag_a, flag_b, mast, flag,
count = 0, new_obstacle;
this.setMapInfo(GAMEPARAMETERS.map, GAMEPARAMETERS.initialPosition);
count = 0, new_obstacle, obstacle, flag_info, enemy;
if (!map_param) {
// Use default map base parameters
map_param = MAP;
}
_this.mapUtils = new MapUtils(map_param);
_this.map_info = map_param;
Object.assign(_this.map_info, _this.mapUtils.map_info);
_this.map_info.initial_position = _this.mapUtils.convertToLocalCoordinates(
_this.map_info.initial_position.x,
_this.map_info.initial_position.y,
_this.map_info.initial_position.z);
max = _this.map_info.width;
if (_this.map_info.depth > max) {
max = _this.map_info.depth;
......@@ -459,9 +488,26 @@ var MapManager = /** @class */ (function () {
terrain.position = BABYLON.Vector3.Zero();
terrain.scaling = new BABYLON.Vector3(depth / 50000, depth / 50000,
width / 50000);
// Enemies
_this._enemy_list = [];
_this.map_info.enemy_list.forEach(function (geo_enemy) {
enemy = {};
Object.assign(enemy, geo_enemy);
enemy.position = _this.mapUtils.convertToLocalCoordinates(
geo_enemy.position.x,
geo_enemy.position.y,
geo_enemy.position.z);
_this._enemy_list.push(enemy);
});
// Obstacles
_this._obstacle_list = [];
_this.map_info.obstacle_list.forEach(function (obstacle) {
_this.map_info.obstacle_list.forEach(function (geo_obstacle) {
obstacle = {};
Object.assign(obstacle, geo_obstacle);
obstacle.position = _this.mapUtils.convertToLocalCoordinates(
geo_obstacle.position.x,
geo_obstacle.position.y,
geo_obstacle.position.z);
switch (obstacle.type) {
case "box":
new_obstacle = BABYLON.MeshBuilder.CreateBox("obs_" + count,
......@@ -513,7 +559,13 @@ var MapManager = /** @class */ (function () {
'y': 1,
'z': 6
};
_this.map_info.flag_list.forEach(function (flag_info, index) {
_this.map_info.flag_list.forEach(function (geo_flag, index) {
flag_info = {};
Object.assign(flag_info, geo_flag);
flag_info.position = _this.mapUtils.convertToLocalCoordinates(
geo_flag.position.x,
geo_flag.position.y,
geo_flag.position.z);
flag_material = new BABYLON.StandardMaterial("flag_mat_" + index, scene);
flag_material.alpha = 1;
flag_material.diffuseColor = BABYLON.Color3.Green();
......@@ -523,7 +575,7 @@ var MapManager = /** @class */ (function () {
flag_a.material = flag_material;
flag_a.position = new BABYLON.Vector3(
flag_info.position.x + 1,
FLAG_SIZE.z + 1, //swap
flag_info.position.z + FLAG_SIZE.z + 1, //swap
flag_info.position.y - 1
);
flag_a.rotation = new BABYLON.Vector3(0, 1, 0);
......@@ -533,7 +585,7 @@ var MapManager = /** @class */ (function () {
flag_b.material = flag_material;
flag_b.position = new BABYLON.Vector3(
flag_info.position.x - 1,
FLAG_SIZE.z + 1, //swap
flag_info.position.z + FLAG_SIZE.z + 1, //swap
flag_info.position.y + 1
);
flag_b.rotation = new BABYLON.Vector3(0, 4, 0);
......@@ -541,7 +593,7 @@ var MapManager = /** @class */ (function () {
{ 'size': 1 }, scene);
mast.position = new BABYLON.Vector3(
flag_info.position.x,
FLAG_SIZE.z / 2, //swap
flag_info.position.z + FLAG_SIZE.z / 2, //swap
flag_info.position.y
);
mast.scaling = new BABYLON.Vector3(
......@@ -551,117 +603,32 @@ var MapManager = /** @class */ (function () {
mast.material = flag_material;
flag = BABYLON.Mesh.MergeMeshes([flag_a, flag_b, mast]);
flag.id = index;
//flag.weight = _this.map_info.flag_weight;
flag.location = flag_info.position;
flag.drone_collider_list = [];
flag.weight = flag_info.weight;
flag.score = flag_info.score;
flag.id = index;
_this._flag_list.push(flag);
});
}
MapManager.prototype.setMapInfo = function (map_dict, initial_position) {
var max_width = this.latLonDistance([map_dict.min_lat, map_dict.min_lon],
[map_dict.min_lat, map_dict.max_lon]),
max_height = this.latLonDistance([map_dict.min_lat, map_dict.min_lon],
[map_dict.max_lat, map_dict.min_lon]),
map_size = Math.ceil(Math.max(max_width, max_height)),
starting_point = map_size / 2 * -0.75;
this.map_info = {
"depth": map_size,
"height": map_dict.height,
"width": map_size,
"map_size": map_size,
"start_AMSL": map_dict.start_AMSL,
"flag_list": map_dict.flag_list,
"geo_flag_list": [],
"flag_distance_epsilon": map_dict.flag_distance_epsilon || EPSILON,
"obstacle_list": map_dict.obstacle_list,
"geo_obstacle_list": [],
"initial_position": {
"x": 0,
"y": starting_point,
"z": START_Z
}
};
this.map_info.min_x = this.longitudToX(map_dict.min_lon);
this.map_info.min_y = this.latitudeToY(map_dict.min_lat);
this.map_info.max_x = this.longitudToX(map_dict.max_lon);
this.map_info.max_y = this.latitudeToY(map_dict.max_lat);
var map = this;
map_dict.flag_list.forEach(function (flag_info, index) {
map.map_info.geo_flag_list.push(map.convertToGeoCoordinates(
flag_info.position.x,
flag_info.position.y,
flag_info.position.z
));
});
map_dict.obstacle_list.forEach(function (obstacle_info, index) {
var geo_obstacle = {};
Object.assign(geo_obstacle, obstacle_info);
geo_obstacle.position = map.convertToGeoCoordinates(
obstacle_info.position.x,
obstacle_info.position.y,
obstacle_info.position.z
);
map.map_info.geo_obstacle_list.push(geo_obstacle);
});
};
MapManager.prototype.getMapInfo = function () {
return this.map_info;
};
MapManager.prototype.latLonDistance = function (c1, c2) {
return this.mapUtils.latLonDistance(c1, c2);
};
MapManager.prototype.longitudToX = function (lon) {
return (this.map_info.map_size / 360.0) * (180 + lon);
return this.mapUtils.longitudToX(lon);
};
MapManager.prototype.latitudeToY = function (lat) {
return (this.map_info.map_size / 180.0) * (90 - lat);
};
//TODO refactor latLonOffset, should be the reverse of lat-lon distance
//then map_size can be used as parameter (get max lat-lon from map_size)
/*MapManager.prototype.latLonOffset = function (lat, lon, offset_in_mt) {
var R = 6371e3, //Earth radius
lat_offset = offset_in_mt / R,
lon_offset = offset_in_mt / (R * Math.cos(Math.PI * lat / 180));
return [lat + lat_offset * 180 / Math.PI,
lon + lon_offset * 180 / Math.PI];
};*/
MapManager.prototype.latLonDistance = function (c1, c2) {
var q1 = c1[0] * Math.PI / 180,
q2 = c2[0] * Math.PI / 180,
dq = (c2[0] - c1[0]) * Math.PI / 180,
dl = (c2[1] - c1[1]) * Math.PI / 180,
a = Math.sin(dq / 2) * Math.sin(dq / 2) +
Math.cos(q1) * Math.cos(q2) *
Math.sin(dl / 2) * Math.sin(dl / 2),
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
return this.mapUtils.latitudeToY(lat);
};
MapManager.prototype.convertToLocalCoordinates =
function (latitude, longitude, altitude) {
var map_info = this.map_info,
x = this.longitudToX(longitude),
y = this.latitudeToY(latitude);
return {
x: ((x - map_info.min_x) / (map_info.max_x - map_info.min_x)) *
1000 - map_info.width / 2,
y: ((y - map_info.min_y) / (map_info.max_y - map_info.min_y)) *
1000 - map_info.depth / 2,
z: altitude
};
return this.mapUtils.convertToLocalCoordinates(
latitude, longitude, altitude);
};
MapManager.prototype.convertToGeoCoordinates = function (x, y, z) {
var lon = x + this.map_info.width / 2,
lat = y + this.map_info.depth / 2;
lon = lon / 1000;
lon = lon * (this.map_info.max_x - this.map_info.min_x) +
this.map_info.min_x;
lon = lon / (this.map_info.map_size / 360.0) - 180;
lat = lat / 1000;
lat = lat * (this.map_info.max_y - this.map_info.min_y) +
this.map_info.min_y;
lat = 90 - lat / (this.map_info.map_size / 180.0);
return {
x: lat,
y: lon,
z: z
};
return this.mapUtils.convertToGeoCoordinates(x, y, z);
};
return MapManager;
}());
......@@ -701,8 +668,7 @@ var GameManager = /** @class */ (function () {
header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)",
"AMSL (m)", "rel altitude (m)", "yaw (°)",
"ground speed (m/s)", "climb rate (m/s)"];
drone_count = GAMEPARAMETERS.map.drones.user.length +
GAMEPARAMETERS.map.drones.enemy.length;
drone_count = GAMEPARAMETERS.drone.list.length;
for (drone = 0; drone < drone_count; drone += 1) {
this._flight_log[drone] = [];
this._flight_log[drone].push(header_list);
......@@ -801,7 +767,9 @@ var GameManager = /** @class */ (function () {
};
GameManager.prototype.logError = function (drone, error) {
this._flight_log[drone._id].push(error.stack);
if (drone._id < this._flight_log.length) { // don't log enemies
this._flight_log[drone._id].push(error.stack);
}
};
GameManager.prototype._checkDroneOut = function (drone) {
......@@ -854,45 +822,48 @@ var GameManager = /** @class */ (function () {
//there is not a proper collision
if (distance(drone.position, flag.location) <=
this._mapManager.getMapInfo().flag_distance_epsilon) {
if (!flag.drone_collider_list.includes(drone.id)) {
//TODO notify the drone somehow? Or the AI script is in charge?
//console.log("flag " + flag.id + " hit by drone " + drone.id);
drone._internal_crash(new Error('Drone ' + drone.id +
' touched a flag.'));
if (flag.drone_collider_list.length === 0) {
drone.score++;
flag.drone_collider_list.push(drone.id);
}
drone._internal_crash(new Error('Drone ' + drone.id +
' touched flag ' + flag.id));
if (flag.weight > 0) {
flag.weight -= 1;
drone.score += flag.score; // move score to a global place? GM, MM?
}
}
}
};
GameManager.prototype._checkCollision = function (drone, other) {
if (drone.colliderMesh && other.colliderMesh &&
drone.colliderMesh.intersectsMesh(other.colliderMesh, false)) {
var angle = Math.acos(BABYLON.Vector3.Dot(drone.worldDirection,
other.worldDirection) /
(drone.worldDirection.length() *
other.worldDirection.length()));
//TODO is this parameter set? keep it or make 2 drones die when intersect?
if (angle < GAMEPARAMETERS.drone.collisionSector) {
if (drone.speed > other.speed) {
other._internal_crash(new Error('Drone ' + drone.id +
' bump drone ' + other.id + '.'));
}
else {
drone._internal_crash(new Error('Drone ' + other.id +
' bumped drone ' + drone.id + '.'));
}
if (drone.team == TEAM_ENEMY && other.team == TEAM_ENEMY) return;
function distance(a, b) {
return Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2) +
Math.pow((a.z - b.z), 2));
}
if (drone.team != other.team) {
var enemy, prey;
if (drone.team == TEAM_ENEMY) {
enemy = drone;
prey = other;
} else if (other.team == TEAM_ENEMY) {
enemy = other;
prey = drone;
}
else {
drone._internal_crash(new Error('Drone ' + drone.id +
' touched drone ' + other.id + '.'));
other._internal_crash(new Error('Drone ' + drone.id +
' touched drone ' + other.id + '.'));
if (drone.position && other.position) {
if (distance(drone.position, other.position) <
enemy.getCollisionSector()) {
drone._internal_crash(new Error('enemy drone ' + enemy.id +
' bumped drone ' + prey.id + '.'));
other._internal_crash(new Error('enemy drone ' + enemy.id +
' bumped drone ' + prey.id + '.'));
}
}
}
if (drone.colliderMesh && other.colliderMesh &&
drone.colliderMesh.intersectsMesh(other.colliderMesh, false)) {
drone._internal_crash(new Error('drone ' + drone.id +
' touched drone ' + other.id + '.'));
other._internal_crash(new Error('drone ' + drone.id +
' touched drone ' + other.id + '.'));
}
};
GameManager.prototype._update = function (delta_time, fullscreen) {
......@@ -968,11 +939,11 @@ var GameManager = /** @class */ (function () {
_this._result_message += "ALL DRONES DOWN!";
return _this._finish();
}
if (_this._allFlagsCaptured()) {
/*if (_this._allFlagsCaptured()) {
console.log("ALL FLAGS CAPTURED");
_this._result_message += "ALL FLAGS CAPTURED!";
return _this._finish();
}
}*/
});
};
......@@ -1061,24 +1032,10 @@ var GameManager = /** @class */ (function () {
return finish;
};
GameManager.prototype._allFlagsCaptured = function () {
var finish = true;
this._mapManager._flag_list.forEach(function (flag) {
//do not use flag weight for now, just 1 hit is enough
if (flag.drone_collider_list.length === 0) {
//if (flag.drone_collider_list.length < flag.weight) {
finish = false;
}
});
return finish;
};
GameManager.prototype._calculateUserScore = function () {
var score = 0;
this._droneList_user.forEach(function (drone) {
//if (drone.can_play) {
score += drone.score;
//}
});
return score;
};
......@@ -1135,13 +1092,15 @@ var GameManager = /** @class */ (function () {
this._scene
);
hemi_south.intensity = 0.75;
cam_radius = (GAMEPARAMETERS.map.map_size * 1.10 < 6000) ?
GAMEPARAMETERS.map.map_size * 1.10 : 6000; //skybox scene limit
//HARDCODE camera to a hardcoded map_size
var map_size = 900; //GAMEPARAMETERS.map.map_size
//skybox scene limit
cam_radius = (map_size * 1.10 < 6000) ? map_size * 1.10 : 6000;
camera = new BABYLON.ArcRotateCamera("camera", 0, 1.25, cam_radius,
BABYLON.Vector3.Zero(), this._scene);
camera.wheelPrecision = 10;
//zoom out limit
camera.upperRadiusLimit = GAMEPARAMETERS.map.map_size * 10;
camera.upperRadiusLimit = map_size * 10;
//scene.activeCamera.upperRadiusLimit = max * 4;
//changed for event handling
//camera.attachControl(this._scene.getEngine().getRenderingCanvas()); //orig
......@@ -1161,10 +1120,10 @@ var GameManager = /** @class */ (function () {
ctx._map_swapped = true;
}
// Init the map
_this._mapManager = new MapManager(ctx._scene);
_this._mapManager = new MapManager(ctx._scene, GAMEPARAMETERS.map);
ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position,
GAMEPARAMETERS.map.drones.user, TEAM_USER, ctx);
ctx._spawnDrones(null, GAMEPARAMETERS.map.drones.enemy, TEAM_ENEMY, ctx);
GAMEPARAMETERS.drone.list, TEAM_USER, ctx);
ctx._spawnDrones(null, _this._mapManager._enemy_list, TEAM_ENEMY, ctx);
// Hide the drone prefab
DroneManager.Prefab.isVisible = false;
//Hack to make advanced texture work
......@@ -1246,9 +1205,7 @@ var GameManager = /** @class */ (function () {
drone._tick = 0;
promise_list.push(drone.internal_start());
});
start_msg = {
'flag_positions': _this._mapManager.getMapInfo().geo_flag_list
};
start_msg = GAMEPARAMETERS.operator_init_msg;
promise_list.push(_this._droneList_user[0].sendMsg(start_msg));
_this._droneList_enemy.forEach(function (drone) {
drone._tick = 0;
......@@ -1259,6 +1216,8 @@ var GameManager = /** @class */ (function () {
.push(function () {
_this._canUpdate = true;
return _this.finish_deferred.promise;
}, function (error) {
throw new Error('Error on drone initialization msg -' + error.message);
});
};
......@@ -1321,15 +1280,14 @@ var GameManager = /** @class */ (function () {
return false;
}
function spawnDrone(x, y, z, index, drone_info, api, team) {
var default_drone_AI = api.getDroneAI(), code, base, code_eval, trim;
var default_drone_AI = api.getDroneAI(), code, code_eval;
if (default_drone_AI) {
code = default_drone_AI;
} else {
code = drone_info.script_content;
}
trim = code.trim();
if (!trim) {
code = "me.onStart = function () { forcedErrorEmptyScript };";
if (!code.includes("me.onStart")) {
code = "me.onStart = function () { me.exit(); };";
}
code_eval = "let drone = new DroneManager(ctx._scene, " +
index + ', api, team);' +
......@@ -1349,17 +1307,18 @@ var GameManager = /** @class */ (function () {
if (x !== null && y !== null && z !== null) {
code_eval += "me.setStartingPosition(" + x + ", " + y + ", " + z + ");";
}
base = code_eval;
//base = code_eval;
code_eval += code + "}; droneMe(Date, drone, Math, {});";
base += "};ctx._droneList_" + team + ".push(drone)";
//base += "};ctx._droneList_" + team + ".push(drone)";
code_eval += "ctx._droneList_" + team + ".push(drone)";
/*jslint evil: true*/
try {
eval(code_eval);
/*jslint evil: false*/
/*try {
eval(code_eval);
} catch (error) {
eval(base);
}
/*jslint evil: false*/
}*/
}
function randomSpherePoint(x0, y0, z0, rx0, ry0, rz0) {
var u = Math.random(), v = Math.random(),
......@@ -1388,7 +1347,7 @@ var GameManager = /** @class */ (function () {
position_list.push(position);
var id_offset = 0;
if (team == TEAM_ENEMY) {
id_offset = GAMEPARAMETERS.map.drones.user.length;
id_offset = GAMEPARAMETERS.drone.list.length;
}
api = new this.APIs_dict[drone_list[i].type](
this,
......@@ -1429,12 +1388,6 @@ var runGame, updateGame;
}
};
/*// Resize canvas on window resize
window.addEventListener('resize', function () {
game_manager_instance._engine.resize();
});*/
}(this));
/******************************************************************************/
\ No newline at end of file
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.23697.26501.43008</string> </value>
<value> <string>1011.18882.27011.1501</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1691684378.73</float>
<float>1695327797.6</float>
<string>UTC</string>
</tuple>
</state>
......
/******************************* MAP UTILS ************************************/
var MapUtils = /** @class */ (function () {
"use strict";
var FLAG_EPSILON = 15, R = 6371e3;
//** CONSTRUCTOR
function MapUtils(map_param) {
var _this = this, max_width = _this.latLonDistance(
[map_param.min_lat, map_param.min_lon],
[map_param.min_lat, map_param.max_lon]),
max_depth = _this.latLonDistance(
[map_param.min_lat, map_param.min_lon],
[map_param.max_lat, map_param.min_lon]),
map_size = Math.ceil(Math.max(max_width, max_depth));
_this.map_param = {};
_this.map_param.height = map_param.height;
_this.map_param.start_AMSL = map_param.start_AMSL;
_this.map_param.min_lat = map_param.min_lat;
_this.map_param.max_lat = map_param.max_lat;
_this.map_param.min_lon = map_param.min_lon;
_this.map_param.max_lon = map_param.max_lon;
_this.map_param.depth = map_size;
_this.map_param.width = map_size;
_this.map_param.map_size = map_size;
_this.map_info = {
"depth": _this.map_param.depth,
"width": _this.map_param.width,
"flag_distance_epsilon": map_param.flag_distance_epsilon || FLAG_EPSILON
};
_this.map_info.map_size = _this.map_param.map_size;
_this.map_info.height = _this.map_param.height;
_this.map_info.start_AMSL = _this.map_param.start_AMSL;
_this.map_info.min_x = _this.longitudToX(map_param.min_lon);
_this.map_info.min_y = _this.latitudeToY(map_param.min_lat);
_this.map_info.max_x = _this.longitudToX(map_param.max_lon);
_this.map_info.max_y = _this.latitudeToY(map_param.max_lat);
}
MapUtils.prototype.latLonDistance = function (c1, c2) {
var q1 = c1[0] * Math.PI / 180,
q2 = c2[0] * Math.PI / 180,
dq = (c2[0] - c1[0]) * Math.PI / 180,
dl = (c2[1] - c1[1]) * Math.PI / 180,
a = Math.sin(dq / 2) * Math.sin(dq / 2) +
Math.cos(q1) * Math.cos(q2) *
Math.sin(dl / 2) * Math.sin(dl / 2),
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
};
MapUtils.prototype.longitudToX = function (lon) {
return (this.map_info.map_size / 360.0) * (180 + lon);
};
MapUtils.prototype.latitudeToY = function (lat) {
return (this.map_info.map_size / 180.0) * (90 - lat);
};
MapUtils.prototype.convertToLocalCoordinates =
function (latitude, longitude, altitude) {
var map_info = this.map_info,
x = this.longitudToX(longitude),
y = this.latitudeToY(latitude);
return {
x: ((x - map_info.min_x) / (map_info.max_x - map_info.min_x)) *
1000 - map_info.width / 2,
y: ((y - map_info.min_y) / (map_info.max_y - map_info.min_y)) *
1000 - map_info.depth / 2,
z: altitude
};
};
MapUtils.prototype.convertToGeoCoordinates = function (x, y, z) {
var lon = x + this.map_info.width / 2,
lat = y + this.map_info.depth / 2;
lon = lon / 1000;
lon = lon * (this.map_info.max_x - this.map_info.min_x) +
this.map_info.min_x;
lon = lon / (this.map_info.map_size / 360.0) - 180;
lat = lat / 1000;
lat = lat * (this.map_info.max_y - this.map_info.min_y) +
this.map_info.min_y;
lat = 90 - lat / (this.map_info.map_size / 180.0);
return {
x: lat,
y: lon,
z: z
};
};
/*
** Randomizes all map elements: starting point, enemies, flags, obstacles
*/
MapUtils.prototype.randomizeByBlockTemplates = function (seed) {
function normalize(x, min, max) {
return min + (max - min) * x / 100;
}
function fillTemplate(template, min_x, min_y, max_x, max_y) {
function fillFlagList(list, min_x, min_y, max_x, max_y) {
var i, el, result_list = [];
for (i = 0; i < list.length; i += 1) {
el = {"position":
{"x": 0, "y": 0, "z": 0},
"score": list[i].score,
"weight": list[i].weight};
el.position.x = normalize(list[i].position.x, min_x, max_x);
el.position.y = normalize(list[i].position.y, min_y, max_y);
//TODO normalize z to map height?
el.position.z = list[i].position.z;
result_list.push(el);
}
return result_list;
}
function fillEnemyList(list, min_x, min_y, max_x, max_y) {
var i, el, result_list = [];
for (i = 0; i < list.length; i += 1) {
el = {"position":
{"x": 0, "y": 0, "z": 0},
"type": list[i].type};
el.position.x = normalize(list[i].position.x, min_x, max_x);
el.position.y = normalize(list[i].position.y, min_y, max_y);
//TODO normalize z to map height?
el.position.z = list[i].position.z;
result_list.push(el);
}
return result_list;
}
function fillObstacleList(list, min_x, min_y, max_x, max_y) {
var i, el, result_list = [];
for (i = 0; i < list.length; i += 1) {
el = {"position":
{"x": 0, "y": 0, "z": 0},
"scale":
{"x": 0, "y": 0, "z": 0},
"type": list[i].type};
if (list[i].rotation) {
el.rotation = {"x": list[i].rotation.x, "y": list[i].rotation.y,
"z": list[i].rotation.z};
}
el.position.x = normalize(list[i].position.x, min_x, max_x);
el.position.y = normalize(list[i].position.y, min_y, max_y);
//TODO normalize z to map height?
el.position.z = list[i].position.z;
el.scale.x = normalize(list[i].scale.x, 0, Math.abs(max_x - min_x));
el.scale.y = normalize(list[i].scale.y, 0, Math.abs(max_x - min_x));
//TODO normalize z to map height?
el.scale.z = list[i].scale.z;
result_list.push(el);
}
return result_list;
}
return {
"flag_list": fillFlagList(template.flag_list, min_x, min_y, max_x, max_y),
"obstacle_list": fillObstacleList(template.obstacle_list, min_x, min_y, max_x, max_y),
"enemy_list": fillEnemyList(template.enemy_list, min_x, min_y, max_x, max_y)
};
}
// 4x4 grid
var GRID = 4, i, j, map_size = this.map_info.map_size, initial_block,
x1, y1, x2, y2, block_result, index, block_size = map_size / GRID,
result_map,
BLOCK_TEMPLATE_LIST = [{
"flag_list": [{"position":
{"x": 50, "y": 50, "z": 10},
"score": 1, "weight": 1}],
"obstacle_list": [{"type": "box",
"position": {"x": 50, "y": 70, "z": 20},
"scale": {"x": 80, "y": 4, "z": 40},
"rotation": {"x": 0, "y": 0, "z": 0}}],
"enemy_list": [{"type": "EnemyDroneAPI",
"position": {"x": 50, "y": 30, "z": 10}}
]
}, {
"flag_list": [],
"obstacle_list": [{"type": "box",
"position": {"x": 20, "y": 65, "z": 20},
"scale": {"x": 4, "y": 70, "z": 40},
"rotation": {"x": 0, "y": 0, "z": 0}},
{"type": "box",
"position": {"x": 50, "y": 35, "z": 20},
"scale": {"x": 4, "y": 70, "z": 40},
"rotation": {"x": 0, "y": 0, "z": 0}},
{"type": "box",
"position": {"x": 80, "y": 65, "z": 20},
"scale": {"x": 4, "y": 70, "z": 40},
"rotation": {"x": 0, "y": 0, "z": 0}}],
"enemy_list": []
}, {
"flag_list": [],
"obstacle_list": [{"type": "mountain",
"position": {"x": 50, "y": 50, "z": 200},
"scale": {"x": 80, "y": 80,
"z": 400} //this.map_info.height?
}],
"enemy_list": []
}, {
"flag_list": [],
"obstacle_list": [],
"enemy_list": [{"type": "EnemyDroneAPI",
"position": {"x": 20, "y": 20, "z": 10}},
{"type": "EnemyDroneAPI",
"position": {"x": 20, "y": 80, "z": 10}},
{"type": "EnemyDroneAPI",
"position": {"x": 80, "y": 20, "z": 10}},
{"type": "EnemyDroneAPI",
"position": {"x": 80, "y": 80, "z": 10}}]
}, {
"flag_list": [{"position":
{"x": 50, "y": 50, "z": 10},
"score": 1, "weight": 1}],
"obstacle_list": [],
"enemy_list": []
}, {
"flag_list": [{"position":
{"x": 50, "y": 50, "z": 10},
"score": 1, "weight": 1}],
"obstacle_list": [],
"enemy_list": [{"type": "EnemyDroneAPI",
"position": {"x": 50, "y": 20, "z": 10}},
{"type": "EnemyDroneAPI",
"position": {"x": 50, "y": 80, "z": 10}}]
}, {
"flag_list": [{"position":
{"x": 50, "y": 50, "z": 10},
"score": 1, "weight": 1}],
"obstacle_list": [{"type": "box",
"position": {"x": 50, "y": 10, "z": 25},
"scale": {"x": 80, "y": 2, "z": 50},
"rotation": {"x": 0, "y": 0, "z": 0}},
{"type": "box",
"position": {"x": 10, "y": 50, "z": 25},
"scale": {"x": 2, "y": 80, "z": 50},
"rotation": {"x": 0, "y": 0, "z": 0}},
{"type": "box",
"position": {"x": 50, "y": 90, "z": 25},
"scale": {"x": 80, "y": 2, "z": 50},
"rotation": {"x": 0, "y": 0, "z": 0}},
{"type": "box",
"position": {"x": 90, "y": 50, "z": 25},
"scale": {"x": 2, "y": 80, "z": 50},
"rotation": {"x": 0, "y": 0, "z": 0}}],
"enemy_list": []
}, {
"flag_list": [],
"obstacle_list": [],
"enemy_list": []
}];
function getInitialBlock(GRID) {
var x, y;
do {
x = Math.floor(seed.quick() * GRID);
y = Math.floor(seed.quick() * GRID);
//ensure intial block is in the edge of map
} while (x !== 0 && x !== GRID-1 && y !== 0 && y !== GRID-1);
return {x: x, y: y};
}
initial_block = getInitialBlock(GRID);
function checkConditions(json_map, GRID) {
if (!json_map) return false;
// set ~20% of the blocks with flags
if (json_map.flag_list.length !== Math.round(GRID * GRID * 0.2)) return false;
// limit n_mountains
if (json_map.obstacle_list.length > 3) {
var i, n_mountains = 0;
for (i = 0; i < json_map.obstacle_list.length; i += 1) {
if (json_map.obstacle_list[i].type === "mountain") {
n_mountains += 1;
if (n_mountains > 3) {
return false;
}
json_map.obstacle_list[i].type = "box";
}
}
}
var f;
// at least one flag in the oposite side of drones initial position
for (f = 0; f < json_map.flag_list.length; f += 1) {
if ((json_map.flag_list[f].position.x * json_map.initial_position.x) < 0 ||
(json_map.flag_list[f].position.y * json_map.initial_position.y) < 0) {
return true;
}
}
return false;
}
do {
result_map = {
"flag_list": [],
"obstacle_list": [],
"enemy_list": []
};
for (i = 0; i < GRID; i += 1) {
for (j = 0; j < GRID; j += 1) {
index = Math.floor(seed.quick() * BLOCK_TEMPLATE_LIST.length);
x1 = block_size * i - map_size / 2;
y1 = block_size * j - map_size / 2;
x2 = block_size * i + block_size - map_size / 2;
y2 = block_size * j + block_size - map_size / 2;
if (initial_block.x === i && initial_block.y === j) {
result_map.initial_position = {x: normalize(50, x1, x2),
y: normalize(50, y1, y2),
z: 15 };
} else {
block_result = fillTemplate(BLOCK_TEMPLATE_LIST[index], x1, y1, x2, y2);
result_map.flag_list = result_map.flag_list.concat(block_result.flag_list);
result_map.obstacle_list = result_map.obstacle_list.concat(block_result.obstacle_list);
result_map.enemy_list = result_map.enemy_list.concat(block_result.enemy_list);
}
}
}
} while (!checkConditions(result_map, GRID));
return result_map;
};
/*
** Generates a random map json
*/
MapUtils.prototype.randomize = function (seed) {
//TODO randomize start_ASML, map height, depth and width?
var _this = this, flag_list, obstacle_list, enemy_list,
geo_flag_info, geo_obstacle, geo_enemy, coordinates,
random_seed = new Math.seedrandom(seed),
randomized_map = _this.randomizeByBlockTemplates(random_seed);
obstacle_list = randomized_map.obstacle_list;
enemy_list = randomized_map.enemy_list;
flag_list = randomized_map.flag_list;
_this.map_param.obstacle_list = [];
_this.map_param.enemy_list = [];
_this.map_param.flag_list = [];
//convert all map elements positions to geo coordinates
_this.map_info.initial_position = _this.convertToGeoCoordinates(
randomized_map.initial_position.x,
randomized_map.initial_position.y,
randomized_map.initial_position.z
);
Object.assign(_this.map_info, _this.map_param);
flag_list.forEach(function (flag_info, index) {
coordinates = _this.convertToGeoCoordinates(
flag_info.position.x,
flag_info.position.y,
flag_info.position.z
);
geo_flag_info = {
'id': flag_info.id,
'score': flag_info.score,
'weight': flag_info.weight,
'position': {
'x': coordinates.x,
'y': coordinates.y,
'z': coordinates.z
}
};
_this.map_info.flag_list.push(geo_flag_info);
});
obstacle_list.forEach(function (obstacle_info, index) {
geo_obstacle = {};
Object.assign(geo_obstacle, obstacle_info);
geo_obstacle.position = _this.convertToGeoCoordinates(
obstacle_info.position.x,
obstacle_info.position.y,
obstacle_info.position.z
);
_this.map_info.obstacle_list.push(geo_obstacle);
});
enemy_list.forEach(function (enemy_info, index) {
geo_enemy = {};
Object.assign(geo_enemy, enemy_info);
geo_enemy.position = _this.convertToGeoCoordinates(
enemy_info.position.x,
enemy_info.position.y,
enemy_info.position.z
);
_this.map_info.enemy_list.push(geo_enemy);
});
//return only base parameters
randomized_map.min_lat = _this.map_info.min_lat;
randomized_map.max_lat = _this.map_info.max_lat;
randomized_map.min_lon = _this.map_info.min_lon;
randomized_map.max_lon = _this.map_info.max_lon;
randomized_map.height = _this.map_info.height;
randomized_map.start_AMSL = _this.map_info.start_AMSL;
randomized_map.flag_list = _this.map_info.flag_list;
randomized_map.obstacle_list = _this.map_info.obstacle_list;
randomized_map.enemy_list = _this.map_info.enemy_list;
randomized_map.initial_position = _this.map_info.initial_position;
return randomized_map;
};
return MapUtils;
}());
/******************************************************************************/
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_map_utils.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>drone_capture_flag_map_utils_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Capture Map Utils</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1694185956.38</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1011.18883.7641.45704</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1695327563.61</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>empty</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1694185881.0</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
......@@ -29,6 +29,10 @@
margin: 0;
}
.documentation div {
vertical-align: middle !important;
}
.documentation .line {
width: 100%;
height: 1px;
......@@ -54,7 +58,6 @@
.item-name span:last-of-type {
font-style: italic; }
.line {
width: 100%;
height: 1px;
......
......@@ -242,7 +242,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.15231.63877.58538</string> </value>
<value> <string>1011.7107.64372.12151</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -262,7 +262,7 @@
</tuple>
<state>
<tuple>
<float>1691176394.73</float>
<float>1694621148.77</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -10,6 +10,141 @@
<div class="documentation">
<h1>Game specifications</h1>
<!-- Map JSON -->
<h3>Map parameter dictionary (JSON)</h3>
<div>
<h5 class="item-param-1">Map dictionary entries</h5>
<p class="item-descr"></p>
</div>
<div>
<h5 class="item-param-1">Key</h5>
<h5 class="item-param-2">Description</h5>
</div>
<div>
<p class="item-param-1">min_lat, max_lat, min_lon, max_lon: Float</p>
<p class="item-param-2">Min and max latitude and longitude coordinates of the map</p>
</div>
<div>
<p class="item-param-1">map_size: Integer</p>
<p class="item-param-2">Map size in meters (calculated from coordinates)</p>
</div>
<div>
<p class="item-param-1">width, depth: Integer</p>
<p class="item-param-2">Map width and depth in meters (calculated from coordinates)</p>
</div>
<div>
<p class="item-param-1">height: Integer</p>
<p class="item-param-2">Map height in meters</p>
</div>
<div>
<p class="item-param-1">start_AMSL: Integer</p>
<p class="item-param-2">Map height above mean sea level in meters</p>
</div>
<div>
<p class="item-param-1">initial_position: dictionary</p>
<p class="item-param-2">Drones starting point coordinates</p>
<p class="item-param-2">
{<br>
&nbsp;&nbsp;x: number, //latitude (in degrees)<br>
&nbsp;&nbsp;y: number, //longitude (in degrees)<br>
&nbsp;&nbsp;z: number //altitude (in meters)<br>
}<br>
</p>
</div>
<div>
<p class="item-param-1">flag_list: list</p>
<p class="item-param-2">List of flags, each element:</p>
<p class="item-param-2">
{<br>
&nbsp;&nbsp;position {x,y,z}:<br>&nbsp;&nbsp;latitude, longitude and altitude<br>
&nbsp;&nbsp;score: number<br>
&nbsp;&nbsp;weight: number<br>
}<br>
</p>
</div>
<div>
<p class="item-param-1">obstacle_list: list</p>
<p class="item-param-2">List of obstacles, each element:</p>
<p class="item-param-2">
{<br>
&nbsp;&nbsp;position {x,y,z}:<br>&nbsp;&nbsp;latitude, longitude and altitude<br>
&nbsp;&nbsp;type: [box, cilinder, sphere]<br>
&nbsp;&nbsp;scale: {x,y,z}<br>
&nbsp;&nbsp;rotation: {x,y,z}<br>
}<br>
</p>
</div>
<div>
<p class="item-param-1">enemy_list: list</p>
<p class="item-param-2">List of enemies, each element:</p>
<p class="item-param-2">
{<br>
&nbsp;&nbsp;position {x,y,z}:<br>&nbsp;&nbsp;latitude, longitude and altitude<br>
&nbsp;&nbsp;type: drone-type<br>
&nbsp;&nbsp;id: number<br>
}<br>
</p>
</div>
<div class="line"></div>
<h3>Operator script</h3>
<!-- Operator script -->
<h4 class="item-name" id="scoring"><span>Operator</span></h4>
<p class="item-descr">The purpose of this script is to set the initial message that all the drones will get at the beginning of the game.</p>
<p class="item-descr">The map parameter dictionary can be accessed to get any relevant info.</p>
<p class="item-descr">An API is provided through the object <em>operator</em> that allows to get the map json and set the intial message.</p>
<h4 class="item-name" id="scoring"><span>API</span></h4>
<div>
<p class="item-param-1">getMapJSON(): dictionary</p>
<p class="item-param-2">Get the map JSON dictionary</p>
</div>
<div>
<p class="item-param-1">sendMsg(msg): void</p>
<p class="item-param-2">Set the initial msg all the drones will get at the start.</p>
<p class="item-param-2">Message parameter msg must be a dictionary</p>
</div>
<h5 class="item-param-1">Example</h5>
<p class="item-example">var map = operator.getMapJSON();<br>
operator.sendMsg({flag_positions: map.flag_list});
</p>
<div class="line"></div>
<h3>Game scoring</h3>
<!-- Scoring -->
<h4 class="item-name" id="scoring"><span>Score</span></h4>
<p class="item-descr">Every flag has a score, every drone hit on the flag will give it that score value.</p>
<p class="item-descr">The number of hits on a flag is determined by its weight.</p>
<p class="item-descr">Once the number of hits is equal to the flag weight, no more score will be given on following hits.</p>
<p class="item-descr">Total score is the sum of all drones score when the game finishes.</p>
<h5 class="item-param-1">Example</h5>
<p class="item-example">A flag with score=3 and weight=2 will grant 3 score points on every drone hit, up to 2 hits.</p>
<div class="line"></div>
<h1>Fixed Wings Drone API</h1>
<h3>API functions</h3>
......@@ -442,7 +577,7 @@
<!-- id -->
<h4 class="item-name" id="id"><span>id</span><span>: number</span></h4>
<p class="item-descr">Drone unique numeric identifier: from 0 to 9.</p>
<p class="item-descr">Drone unique numeric identifier.</p>
<h5 class="item-param-1">Example</h5>
......
......@@ -244,7 +244,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.23624.18144.48810</string> </value>
<value> <string>1011.7129.2983.29201</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -264,7 +264,7 @@
</tuple>
<state>
<tuple>
<float>1691679891.23</float>
<float>1694622336.88</float>
<string>UTC</string>
</tuple>
</state>
......
div[data-gadget-url$="gadget_erp5_page_drone_capture_flag_script_page.html"] .item-label {
background-color: #F8F8F8;
padding: 8px;
margin: 8px 0;
font-size: 1.2em;
font-weight: bold;
}
div[data-gadget-url$="gadget_erp5_page_drone_capture_flag_script_page.html"] button {
color: #212529;
padding: 3pt;
border: 1px solid rgba(0, 0, 0, 0.14);
border-radius: 0.325em;
display: inline-block;
margin-right: 6pt;
}
div[data-gadget-url$="gadget_erp5_page_drone_capture_flag_script_page.html"] button:disabled,
div[data-gadget-url$="gadget_erp5_page_drone_capture_flag_script_page.html"] button[disabled] {
color: #999999;
}
div[data-gadget-url$="gadget_erp5_page_drone_capture_flag_script_page.html"] button:before {
padding-right: 0.2em;
}
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Style" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_script_page.css</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>ojs_drone_capture_flag_script_page_css</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Drone Capture Flag Script Page CSS</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1693841614.38</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.65016.4453.48725</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1694183879.39</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>empty</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1693841589.15</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<!DOCTYPE html>
<html>
<!--
data-i18n=Others
data-i18n=Tools
-->
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Drone Capture Flag Script Page</title>
<link rel="http://www.renderjs.org/rel/interface" href="interface_page.html">
<link rel="stylesheet" type="text/css" href="gadget_erp5_page_drone_capture_flag_script_page.css">
<!-- renderjs -->
<script src="rsvp.js" type="text/javascript"></script>
......@@ -18,24 +15,16 @@
<script src="jiodev.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script>
<script type="text/javascript" src="./libraries/seedrandom.min.js"></script>
<script src="gadget_erp5_page_drone_capture_map_utils.js" type="text/javascript"></script>
<script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script>
</head>
<body>
<form>
<div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view"
data-gadget-sandbox="public">
</div>
<input name="action_run" class="dialogconfirm" type="submit" value="Run" style="margin-bottom: 20pt;margin-top: 20pt;">
<a data-i18n="Storages"></a> <!-- for zelenium test common macro -->
<div class="simulator_div"></div>
<div data-gadget-url="gadget_erp5_form.html"
data-gadget-scope="form_view_babylonjs"
data-gadget-sandbox="public">
</div>
</form>
<div class="captureflagpageheader"></div>
<div class="captureflagpagebody"></div>
</body>
</html>
\ No newline at end of file
......@@ -244,7 +244,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1008.22253.2281.60074</string> </value>
<value> <string>1010.65526.46361.27613</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -264,7 +264,7 @@
</tuple>
<state>
<tuple>
<float>1683820259.6</float>
<float>1694194019.23</float>
<string>UTC</string>
</tuple>
</state>
......
/*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, URLSearchParams, Blob*/
(function (window, rJS, domsugar, document, URLSearchParams, Blob) {
/*global window, rJS, domsugar, document, Blob, MapUtils, RSVP*/
/******************************* OPERATOR API ********************************/
var OperatorAPI = /** @class */ (function () {
"use strict";
//** CONSTRUCTOR
function OperatorAPI(json_map) {
this.message = "default init message";
this.json_map = json_map;
}
OperatorAPI.prototype.getMapJSON = function () {
return this.json_map;
};
OperatorAPI.prototype.sendMsg = function (msg) {
this.message = msg;
};
OperatorAPI.prototype.getDroneStartMessage = function () {
return this.message;
};
return OperatorAPI;
}());
(function (window, rJS, domsugar, document, Blob, MapUtils, RSVP) {
"use strict";
//Drone default values - TODO: get them from the drone API
var SIMULATION_SPEED = 10,
var SIMULATION_SPEED = 60,
SIMULATION_TIME = 270,
//HARDCODED map size: it is defined by min-max lat-lon distance
//this is done by the map manager (latLonDistance)
//but map_size is needed here for map randomization (location of objects)
//TODO refactor: or randomization is moved to map manager (seed as param)
//or randomization is done here but with geo-coordinates (not meters)
MAP_SIZE = 900,
//square map
min_lat = 45.6419,
max_lat = 45.65,
min_lon = 14.265,
max_lon = 14.2766,
map_height = 700,
start_AMSL = 595,
//default square map
MAP_HEIGHT = 700,
START_AMSL = 595,
MIN_LAT = 45.6419,
MAX_LAT = 45.65,
MIN_LON = 14.265,
MAX_LON = 14.2766,
//seed
//url_sp = new URLSearchParams(window.location.hash),
//url_seed = url_sp.get("seed"),
SEED = '123',//'6!',
MAP = {
"height": MAP_HEIGHT,
"start_AMSL": START_AMSL,
"min_lat": MIN_LAT,
"max_lat": MAX_LAT,
"min_lon": MIN_LON,
"max_lon": MAX_LON,
"flag_list": [{"position":
{"x": 45.6464947316632,
"y": 14.270747186236491,
"z": 10},
"score": 1,
"weight": 1}],
"obstacle_list": [{"type": "box",
"position": {"x": 45.6456815316444,
"y": 14.274667031215898,
"z": 15},
"scale": {"x": 132, "y": 56, "z": 10},
"rotation": {"x": 0, "y": 0, "z": 0}}],
"enemy_list": [{"type": "EnemyDroneAPI",
"position": {"x": 45.6455531,
"y": 14.270747186236491,
"z": 15}}],
"initial_position": {"x": 45.642813275, "y": 14.270231599999988, "z": 15}
},
DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6,
MAX_DECELERATION = 1,
......@@ -29,15 +75,16 @@
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
NUMBER_OF_DRONES = 10,
FLAG_WEIGHT = 5,
SEED = '6',
NUMBER_OF_DRONES = 5,
// Non-inputs parameters
EPSILON = "15",
DEFAULT_OPERATOR_SCRIPT = 'var map = operator.getMapJSON();\n' +
'operator.sendMsg({flag_positions: map.flag_list});\n',
DEFAULT_SCRIPT_CONTENT =
'var EPSILON = 15,\n' +
'var EPSILON = ' + EPSILON + ',\n' +
' DODGE_DISTANCE = 100;\n' +
'\n' +
'function distance(a, b) {\n' +
'function distance2D(a, b) {\n' +
' var R = 6371e3, // meters\n' +
' la1 = a.x * Math.PI / 180, // lat, lon in radians\n' +
' la2 = b.x * Math.PI / 180,\n' +
......@@ -49,6 +96,12 @@
' return 2 * R * Math.asin(Math.sqrt(h));\n' +
'}\n' +
'\n' +
'function distance(a, b) {\n' +
' return Math.sqrt(\n' +
' Math.pow(a.z - b.z, 2) + Math.pow(distance2D(a, b), 2)\n' +
' );\n' +
'}\n' +
'\n' +
'me.onStart = function () {\n' +
' me.direction_set = false;\n' +
' me.dodging = false;\n' +
......@@ -57,7 +110,7 @@
'\n' +
'me.onGetMsg = function (msg) {\n' +
' if (msg && msg.flag_positions) {\n' +
' me.flag_positions = msg.flag_positions\n' +
' me.flag_positions = msg.flag_positions;\n' +
' me.next_checkpoint = me.id % me.flag_positions.length;\n' +
' }\n' +
'};\n' +
......@@ -79,9 +132,9 @@
' if (!me.direction_set) {\n' +
' if (me.next_checkpoint < me.flag_positions.length) {\n' +
' me.setTargetCoordinates(\n' +
' me.flag_positions[me.next_checkpoint].x,\n' +
' me.flag_positions[me.next_checkpoint].y,\n' +
' me.flag_positions[me.next_checkpoint].z + me.id\n' +
' me.flag_positions[me.next_checkpoint].position.x,\n' +
' me.flag_positions[me.next_checkpoint].position.y,\n' +
' me.flag_positions[me.next_checkpoint].position.z + me.id\n' +
' );\n' +
//' console.log("[DEMO] Going to Checkpoint %d", me.next_checkpoint);\n' +
' }\n' +
......@@ -98,7 +151,7 @@
' me.current_position = me.getCurrentPosition();\n' +
' me.distance = distance(\n' +
' me.current_position,\n' +
' me.flag_positions[me.next_checkpoint]\n' +
' me.flag_positions[me.next_checkpoint].position\n' +
' );\n' +
' if (me.distance <= EPSILON) {\n' +
//' console.log("[DEMO] Reached Checkpoint %d", me.next_checkpoint);\n' +
......@@ -107,6 +160,12 @@
' }\n' +
' return;\n' +
' }\n' +
' if (me.next_checkpoint == me.flag_positions.length) {\n' +
' me.triggerParachute();\n' +
' }\n' +
' if (me.landed()) {\n' +
' me.exit();\n' +
' }\n' +
'};\n' +
'\n' +
'me.onDroneViewInfo = function (drone_view) {\n' +
......@@ -115,7 +174,7 @@
' me.dodging = drone_view.obstacles[0];\n' +
' me.direction_set = false;\n' +
' var random = Math.random() < 0.5, dodge_point = {};\n' +
' Object.assign(dodge_point, me.flag_positions[me.next_checkpoint]);\n' +
' Object.assign(dodge_point, me.flag_positions[me.next_checkpoint].position);\n' +
' if (random) {\n' +
' dodge_point.x = dodge_point.x * -1;\n' +
' } else {\n' +
......@@ -128,431 +187,616 @@
DRAW = true,
LOG = true,
LOG_TIME = 1662.7915426540285,
DRONE_LIST = [],
LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_map_utils.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js',
'gadget_erp5_page_drone_capture_flag_enemydrone.js'
];
],
DISPLAY_MAP_PARAMETER = 'display_map_parameter',
DISPLAY_RANDOMIZE = 'display_randomize',
DISPLAY_OPERATOR_PARAMETER = 'display_operator_parameter',
DISPLAY_DRONE_PARAMETER = 'display_drone_parameter',
DISPLAY_GAME_PARAMETER = 'display_game_parameter',
DISPLAY_PLAY = "display_play";
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
function renderGadgetHeader(gadget, loading) {
var element_list = [],
game_map_icon = 'ui-icon-map-marker',
game_randomize_icon = 'ui-icon-random',
game_operator_icon = 'ui-icon-rss',
game_drone_icon = 'ui-icon-paper-plane',
game_parameter_icon = 'ui-icon-gears',
game_play_icon = 'ui-icon-play';
.allowPublicAcquisition('notifySubmit', function () {
return this.triggerSubmit();
})
.declareMethod("triggerSubmit", function () {
return this.element.querySelector('input[type="submit"]').click();
})
if (loading) {
if (gadget.state.display_step === DISPLAY_MAP_PARAMETER) {
game_map_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_RANDOMIZE) {
game_randomize_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_OPERATOR_PARAMETER) {
game_operator_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_DRONE_PARAMETER) {
game_drone_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_GAME_PARAMETER) {
game_parameter_icon = 'ui-icon-spinner';
} else if (gadget.state.display_step === DISPLAY_PLAY) {
game_play_icon = 'ui-icon-spinner';
} else {
throw new Error("Can't render header state " +
gadget.state.display_step);
}
}
.onEvent('submit', function () {
var gadget = this;
return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) {
return form_gadget.getContent();
})
.push(function (input) {
gadget.runGame(input);
});
})
element_list.push(
domsugar('button', {
type: 'button',
text: "Map",
disabled: (gadget.state.display_step === DISPLAY_MAP_PARAMETER),
'class': 'display-map-parameter-btn ui-btn-icon-left ' + game_map_icon
}),
domsugar('button', {
type: 'button',
text: "Randomize",
disabled: (gadget.state.display_step === DISPLAY_RANDOMIZE),
'class': 'display-randomize-btn ui-btn-icon-left ' + game_randomize_icon
}),
domsugar('button', {
type: 'button',
text: "Parameters",
disabled: (gadget.state.display_step === DISPLAY_GAME_PARAMETER),
'class': 'display-game-parameter-btn ui-btn-icon-left ' + game_parameter_icon
}),
domsugar('button', {
type: 'button',
text: "Operator Script",
disabled: (gadget.state.display_step === DISPLAY_OPERATOR_PARAMETER),
'class': 'display-operator-script-btn ui-btn-icon-left ' + game_operator_icon
}),
domsugar('button', {
type: 'button',
text: "Drone Script",
disabled: (gadget.state.display_step === DISPLAY_DRONE_PARAMETER),
'class': 'display-drone-script-btn ui-btn-icon-left ' + game_drone_icon
}),
domsugar('button', {
type: 'button',
text: "Run",
// Always make this button clickable, so that user can run it twice
// disabled: (gadget.state.display_step === DISPLAY_PLAY),
'class': 'display-play-btn ui-btn-icon-left ' + game_play_icon
})
);
.declareMethod('render', function render() {
var gadget = this, url_sp = new URLSearchParams(window.location.hash),
url_seed = url_sp.get("seed");
return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) {
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_simulation_speed": {
"description": "",
"title": "Simulation Speed",
"default": SIMULATION_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "simulation_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_simulation_time": {
"description": "Duration of the simulation (in seconds)",
"title": "Simulation Time",
"default": SIMULATION_TIME,
"css_class": "",
"required": 1,
"editable": 1,
"key": "simulation_time",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_min_speed": {
"description": "",
"title": "Drone min speed",
"default": MIN_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_speed": {
"description": "",
"title": "Drone speed",
"default": DEFAULT_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_speed",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": MAX_SPEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": MAX_ACCELERATION,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_acceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": MAX_DECELERATION,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_deceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": MAX_ROLL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_roll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_pitch": {
"description": "",
"title": "Drone min pitch",
"default": MIN_PITCH,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_pitch": {
"description": "",
"title": "Drone max pitch",
"default": MAX_PITCH,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_sink_rate": {
"description": "",
"title": "Drone max sink rate",
"default": MAX_SINK_RATE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_sink_rate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_climb_rate": {
"description": "",
"title": "Drone max climb rate",
"default": MAX_CLIMB_RATE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_climb_rate",
"hidden": 0,
"type": "FloatField"
},
/*"my_map_size": {
"description": "",
"title": "Map size",
"default": MAP_SIZE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "map_size",
"hidden": 0,
"type": "FloatField"
},*/
"my_start_AMSL": {
"description": "",
"title": "Start AMSL",
"default": start_AMSL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "start_AMSL",
"hidden": 0,
"type": "FloatField"
},
"my_map_seed": {
"description": "Seed value to randomize the map",
"title": "Seed value",
"default": url_seed ? url_seed : SEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "map_seed",
"hidden": 0,
"type": "StringField"
},
"my_map_height": {
"description": "",
"title": "Map Height",
"default": map_height,
"css_class": "",
"required": 1,
"editable": 1,
"key": "map_height",
"hidden": 0,
"type": "IntegerField"
},
/*"my_flag_weight": {
"description": "",
"title": "Flag Weight",
"default": FLAG_WEIGHT,
"css_class": "",
"required": 1,
"editable": 1,
"key": "flag_weight",
"hidden": 0,
"type": "IntegerField"
},*/
"my_number_of_drones": {
"description": "",
"title": "Number of drones",
"default": NUMBER_OF_DRONES,
"css_class": "",
"required": 1,
"editable": 1,
"key": "number_of_drones",
"hidden": 0,
"type": "IntegerField"
},
"my_script": {
"default": DEFAULT_SCRIPT_CONTENT,
"css_class": "",
"required": 1,
"editable": 1,
"key": "script",
"hidden": 0,
"type": "GadgetField",
"renderjs_extra": '{"editor": "codemirror", "maximize": true}',
"url": "gadget_editor.html",
"sandbox": "public"
}
}},
"_links": {
"type": {
name: ""
}
domsugar(gadget.element.querySelector('div.captureflagpageheader'), element_list);
}
function getContentFromParameterForm(gadget) {
return gadget.getDeclaredGadget('parameter_form')
.push(function (form_gadget) {
return form_gadget.getContent();
})
.push(function (content_dict) {
var key;
for (key in content_dict) {
if (content_dict.hasOwnProperty(key)) {
gadget.state[key] = content_dict[key];
}
}
});
}
//////////////////////////////////////////////////
// Map parameters
//////////////////////////////////////////////////
function renderMapParameterView(gadget) {
var form_gadget;
renderGadgetHeader(gadget, true);
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form"
})
.push(function (sub_gadget) {
form_gadget = sub_gadget;
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_map_json": {
"description": "",
"title": "Map JSON",
"default": gadget.state.map_json,
"css_class": "",
"required": 1,
"editable": 1,
"key": "map_json",
"hidden": 0,
"url": "gadget_editor.html",
"renderjs_extra": JSON.stringify({
"maximize": true,
"language": "en",
"editor": "codemirror"
}),
"type": "GadgetField"
}
}},
"_links": {
"type": {
name: ""
}
},
form_definition: {
group_list: [[
"left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_number_of_drones"],
/*["my_map_size"], */["my_map_height"],// ["my_flag_weight"],
["my_start_AMSL"], ["my_map_seed"]]
], [
"right",
[["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"],
["my_drone_max_acceleration"], ["my_drone_max_deceleration"],
["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"],
["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]]
], [
"bottom",
[["my_script"]]
]]
}
});
})
.push(function () {
return gadget.updateHeader({
page_title: 'Drone Capture Flag',
page_icon: 'puzzle-piece'
});
},
form_definition: {
group_list: [[
"bottom",
[["my_map_json"]]
]]
}
});
})
})
.push(function () {
renderGadgetHeader(gadget, false);
// Attach the form to the page
domsugar(gadget.element.querySelector('div.captureflagpagebody'), [
form_gadget.element
]);
});
}
.declareJob('runGame', function runGame(options) {
var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json, map_json;
options.map_size = MAP_SIZE;
DRONE_LIST = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild;
for (i = 0; i < options.number_of_drones; i += 1) {
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI",
"script_content": options.script};
}
function randomizeMap(json_map) {
function randomIntFromInterval(min, max, random_seed) {
return Math.floor(random_seed.quick() * (max - min + 1) + min);
}
function randomPosition(random_seed, map_size) {
var sign_x = random_seed.quick() < 0.5 ? -1 : 1,
sign_y = random_seed.quick() < 0.5 ? -1 : 1,
pos_x = sign_x * random_seed.quick() * map_size / 2,
pos_y = sign_y * random_seed.quick() * map_size / 2;
return [pos_x, pos_y];
}
var seed_value = options.map_seed,
random_seed = new Math.seedrandom(seed_value), i,
n_enemies = randomIntFromInterval(5, 10, random_seed),
n_flags = randomIntFromInterval(5, 10, random_seed),
n_obstacles = randomIntFromInterval(5, 15, random_seed),
flag_list = [], obstacle_list = [], enemy_list = [], random_position,
obstacles_types = ["box"/*, "sphere"*/, "cylinder"], type,
obstacle_limit = [options.map_size / 6, options.map_size / 100,
options.map_size / 6, 30];
//enemies
for (i = 0; i < n_enemies; i += 1) {
random_position = randomPosition(random_seed, options.map_size);
enemy_list.push({
"id": i + parseInt(options.number_of_drones),
"type": "EnemyDroneAPI",
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
//////////////////////////////////////////////////
// Map parameters
//////////////////////////////////////////////////
function renderRandomizeView(gadget) {
var form_gadget;
renderGadgetHeader(gadget, true);
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form"
})
.push(function (sub_gadget) {
form_gadget = sub_gadget;
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_map_seed": {
"description": "Seed value to randomize the map",
"title": "Seed value (ex: " + SEED + ")",
"default": gadget.state.map_seed,
"placeholder": SEED,
"css_class": "",
"required": 0,
"editable": 1,
"key": "map_seed",
"hidden": 0,
"type": "StringField"
}
}},
"_links": {
"type": {
name: ""
}
}
});
}
//flags
for (i = 0; i < n_flags; i += 1) {
//avoid flags near the limits
random_position = randomPosition(random_seed, options.map_size * 0.75);
flag_list.push({
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 10
},
form_definition: {
group_list: [[
"center",
[["my_map_seed"]]
]]
}
});
})
.push(function () {
renderGadgetHeader(gadget, false);
// Attach the form to the page
domsugar(gadget.element.querySelector('div.captureflagpagebody'), [
/*
domsugar('label', {
'class': 'item-label',
text: 'Map'
}),*/
form_gadget.element
]);
});
}
//////////////////////////////////////////////////
// Operator parameters
//////////////////////////////////////////////////
function renderOperatorParameterView(gadget) {
var form_gadget;
renderGadgetHeader(gadget, true);
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form"
})
.push(function (sub_gadget) {
form_gadget = sub_gadget;
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_operator_script": {
"description": "",
"title": "Operator script",
"default": gadget.state.operator_script,
"css_class": "",
"required": 1,
"editable": 1,
"key": "operator_script",
"hidden": 0,
"url": "gadget_editor.html",
"renderjs_extra": JSON.stringify({
"maximize": true,
"language": "en",
"portal_type": "Web Script",
"editor": "codemirror"
}),
"type": "GadgetField"
}
}},
"_links": {
"type": {
name: ""
}
}
});
}
function checkDistance(position, position_list) {
function distance(a, b) {
return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
},
form_definition: {
group_list: [[
"bottom",
[["my_operator_script"]]
]]
}
var el;
for (el = 0; el < position_list.length; el += 1) {
if (distance(position, position_list[el].position) < options.map_size / 6) {
return true;
});
})
.push(function () {
renderGadgetHeader(gadget, false);
// Attach the form to the page
domsugar(gadget.element.querySelector('div.captureflagpagebody'), [
form_gadget.element
]);
});
}
//////////////////////////////////////////////////
// Drone script parameter
//////////////////////////////////////////////////
function renderDroneParameterView(gadget) {
var form_gadget;
renderGadgetHeader(gadget, true);
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form"
})
.push(function (sub_gadget) {
form_gadget = sub_gadget;
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_drone_script": {
"description": "",
"title": "Drone script",
"default": gadget.state.drone_script,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_script",
"hidden": 0,
"url": "gadget_editor.html",
"renderjs_extra": JSON.stringify({
"maximize": true,
"language": "en",
"portal_type": "Web Script",
"editor": "codemirror"
}),
"type": "GadgetField"
}
}},
"_links": {
"type": {
name: ""
}
}
},
form_definition: {
group_list: [[
"bottom",
[["my_drone_script"]]
]]
}
return false;
}
//obstacles
for (i = 0; i < n_obstacles; i += 1) {
random_position = randomPosition(random_seed, options.map_size);
if (checkDistance({ 'x': random_position[0],
'y': random_position[1]}, flag_list)) {
i -= 1;
} else {
type = randomIntFromInterval(0, 2, random_seed);
obstacle_list.push({
"type": obstacles_types[type],
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
});
})
.push(function () {
renderGadgetHeader(gadget, false);
// Attach the form to the page
domsugar(gadget.element.querySelector('div.captureflagpagebody'), [
form_gadget.element
]);
});
}
//////////////////////////////////////////////////
// Game parameters
//////////////////////////////////////////////////
function renderGameParameterView(gadget) {
var form_gadget;
renderGadgetHeader(gadget, true);
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "parameter_form"
})
.push(function (sub_gadget) {
form_gadget = sub_gadget;
return form_gadget.render({
erp5_document: {
"_embedded": {"_view": {
"my_simulation_speed": {
"description": "",
"title": "Simulation Speed",
"default": gadget.state.simulation_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "simulation_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_simulation_time": {
"description": "Duration of the simulation (in seconds)",
"title": "Simulation Time",
"default": gadget.state.simulation_time,
"css_class": "",
"required": 1,
"editable": 1,
"key": "simulation_time",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_min_speed": {
"description": "",
"title": "Drone min speed",
"default": gadget.state.drone_min_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_speed",
"hidden": 0,
"type": "IntegerField"
},
"scale": {
"x": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"y": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"z": randomIntFromInterval(5, obstacle_limit[3], random_seed)
"my_drone_speed": {
"description": "",
"title": "Drone speed",
"default": gadget.state.drone_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_speed",
"hidden": 0,
"type": "FloatField"
},
"rotation": {
"x": 0,
"y": 0,
"z": 0
"my_drone_max_speed": {
"description": "",
"title": "Drone max speed",
"default": gadget.state.drone_max_speed,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_speed",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_acceleration": {
"description": "",
"title": "Drone max Acceleration",
"default": gadget.state.drone_max_acceleration,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_acceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_deceleration": {
"description": "",
"title": "Drone max Deceleration",
"default": gadget.state.drone_max_deceleration,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_deceleration",
"hidden": 0,
"type": "IntegerField"
},
"my_drone_max_roll": {
"description": "",
"title": "Drone max roll",
"default": gadget.state.drone_max_roll,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_roll",
"hidden": 0,
"type": "FloatField"
},
"my_drone_min_pitch": {
"description": "",
"title": "Drone min pitch",
"default": gadget.state.drone_min_pitch,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_min_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_pitch": {
"description": "",
"title": "Drone max pitch",
"default": gadget.state.drone_max_pitch,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_pitch",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_sink_rate": {
"description": "",
"title": "Drone max sink rate",
"default": gadget.state.drone_max_sink_rate,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_sink_rate",
"hidden": 0,
"type": "FloatField"
},
"my_drone_max_climb_rate": {
"description": "",
"title": "Drone max climb rate",
"default": gadget.state.drone_max_climb_rate,
"css_class": "",
"required": 1,
"editable": 1,
"key": "drone_max_climb_rate",
"hidden": 0,
"type": "FloatField"
},
"my_number_of_drones": {
"description": "",
"title": "Number of drones",
"default": gadget.state.number_of_drones,
"css_class": "",
"required": 1,
"editable": 1,
"key": "number_of_drones",
"hidden": 0,
"type": "IntegerField"
}
});
}},
"_links": {
"type": {
name: ""
}
}
},
form_definition: {
group_list: [[
"left",
[["my_simulation_speed"], ["my_simulation_time"],
["my_number_of_drones"], ["my_map_seed"]]
], [
"right",
[["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"],
["my_drone_max_acceleration"], ["my_drone_max_deceleration"],
["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"],
["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]]
]]
}
}
json_map.obstacle_list = obstacle_list;
json_map.drones.enemy = enemy_list;
json_map.flag_list = flag_list;
return json_map;
}
});
})
.push(function () {
renderGadgetHeader(gadget, false);
// Attach the form to the page
domsugar(gadget.element.querySelector('div.captureflagpagebody'), [
form_gadget.element
]);
});
}
//////////////////////////////////////////////////
// Play
//////////////////////////////////////////////////
function renderPlayView(gadget) {
renderGadgetHeader(gadget, true);
// XXX Load babylonjs and run game
return gadget.declareGadget("gadget_erp5_form.html", {
scope: "form_view_babylonjs"
})
.push(function (sub_gadget) {
renderGadgetHeader(gadget, false);
// Attach the form to the page
domsugar(gadget.element.querySelector('div.captureflagpagebody'), [
domsugar('div', {
'class': 'simulator_div'
}),
sub_gadget.element
]);
var operator_code = "let operator = function(operator){" +
gadget.state.operator_script +
"return operator.getDroneStartMessage();" +
"}; return operator(new OperatorAPI(" + gadget.state.map_json + "));";
map_json = {
"map_size": parseFloat(options.map_size),
"height": parseInt(options.map_height, 10),
"start_AMSL": parseFloat(options.start_AMSL),
"min_lat": parseFloat(min_lat),
"max_lat": parseFloat(max_lat),
"min_lon": parseFloat(min_lon),
"max_lon": parseFloat(max_lon),
"flag_list": [],
"obstacle_list" : [],
"drones": {
"user": DRONE_LIST,
"enemy": []
/*jslint evil: true*/
try {
gadget.state.operator_init_msg = new Function(operator_code)();
} catch (error) {
return gadget.notifySubmitted({message: "Error in operator script: " +
error.message, status: 'error'});
}
};
/*jslint evil: false*/
gadget.runGame();
});
}
rJS(window)
/////////////////////////////////////////////////////////////////
// Acquired methods
/////////////////////////////////////////////////////////////////
.declareAcquiredMethod("updateHeader", "updateHeader")
.declareAcquiredMethod("notifySubmitted", "notifySubmitted")
.allowPublicAcquisition('notifySubmit', function () {
return this.triggerSubmit();
})
.declareMethod("triggerSubmit", function () {
return;
})
.declareJob('runGame', function runGame(do_nothing) {
if (do_nothing) {
// Cancel the previous job execution
return;
}
var gadget = this,
i,
parsed_map,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json,
drone_list = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild;
for (i = 0; i < gadget.state.number_of_drones; i += 1) {
drone_list[i] = {"id": i, "type": "FixedWingDroneAPI",
"script_content": gadget.state.drone_script};
}
try {
parsed_map = JSON.parse(gadget.state.map_json);
} catch (error) {
return gadget.notifySubmitted({message: "Error: " + error.message,
status: 'error'});
}
game_parameters_json = {
"drone": {
"maxAcceleration": parseInt(options.drone_max_acceleration, 10),
"maxDeceleration": parseInt(options.drone_max_deceleration, 10),
"minSpeed": parseInt(options.drone_min_speed, 10),
"speed": parseFloat(options.drone_speed),
"maxSpeed": parseInt(options.drone_max_speed, 10),
"maxRoll": parseFloat(options.drone_max_roll),
"minPitchAngle": parseFloat(options.drone_min_pitch),
"maxPitchAngle": parseFloat(options.drone_max_pitch),
"maxSinkRate": parseFloat(options.drone_max_sink_rate),
"maxClimbRate": parseFloat(options.drone_max_climb_rate)
"maxAcceleration": parseInt(gadget.state.drone_max_acceleration, 10),
"maxDeceleration": parseInt(gadget.state.drone_max_deceleration, 10),
"minSpeed": parseInt(gadget.state.drone_min_speed, 10),
"speed": parseFloat(gadget.state.drone_speed),
"maxSpeed": parseInt(gadget.state.drone_max_speed, 10),
"maxRoll": parseFloat(gadget.state.drone_max_roll),
"minPitchAngle": parseFloat(gadget.state.drone_min_pitch),
"maxPitchAngle": parseFloat(gadget.state.drone_max_pitch),
"maxSinkRate": parseFloat(gadget.state.drone_max_sink_rate),
"maxClimbRate": parseFloat(gadget.state.drone_max_climb_rate),
"list": drone_list
},
"gameTime": parseInt(options.simulation_time, 10),
"simulation_speed": parseInt(options.simulation_speed, 10),
"gameTime": parseInt(gadget.state.simulation_time, 10),
"simulation_speed": parseInt(gadget.state.simulation_speed, 10),
"latency": {
"information": 0,
"communication": 0
},
"map": randomizeMap(map_json),
"map": parsed_map,
"operator_init_msg": gadget.state.operator_init_msg,
"draw_flight_path": DRAW,
"temp_flight_path": true,
"log_drone_flight": LOG,
......@@ -604,9 +848,12 @@
return form_gadget.getContent();
})
.push(function (result) {
var a, blob, div, key, log, log_content, aux;
var a, blob, div, key, log, log_content, label;
i = 0;
div = domsugar('div', { text: result.message });
label = domsugar('label', { text: "Results" });
label.classList.add("item-label");
document.querySelector('.container').parentNode.appendChild(label);
document.querySelector('.container').parentNode.appendChild(div);
for (key in result.content) {
if (result.content.hasOwnProperty(key)) {
......@@ -615,17 +862,17 @@
a = domsugar('a', {
text: 'Download Simulation LOG ' + i,
download: 'simulation_log_' + i +
'_speed_' + game_parameters_json.drone.speed +
'_min-speed_' + game_parameters_json.drone.minSpeed +
'_max-speed_' + game_parameters_json.drone.maxSpeed +
'_max-accel_' + game_parameters_json.drone.maxAcceleration +
'_max-decel_' + game_parameters_json.drone.maxDeceleration +
'_max-roll_' + game_parameters_json.drone.maxRoll +
'_min-pitch_' + game_parameters_json.drone.minPitchAngle +
'_max-pitch_' + game_parameters_json.drone.maxPitchAngle +
'_max-sink_' + game_parameters_json.drone.maxSinkRate +
'_max-climb_' + game_parameters_json.drone.maxClimbRate +
'.txt',
'_speed_' + game_parameters_json.drone.speed +
'_min-speed_' + game_parameters_json.drone.minSpeed +
'_max-speed_' + game_parameters_json.drone.maxSpeed +
'_max-accel_' + game_parameters_json.drone.maxAcceleration +
'_max-decel_' + game_parameters_json.drone.maxDeceleration +
'_max-roll_' + game_parameters_json.drone.maxRoll +
'_min-pitch_' + game_parameters_json.drone.minPitchAngle +
'_max-pitch_' + game_parameters_json.drone.maxPitchAngle +
'_max-sink_' + game_parameters_json.drone.maxSinkRate +
'_max-climb_' + game_parameters_json.drone.maxClimbRate +
'.txt',
href: window.URL.createObjectURL(blob)
});
log = domsugar('textarea',
......@@ -636,7 +883,7 @@
document.querySelector('.container').parentNode.appendChild(div);
document.querySelector('.container').parentNode.appendChild(log);
i += 1;
if (i === DRONE_LIST.length) {
if (i === drone_list.length) {
break;
//Do not show enemy drone logs for now
/*aux = domsugar('div', { text: "Enemy drones logs:" });
......@@ -648,6 +895,206 @@
return gadget.notifySubmitted({message: "Error: " + error.message,
status: 'error'});
});
});
})
.setState({
operator_script: DEFAULT_OPERATOR_SCRIPT,
drone_script: DEFAULT_SCRIPT_CONTENT,
number_of_drones: NUMBER_OF_DRONES,
drone_max_climb_rate: MAX_CLIMB_RATE,
drone_max_sink_rate: MAX_SINK_RATE,
drone_max_pitch: MAX_PITCH,
drone_min_pitch: MIN_PITCH,
drone_max_roll: MAX_ROLL,
drone_max_deceleration: MAX_DECELERATION,
drone_max_acceleration: MAX_ACCELERATION,
drone_max_speed: MAX_SPEED,
drone_speed: DEFAULT_SPEED,
drone_min_speed: MIN_SPEED,
simulation_time: SIMULATION_TIME,
simulation_speed: SIMULATION_SPEED,
operator_init_msg: {},
// Force user to fill a value, to prevent
// deleting the map by accident
map_seed: null,
map_json: JSON.stringify(MAP, undefined, 4)
})
.declareMethod('render', function render() {
var gadget = this;
return gadget.changeState({
display_step: DISPLAY_PLAY
})
.push(function () {
return gadget.updateHeader({
page_title: 'Drone Capture Flag',
page_icon: 'puzzle-piece'
});
});
})
.onStateChange(function (modification_dict) {
var gadget = this;
if (gadget.state.display_step === DISPLAY_MAP_PARAMETER) {
if (modification_dict.hasOwnProperty('display_step')) {
// do not update the form if it is already displayed
return renderMapParameterView(gadget);
}
}
if (gadget.state.display_step === DISPLAY_RANDOMIZE) {
if (modification_dict.hasOwnProperty('display_step')) {
// do not update the form if it is already displayed
return renderRandomizeView(gadget);
}
}
if (gadget.state.display_step === DISPLAY_GAME_PARAMETER) {
if (modification_dict.hasOwnProperty('display_step')) {
// do not update the form if it is already displayed
return renderGameParameterView(gadget);
}
}
if (gadget.state.display_step === DISPLAY_OPERATOR_PARAMETER) {
if (modification_dict.hasOwnProperty('display_step')) {
// do not update the form if it is already displayed
return renderOperatorParameterView(gadget);
}
}
if (gadget.state.display_step === DISPLAY_DRONE_PARAMETER) {
if (modification_dict.hasOwnProperty('display_step')) {
// do not update the form if it is already displayed
return renderDroneParameterView(gadget);
}
}
if (gadget.state.display_step === DISPLAY_PLAY) {
return renderPlayView(gadget);
}
if (modification_dict.hasOwnProperty('display_step')) {
throw new Error('Unhandled display step: ' + gadget.state.display_step);
}
})
//////////////////////////////////////////////////
// Used when submitting the form
//////////////////////////////////////////////////
.declareMethod('getContent', function () {
var gadget = this,
display_step = gadget.state.display_step,
queue;
if ([DISPLAY_OPERATOR_PARAMETER,
DISPLAY_DRONE_PARAMETER,
DISPLAY_MAP_PARAMETER,
DISPLAY_GAME_PARAMETER].indexOf(gadget.state.display_step) !== -1) {
queue = new RSVP.Queue(getContentFromParameterForm(gadget));
} else if (gadget.state.display_step === DISPLAY_RANDOMIZE) {
// Randomizing function is called, only if user entered a feed
queue = new RSVP.Queue(getContentFromParameterForm(gadget))
.push(function () {
if (gadget.state.map_seed) {
gadget.state.map_json = JSON.stringify(
new MapUtils(MAP).randomize(gadget.state.map_seed),
undefined,
4
);
}
});
} else if (gadget.state.display_step === DISPLAY_PLAY) {
// Cancel the run execution, by triggering the job again
// Out job does nothing if no parameter is passed
gadget.runGame(true);
// Nothing to store in the play view
queue = new RSVP.Queue();
} else {
throw new Error('getContent form not handled: ' + display_step);
}
return queue;
}, {mutex: 'changestate'})
.onEvent("click", function (evt) {
// Only handle click on BUTTON element
var gadget = this,
tag_name = evt.target.tagName,
queue;
if (tag_name !== 'BUTTON') {
return;
}
// Disable any button. It must be managed by this gadget
evt.preventDefault();
// Always get content to ensure the possible displayed form
// is checked and content propagated to the gadget state value
queue = gadget.getContent();
if (evt.target.className.indexOf("display-map-parameter-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_MAP_PARAMETER
});
});
}
if (evt.target.className.indexOf("display-randomize-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_RANDOMIZE
});
});
}
if (evt.target.className.indexOf("display-operator-script-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_OPERATOR_PARAMETER
});
});
}
if (evt.target.className.indexOf("display-drone-script-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_DRONE_PARAMETER
});
});
}
if (evt.target.className.indexOf("display-game-parameter-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_GAME_PARAMETER
});
});
}
if (evt.target.className.indexOf("display-play-btn") !== -1) {
return queue
.push(function () {
return gadget.changeState({
display_step: DISPLAY_PLAY,
force_timestamp: new Date()
});
});
}
throw new Error('Unhandled button: ' + evt.target.textContent);
}, false, false);
}(window, rJS, domsugar, document, URLSearchParams, Blob));
\ No newline at end of file
}(window, rJS, domsugar, document, Blob, MapUtils, RSVP));
\ No newline at end of file
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1010.23654.50890.20360</string> </value>
<value> <string>1011.18818.32686.32580</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1691681704.91</float>
<float>1695397751.99</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -277,7 +277,7 @@
</item>
<item>
<key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; script-src \'self\' \'unsafe-eval\';</string> </value>
</item>
<item>
<key> <string>configuration_latest_document_version</string> </key>
......@@ -538,7 +538,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1007.63243.40091.31010</string> </value>
<value> <string>1010.35278.59853.35635</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -558,7 +558,7 @@
</tuple>
<state>
<tuple>
<float>1682433351.46</float>
<float>1692976685.9</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; script-src \'self\' \'unsafe-eval\';</string> </value>
</item>
<item>
<key> <string>configuration_default_view_action_reference</string> </key>
......@@ -502,7 +502,7 @@ WebSection_getDroneCaptureFlagPrecacheManifestList</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1007.63247.30934.52258</string> </value>
<value> <string>1010.35278.59853.35635</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -522,7 +522,7 @@ WebSection_getDroneCaptureFlagPrecacheManifestList</string> </value>
</tuple>
<state>
<tuple>
<float>1682433685.5</float>
<float>1692976699.18</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -4,8 +4,10 @@ url_list = [
"gadget_erp5_page_drone_capture_flag_logic.js",
"gadget_erp5_page_drone_capture_flag_script_page.html",
"gadget_erp5_page_drone_capture_flag_script_page.js",
"gadget_erp5_page_drone_capture_flag_script_page.css",
"gadget_erp5_panel_drone_capture_flag.html",
"gadget_erp5_panel_drone_capture_flag.js",
"gadget_erp5_page_drone_capture_map_utils.js",
"gadget_erp5_page_drone_capture_flag_fixedwingdrone.js",
"gadget_erp5_page_drone_capture_flag_enemydrone.js",
"gadget_erp5_page_drone_capture_flag_api_page.html",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment