New insectoid almost done + DestroyBlockObjective
BIN
core/assets-raw/sprites/units/anthicus-blade-heat.png
Normal file
|
After Width: | Height: | Size: 734 B |
BIN
core/assets-raw/sprites/units/anthicus-blade.png
Normal file
|
After Width: | Height: | Size: 194 B |
BIN
core/assets-raw/sprites/units/anthicus-leg-base.png
Normal file
|
After Width: | Height: | Size: 519 B |
BIN
core/assets-raw/sprites/units/anthicus-leg.png
Normal file
|
After Width: | Height: | Size: 557 B |
BIN
core/assets-raw/sprites/units/anthicus-weapon-blade-heat.png
Normal file
|
After Width: | Height: | Size: 624 B |
BIN
core/assets-raw/sprites/units/anthicus-weapon-blade.png
Normal file
|
After Width: | Height: | Size: 505 B |
BIN
core/assets-raw/sprites/units/anthicus-weapon-heat.png
Normal file
|
After Width: | Height: | Size: 741 B |
BIN
core/assets-raw/sprites/units/anthicus-weapon.png
Normal file
|
After Width: | Height: | Size: 369 B |
BIN
core/assets-raw/sprites/units/weapons/anthicus-missile-cell.png
Normal file
|
After Width: | Height: | Size: 183 B |
BIN
core/assets-raw/sprites/units/weapons/anthicus-missile.png
Normal file
|
After Width: | Height: | Size: 443 B |
@@ -574,6 +574,7 @@ uncover = Uncover
|
|||||||
configure = Configure Loadout
|
configure = Configure Loadout
|
||||||
|
|
||||||
objective.research = [accent]Research:\n[]{0}[lightgray]{1}
|
objective.research = [accent]Research:\n[]{0}[lightgray]{1}
|
||||||
|
objective.destroyblock = [accent]Destroy Structure:\n[]{0}[lightgray]{1}
|
||||||
objective.item = [accent]Obtain: [][lightgray]{0}[]/{1}\n{2}[lightgray]{3}
|
objective.item = [accent]Obtain: [][lightgray]{0}[]/{1}\n{2}[lightgray]{3}
|
||||||
objective.coreitem = [accent]Move into Core:\n[][lightgray]{0}[]/{1}\n{2}[lightgray]{3}
|
objective.coreitem = [accent]Move into Core:\n[][lightgray]{0}[]/{1}\n{2}[lightgray]{3}
|
||||||
objective.build = [accent]Build: [][lightgray]{0}[]x\n{1}[lightgray]{2}
|
objective.build = [accent]Build: [][lightgray]{0}[]x\n{1}[lightgray]{2}
|
||||||
|
|||||||
@@ -548,3 +548,4 @@
|
|||||||
63144=canvas|block-canvas-ui
|
63144=canvas|block-canvas-ui
|
||||||
63143=armored-duct|block-armored-duct-ui
|
63143=armored-duct|block-armored-duct-ui
|
||||||
63142=anthicus|unit-anthicus-ui
|
63142=anthicus|unit-anthicus-ui
|
||||||
|
63141=anthicus-missile|unit-anthicus-missile-ui
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ public class MissileAI extends AIController{
|
|||||||
@Override
|
@Override
|
||||||
public boolean retarget(){
|
public boolean retarget(){
|
||||||
//more frequent retarget due to high speed. TODO won't this lag?
|
//more frequent retarget due to high speed. TODO won't this lag?
|
||||||
return timer.get(timerTarget, 10f);
|
return timer.get(timerTarget, 4f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import arc.graphics.g2d.*;
|
|||||||
import arc.math.*;
|
import arc.math.*;
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
import mindustry.ai.types.*;
|
import mindustry.ai.types.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
@@ -2933,6 +2934,7 @@ public class UnitTypes{
|
|||||||
|
|
||||||
legCount = 6;
|
legCount = 6;
|
||||||
legLength = 18f;
|
legLength = 18f;
|
||||||
|
legGroupSize = 3;
|
||||||
lockLegBase = true;
|
lockLegBase = true;
|
||||||
legContinuousMove = true;
|
legContinuousMove = true;
|
||||||
legExtension = -3f;
|
legExtension = -3f;
|
||||||
@@ -2940,13 +2942,134 @@ public class UnitTypes{
|
|||||||
maxStretch = 1.1f;
|
maxStretch = 1.1f;
|
||||||
maxCompress = 0.2f;
|
maxCompress = 0.2f;
|
||||||
legLengthScl = 0.95f;
|
legLengthScl = 0.95f;
|
||||||
legTrns = 0.7f;
|
legTrns = 0.9f;
|
||||||
|
|
||||||
legMoveSpace = 1f;
|
legMoveSpace = 1f;
|
||||||
hovering = true;
|
hovering = true;
|
||||||
|
|
||||||
visualElevation = 0.2f;
|
visualElevation = 0.2f;
|
||||||
groundLayer = Layer.legUnit - 1f;
|
groundLayer = Layer.legUnit - 1f;
|
||||||
|
|
||||||
|
for(int j = 0; j < 3; j++){
|
||||||
|
int i = j;
|
||||||
|
parts.add(new RegionPart("-blade"){{
|
||||||
|
layerOffset = -0.01f;
|
||||||
|
heatLayerOffset = 0.005f;
|
||||||
|
x = 2f;
|
||||||
|
moveX = 6f + i * 1.9f;
|
||||||
|
moveY = 8f + -4f * i;
|
||||||
|
moveRot = 40f - i * 25f;
|
||||||
|
mirror = true;
|
||||||
|
progress = PartProgress.warmup.delay(i * 0.2f);
|
||||||
|
heatProgress = p -> Mathf.absin(Time.time + i * 14f, 7f, 1f);
|
||||||
|
|
||||||
|
heatColor = Pal.techBlue;
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
weapons.add(new Weapon("anthicus-weapon"){{
|
||||||
|
x = 29f / 4f;
|
||||||
|
y = -11f / 4f;
|
||||||
|
shootY = 1.5f;
|
||||||
|
reload = 130f;
|
||||||
|
layerOffset = 0.01f;
|
||||||
|
heatColor = Color.red;
|
||||||
|
cooldownTime = 60f;
|
||||||
|
smoothReloadSpeed = 0.15f;
|
||||||
|
shootWarmupSpeed = 0.05f;
|
||||||
|
minWarmup = 0.9f;
|
||||||
|
shootStatus = StatusEffects.slow;
|
||||||
|
shootStatusDuration = reload + 1f;
|
||||||
|
|
||||||
|
rotateSpeed = 5f;
|
||||||
|
inaccuracy = 20f;
|
||||||
|
|
||||||
|
rotate = true;
|
||||||
|
|
||||||
|
shoot = new ShootPattern(){{
|
||||||
|
shots = 2;
|
||||||
|
shotDelay = 6f;
|
||||||
|
}};
|
||||||
|
|
||||||
|
parts.add(new RegionPart("-blade"){{
|
||||||
|
mirror = true;
|
||||||
|
moveRot = -25f;
|
||||||
|
under = true;
|
||||||
|
moves.add(new PartMove(PartProgress.reload, 1f, 0f, 0f));
|
||||||
|
|
||||||
|
heatColor = Color.red;
|
||||||
|
cooldownTime = 60f;
|
||||||
|
}});
|
||||||
|
|
||||||
|
parts.add(new RegionPart("-blade"){{
|
||||||
|
mirror = true;
|
||||||
|
moveRot = -50f;
|
||||||
|
moveY = -2f;
|
||||||
|
moves.add(new PartMove(PartProgress.reload.shorten(0.5f), 1f, 0f, -15f));
|
||||||
|
under = true;
|
||||||
|
|
||||||
|
heatColor = Color.red;
|
||||||
|
cooldownTime = 60f;
|
||||||
|
}});
|
||||||
|
|
||||||
|
bullet = new BulletType(){{
|
||||||
|
shootEffect = new MultiEffect(Fx.shootBigColor, new Effect(9, e -> {
|
||||||
|
color(Color.white, e.color, e.fin());
|
||||||
|
stroke(0.7f + e.fout());
|
||||||
|
Lines.square(e.x, e.y, e.fin() * 5f, e.rotation + 45f);
|
||||||
|
|
||||||
|
Drawf.light(e.x, e.y, 23f, e.color, e.fout() * 0.7f);
|
||||||
|
}), new WaveEffect(){{
|
||||||
|
colorFrom = colorTo = Pal.techBlue;
|
||||||
|
sizeTo = 15f;
|
||||||
|
lifetime = 12f;
|
||||||
|
strokeFrom = 3f;
|
||||||
|
}});
|
||||||
|
|
||||||
|
smokeEffect = Fx.shootBigSmoke2;
|
||||||
|
shake = 2f;
|
||||||
|
speed = 0f;
|
||||||
|
keepVelocity = false;
|
||||||
|
inaccuracy = 2f;
|
||||||
|
|
||||||
|
spawnUnit = new MissileUnitType("anthicus-missile"){{
|
||||||
|
trailColor = engineColor = Pal.techBlue;
|
||||||
|
engineSize = 1.75f;
|
||||||
|
engineLayer = Layer.effect;
|
||||||
|
speed = 3.7f;
|
||||||
|
maxRange = 6f;
|
||||||
|
lifetime = 60f * 1.63f;
|
||||||
|
outlineColor = Pal.darkOutline;
|
||||||
|
health = 40;
|
||||||
|
lowAltitude = true;
|
||||||
|
|
||||||
|
parts.add(new FlarePart(){{
|
||||||
|
progress = PartProgress.life.slope().curve(Interp.pow2In);
|
||||||
|
radius = 0f;
|
||||||
|
radiusTo = 35f;
|
||||||
|
stroke = 3f;
|
||||||
|
rotation = 45f;
|
||||||
|
y = -5f;
|
||||||
|
followRotation = true;
|
||||||
|
}});
|
||||||
|
|
||||||
|
weapons.add(new Weapon(){{
|
||||||
|
shootCone = 360f;
|
||||||
|
mirror = false;
|
||||||
|
reload = 1f;
|
||||||
|
shootOnDeath = true;
|
||||||
|
bullet = new ExplosionBulletType(100f, 22f){{
|
||||||
|
shootEffect = new MultiEffect(Fx.massiveExplosion, new WaveEffect(){{
|
||||||
|
colorFrom = colorTo = Pal.techBlue;
|
||||||
|
sizeTo = 40f;
|
||||||
|
lifetime = 12f;
|
||||||
|
strokeFrom = 4f;
|
||||||
|
}});
|
||||||
|
}};
|
||||||
|
}});
|
||||||
|
}};
|
||||||
|
}};
|
||||||
|
}});
|
||||||
}};
|
}};
|
||||||
|
|
||||||
bulwark = new ErekirUnitType("bulwark"){{
|
bulwark = new ErekirUnitType("bulwark"){{
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import static mindustry.Vars.*;
|
|||||||
abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
|
abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
|
||||||
private static final Vec2 straightVec = new Vec2();
|
private static final Vec2 straightVec = new Vec2();
|
||||||
|
|
||||||
@Import float x, y, rotation;
|
@Import float x, y, rotation, speedMultiplier;
|
||||||
@Import UnitType type;
|
@Import UnitType type;
|
||||||
@Import Team team;
|
@Import Team team;
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
|
|||||||
int div = Math.max(legs.length / type.legGroupSize, 2);
|
int div = Math.max(legs.length / type.legGroupSize, 2);
|
||||||
moveSpace = legLength / 1.6f / (div / 2f) * type.legMoveSpace;
|
moveSpace = legLength / 1.6f / (div / 2f) * type.legMoveSpace;
|
||||||
//TODO should move legs even when still, based on speed. also, to prevent "slipping", make sure legs move when they are too far from their destination
|
//TODO should move legs even when still, based on speed. also, to prevent "slipping", make sure legs move when they are too far from their destination
|
||||||
totalLength += type.legContinuousMove ? type.speed : Mathf.dst(deltaX(), deltaY());
|
totalLength += type.legContinuousMove ? type.speed * speedMultiplier : Mathf.dst(deltaX(), deltaY());
|
||||||
|
|
||||||
float trns = moveSpace * 0.85f * type.legTrns;
|
float trns = moveSpace * 0.85f * type.legTrns;
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ public abstract class DrawPart{
|
|||||||
public boolean turretShading;
|
public boolean turretShading;
|
||||||
/** If true, the layer is overridden to be under the weapon/turret itself. */
|
/** If true, the layer is overridden to be under the weapon/turret itself. */
|
||||||
public boolean under = false;
|
public boolean under = false;
|
||||||
|
/** For units, this is the index of the weapon this part gets its progress for. */
|
||||||
|
public int weaponIndex = 0;
|
||||||
|
|
||||||
public abstract void draw(PartParams params);
|
public abstract void draw(PartParams params);
|
||||||
public abstract void load(String name);
|
public abstract void load(String name);
|
||||||
@@ -81,6 +83,11 @@ public abstract class DrawPart{
|
|||||||
return p -> 1f - get(p);
|
return p -> 1f - get(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default PartProgress slope(){
|
||||||
|
return p -> Mathf.slope(get(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
default PartProgress clamp(){
|
default PartProgress clamp(){
|
||||||
return p -> Mathf.clamp(get(p));
|
return p -> Mathf.clamp(get(p));
|
||||||
}
|
}
|
||||||
|
|||||||
53
core/src/mindustry/entities/part/FlarePart.java
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package mindustry.entities.part;
|
||||||
|
|
||||||
|
import arc.graphics.*;
|
||||||
|
import arc.graphics.g2d.*;
|
||||||
|
import arc.math.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import mindustry.graphics.*;
|
||||||
|
|
||||||
|
public class FlarePart extends DrawPart{
|
||||||
|
public int sides = 4;
|
||||||
|
public float radius = 100f, radiusTo = -1f, stroke = 6f, innerScl = 0.5f, innerRadScl = 0.33f;
|
||||||
|
public float x, y, rotation, rotMove;
|
||||||
|
public boolean followRotation;
|
||||||
|
public Color color1 = Pal.techBlue, color2 = Color.white;
|
||||||
|
public PartProgress progress = PartProgress.warmup;
|
||||||
|
public float layer = Layer.effect;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(PartParams params){
|
||||||
|
float z = Draw.z();
|
||||||
|
if(layer > 0) Draw.z(layer);
|
||||||
|
|
||||||
|
float prog = progress.getClamp(params);
|
||||||
|
int i = params.sideOverride == -1 ? 0 : params.sideOverride;
|
||||||
|
|
||||||
|
float sign = (i == 0 ? 1 : -1) * params.sideMultiplier;
|
||||||
|
Tmp.v1.set(x * sign, y).rotate(params.rotation - 90);
|
||||||
|
|
||||||
|
float
|
||||||
|
rx = params.x + Tmp.v1.x,
|
||||||
|
ry = params.y + Tmp.v1.y,
|
||||||
|
rot = (followRotation ? params.rotation : 0f) + rotMove * prog + rotation,
|
||||||
|
rad = radiusTo < 0 ? radius : Mathf.lerp(radius, radiusTo, prog);
|
||||||
|
|
||||||
|
Draw.color(color1);
|
||||||
|
for(int j = 0; j < sides; j++){
|
||||||
|
Drawf.tri(rx, ry, stroke, rad, j * 360f / sides + rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw.color(color2);
|
||||||
|
for(int j = 0; j < sides; j++){
|
||||||
|
Drawf.tri(rx, ry, stroke * innerScl, rad * innerRadScl, j * 360f / sides + rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Draw.color();
|
||||||
|
Draw.z(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(String name){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ public class RegionPart extends DrawPart{
|
|||||||
/** Progress function for heat alpha. */
|
/** Progress function for heat alpha. */
|
||||||
public PartProgress heatProgress = PartProgress.heat;
|
public PartProgress heatProgress = PartProgress.heat;
|
||||||
public Blending blending = Blending.normal;
|
public Blending blending = Blending.normal;
|
||||||
public float layer = -1, layerOffset = 0f;
|
public float layer = -1, layerOffset = 0f, heatLayerOffset = 1f;
|
||||||
public float outlineLayerOffset = -0.001f;
|
public float outlineLayerOffset = -0.001f;
|
||||||
public float x, y, rotation;
|
public float x, y, rotation;
|
||||||
public float moveX, moveY, moveRot;
|
public float moveX, moveY, moveRot;
|
||||||
@@ -62,7 +62,7 @@ public class RegionPart extends DrawPart{
|
|||||||
|
|
||||||
float prevZ = Draw.z();
|
float prevZ = Draw.z();
|
||||||
float prog = progress.getClamp(params);
|
float prog = progress.getClamp(params);
|
||||||
float mx = moveX * prog, my = moveY * prog, mr = moveRot * prog;
|
float mx = moveX * prog, my = moveY * prog, mr = moveRot * prog + rotation;
|
||||||
|
|
||||||
if(moves.size > 0){
|
if(moves.size > 0){
|
||||||
for(int i = 0; i < moves.size; i++){
|
for(int i = 0; i < moves.size; i++){
|
||||||
@@ -111,7 +111,7 @@ public class RegionPart extends DrawPart{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(heat.found()){
|
if(heat.found()){
|
||||||
Drawf.additive(heat, heatColor.write(Tmp.c1).a(heatProgress.getClamp(params) * heatColor.a), rx, ry, rot, turretShading ? Layer.turretHeat : z + 1f);
|
Drawf.additive(heat, heatColor.write(Tmp.c1).a(heatProgress.getClamp(params) * heatColor.a), rx, ry, rot, turretShading ? Layer.turretHeat : Draw.z() + heatLayerOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw.xscl = 1f;
|
Draw.xscl = 1f;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class ShapePart extends DrawPart{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!circle){
|
if(!circle){
|
||||||
Fill.poly(rx, ry, sides, rad, moveRot * prog * sign + params.rotation - 90);
|
Fill.poly(rx, ry, sides, rad, moveRot * prog * sign + params.rotation - 90 * sign + rotation * sign);
|
||||||
}else{
|
}else{
|
||||||
Fill.circle(rx, ry, rad);
|
Fill.circle(rx, ry, rad);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class MapObjectives{
|
|||||||
public static Prov<MapObjective>[] allObjectiveTypes = new Prov[]{
|
public static Prov<MapObjective>[] allObjectiveTypes = new Prov[]{
|
||||||
ResearchObjective::new, BuildCountObjective::new, UnitCountObjective::new, ItemObjective::new,
|
ResearchObjective::new, BuildCountObjective::new, UnitCountObjective::new, ItemObjective::new,
|
||||||
CommandModeObjective::new, CoreItemObjective::new, DestroyCoreObjective::new, DestroyUnitsObjective::new,
|
CommandModeObjective::new, CoreItemObjective::new, DestroyCoreObjective::new, DestroyUnitsObjective::new,
|
||||||
TimerObjective::new, FlagObjective::new
|
TimerObjective::new, FlagObjective::new, DestroyBlockObjective::new
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Prov<ObjectiveMarker>[] allMarkerTypes = new Prov[]{
|
public static Prov<ObjectiveMarker>[] allMarkerTypes = new Prov[]{
|
||||||
@@ -208,6 +208,34 @@ public class MapObjectives{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class DestroyBlockObjective extends MapObjective{
|
||||||
|
public int x, y;
|
||||||
|
public Team team = Team.malis;
|
||||||
|
public Block block = Blocks.router;
|
||||||
|
|
||||||
|
public DestroyBlockObjective(Block block, int x, int y, Team team){
|
||||||
|
this.block = block;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.team = team;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DestroyBlockObjective(){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean complete(){
|
||||||
|
var build = world.build(x, y);
|
||||||
|
return build == null || build.team != team || build.block != block;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String text(){
|
||||||
|
return Core.bundle.format("objective.destroyblock", block.emoji(), block.localizedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** Command any unit to do anything. Always compete in headless mode. */
|
/** Command any unit to do anything. Always compete in headless mode. */
|
||||||
public static class CommandModeObjective extends MapObjective{
|
public static class CommandModeObjective extends MapObjective{
|
||||||
|
|
||||||
|
|||||||
@@ -881,18 +881,20 @@ public class UnitType extends UnlockableContent{
|
|||||||
|
|
||||||
//TODO how/where do I draw under?
|
//TODO how/where do I draw under?
|
||||||
if(parts.size > 0){
|
if(parts.size > 0){
|
||||||
//TODO does it need an outline?
|
|
||||||
WeaponMount first = unit.mounts.length > 0 ? unit.mounts[0] : null;
|
|
||||||
if(unit.mounts.length > 0){
|
|
||||||
DrawPart.params.set(first.warmup, first.reload / weapons.first().reload, first.smoothReload, first.heat, unit.x, unit.y, unit.rotation);
|
|
||||||
}else{
|
|
||||||
DrawPart.params.set(0f, 0f, 0f, 0f, unit.x, unit.y, unit.rotation);
|
|
||||||
}
|
|
||||||
if(unit instanceof Scaled s){
|
|
||||||
DrawPart.params.life = s.fin();
|
|
||||||
}
|
|
||||||
for(int i = 0; i < parts.size; i++){
|
for(int i = 0; i < parts.size; i++){
|
||||||
var part = parts.items[i];
|
var part = parts.items[i];
|
||||||
|
|
||||||
|
WeaponMount first = unit.mounts.length > part.weaponIndex ? unit.mounts[part.weaponIndex] : null;
|
||||||
|
if(first != null){
|
||||||
|
DrawPart.params.set(first.warmup, first.reload / weapons.first().reload, first.smoothReload, first.heat, unit.x, unit.y, unit.rotation);
|
||||||
|
}else{
|
||||||
|
DrawPart.params.set(0f, 0f, 0f, 0f, unit.x, unit.y, unit.rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unit instanceof Scaled s){
|
||||||
|
DrawPart.params.life = s.fin();
|
||||||
|
}
|
||||||
|
|
||||||
part.draw(DrawPart.params);
|
part.draw(DrawPart.params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||