Advertisement
ezNNP

main.js

Aug 13th, 2020
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const POSSIBLE_TYPES = ["none","rock"];
  2. const POSSIBLE_THINGS = ["nothing","boy","apples","apple-tree","red-cherry-tree","red-cherry","yellow-cherry-tree","yellow-cherry","stump"];
  3. const POSSIBLE_DIRS = ["N","S","E","W"];
  4. const POSSIBLE_STATES = ["walking","waiting","recovering","hitting"];
  5.  
  6. let iLoveCssDegrees = 0;
  7.  
  8. class Cell
  9. {
  10.     constructor(x,y,type)
  11.     {
  12.         this.x = x;
  13.         this.y = y;
  14.         this.type = type || "none";
  15.         this.isWall = ((this.x*this.y) % 2 === 0);
  16.     }
  17.     checkPassable()
  18.     {
  19.         return (this.type==="none") && (this.getThing()===nothing);
  20.     }
  21.     setType(newType)
  22.     {
  23.         this.type=newType;
  24.         switch (newType) {
  25.             case "rock":
  26.                 this.description = "Каменная стена. Ничего не могу с ней сделать.";
  27.                 break;
  28.         }
  29.         return this;
  30.     }
  31.     getNext()
  32.     {
  33.         switch (boy.dir)
  34.         {
  35.             case "N": return cells[this.x][this.y+1];
  36.             case "S": return cells[this.x][this.y-1];
  37.             case "E": return cells[this.x+1][this.y];
  38.             case "W": return cells[this.x-1][this.y];
  39.         }
  40.     }
  41.     getDescription()
  42.     {
  43.         return (this.isWall)
  44.             ?(this.checkPassable())
  45.                 ?this.getNext().getDescription()
  46.                 :this.description
  47.             :this.getThing().description;
  48.     }
  49.     addThing(Cl,props)
  50.     {
  51.         return new Cl(this,props);// TODO: check available space
  52.     }
  53.     getThing()
  54.     {
  55.         return (things.filter(thing=>thing.cell===this).length!==0)
  56.             ?things.filter(thing=>thing.cell===this)[0]
  57.             :nothing;
  58.     }
  59.     getContainer()
  60.     {
  61.         return document.querySelector(`.c${13+this.x-boy.cell.x}.r${13-this.y+boy.cell.y}`);
  62.     }
  63.     updateSelf()
  64.     {
  65.         changeClass(this.getContainer(),POSSIBLE_TYPES,this.type);
  66.         if(this.getThing()===nothing)
  67.         {
  68.             removeClassList(this.getContainer(),POSSIBLE_THINGS);
  69.             removeLabel(this.getContainer());
  70.         }
  71.     }
  72. }
  73. class Fact
  74. {
  75.     constructor (target, action, lifeTime)
  76.     {
  77.         this.target = target;
  78.         this.birth = boy.age;
  79.         this.lifeTime = lifeTime;
  80.         this.explode = action;
  81.         facts.push(this);
  82.     }
  83.     evolve()
  84.     {
  85.         if (this.lifeTime--<=0)
  86.         {
  87.             this.explode.call(this.target);
  88.             kick(facts,this);
  89.         }
  90.         if (!this.target.checkExistance()) kick(facts,this);
  91.     }
  92. }
  93. class Thing
  94. {
  95.     constructor(cell,props)
  96.     {
  97.         this.cell = cell;
  98.         this.gotHit = false;
  99.         if(!!props) Object.entries(props).forEach(prop => this[prop[0]] = prop[1]);
  100.         things.push(this);
  101.     }
  102.     checkExistance() {return (things.indexOf(this)!==-1);}
  103.     suffer(damage)
  104.     {
  105.         damage = damage || 1;
  106.         if (this.state==="waiting") damage = Math.ceil(damage/2);
  107.         logs.add(`${this.name} получил ${damage} повреждений,${(this.state==="waiting")?" 50% заблокировано,":""} осталось ${this.hp} жизней.`);
  108.         this.set("hp",this.hp-damage);
  109.         this.state = "recovering";
  110.         this.gotHit = true;
  111.         if (this.hp<=0) this.die();
  112.     }
  113.     respawn()
  114.     {
  115.         kick(things,this);
  116.         this.cell.addThing(this.owner.constructor);
  117.     }
  118.     die()
  119.     {
  120.         kick(things,this);
  121.         if (!!this.body) new Fact(this.cell.addThing(this.body,{owner:this}),this.respawn,dice(this.hp*this.xpPrice,this.hp*this.xpPrice*3,"low"));
  122.         logs.add(this.necrolog);
  123.         boy.getXp(this.xpPrice);
  124.         this.hp=0;
  125.     }
  126.     set(k, v)
  127.     {
  128.         this[k]=v;
  129.         if (k===this.labelName) this.label = v;
  130.         return this;
  131.     }
  132.     updateSelf()
  133.     {
  134.         changeClass(this.cell.getContainer(),POSSIBLE_THINGS,this.type);
  135.         if(!!this.dir) {
  136.             document.getElementById("boyCell").style.transform = `rotate(${iLoveCssDegrees}deg)`
  137.             changeClass(this.cell.getContainer(), POSSIBLE_DIRS, this.dir);
  138.         }
  139.         if(!!this.state)
  140.             changeClass(this.cell.getContainer(),POSSIBLE_STATES,this.state);
  141.         if(!!this.label)
  142.             changeLabel(this.cell.getContainer(), this.label);
  143.         else removeLabel(this.cell.getContainer());
  144.         if(this.gotHit)
  145.         {
  146.             flashClass(this.cell.getContainer(),"red-pulse");
  147.             this.gotHit = false;
  148.         }
  149.     }
  150.     linkLabel(lbl)
  151.     {
  152.         this.labelName = lbl;
  153.         this.label = this[lbl];
  154.     }
  155. }
  156. class Tree extends Thing
  157. {
  158.     constructor(cell,props)
  159.     {
  160.         super(cell,props);
  161.         this.chops = 0;
  162.         this.body=Stump;
  163.     }
  164.     checkNumberOfChops()
  165.     {
  166.         if (this.chops/6===this.hp) this.die();
  167.         else boy.suffer(dice(5,15,"flat"));
  168.         this.chops=0;
  169.     }
  170.     getChoppedGenerator(multiplicator)
  171.     {
  172.         return () =>
  173.         {
  174.             let fact = facts.find(fact=>fact.target===this) || new Fact(this,this.checkNumberOfChops,1);
  175.             fact.lifeTime=1;
  176.             fact.target.chops+=6/multiplicator;
  177.             this.gotHit = true;
  178.         }
  179.     }
  180. }
  181. class AppleTree extends Tree
  182. {
  183.     constructor(cell,props)
  184.     {
  185.         super(cell,props);
  186.         this.type = "apple-tree";
  187.         this.hp = dice(1,100,"low");
  188.         this.linkLabel("hp");
  189.         this.xpPrice = 5;
  190.         this.getHit=this.getChoppedGenerator(1);
  191.         this.name="Яблоня";
  192.         this.description = `Яблоня с <b>${this.hp}</b> яблоками. Чтобы срубить её и заполучить яблоки, нужно ударить по ней столько раз, сколько на ней яблок. Ошибешься - прилетит веткой.`;
  193.         this.necrolog = `Я срубил яблоню с ${this.hp} яблоками.`;
  194.     }
  195. }
  196. class RedCherryTree extends Tree
  197. {
  198.     constructor(cell,props)
  199.     {
  200.         super(cell,props);
  201.         this.type = "red-cherry-tree";
  202.         this.hp = dice(1,10,"high");
  203.         this.linkLabel("hp");
  204.         this.xpPrice = 10;
  205.         this.getHit=this.getChoppedGenerator(2);
  206.         this.name="Красная вишня";
  207.         this.description = `Вишневое дерево с <b>${this.hp}</b> гроздьями по 2 красные вишни. Чтобы срубить её и заполучить ягоды, нужно ударить по ней столько раз, сколько на ней вишен. Ошибешься - прилетит веткой.`;
  208.         this.necrolog = `Я срубил вишневое дерево с ${this.hp*2} красными вишнями.`;
  209.     }
  210. }
  211. class YellowCherryTree extends Tree
  212. {
  213.     constructor(cell,props)
  214.     {
  215.         super(cell,props);
  216.         this.type = "yellow-cherry-tree";
  217.         this.hp = dice(1,10,"high");
  218.         this.linkLabel("hp");
  219.         this.xpPrice = 15;
  220.         this.getHit=this.getChoppedGenerator(3);
  221.         this.name="Желтая вишня";
  222.         this.description = `Вишневое дерево с <b>${this.hp}</b> гроздьями по 3 желтые вишни. Чтобы срубить её и заполучить ягоды, нужно ударить по ней столько раз, сколько на ней вишен. Ошибешься - прилетит веткой.`;
  223.         this.necrolog = `Я срубил вишневое дерево с ${this.hp*3} желтыми вишнями.`;
  224.     }
  225. }
  226. class Stump extends Thing
  227. {
  228.     constructor(cell,props)
  229.     {
  230.         super(cell,props);
  231.         this.type = "stump";
  232.         this.hp = 10;
  233.         this.xpPrice = 1;
  234.         this.getHit=this.suffer;
  235.         this.name="Пень";
  236.         this.description = `Когда-то здесь стояла <b>${this.owner.name}</b>, остался только пенёк. Его можно срубить за 10 ударов, если он мешает проходу. Но лучше оставить его в покое и скоро здесь вырастет новое дерево.`;
  237.         this.necrolog = `Я зачем-то срубил пень.`;
  238.     }
  239. }
  240.  
  241. const cells = Array.from({length:100}, (v,x)=>Array.from({length:100}, (v,y)=>new Cell(x,y)));;
  242. const things = [];
  243. const facts = [];
  244. const logs = [];
  245.  
  246. logs.add = line => logs.unshift(`(ход: ${boy.age}) `+ line);
  247.  
  248. const nothing = new Thing(cells[0][0],{description: "Ничего."});
  249.  
  250. const boy = new Thing(cells[51][51],{
  251.     type: "boy",
  252.     dir: "S",
  253.     state: "walking",
  254.     name: "Я",
  255.     necrolog: "Я умер.",
  256.     body: "deadBoy",
  257.     hp: 30,
  258.     xp:0,
  259.     age: 0,
  260.     xpPrice: 0});
  261.  
  262. boy.move = dir =>
  263. {
  264.     if (boy.state==="recovering") return boy.set("state","walking");
  265.     switch (boy.dir+"->"+dir)
  266.     {
  267.         case "S->E": case "E->N": case "N->W": case "W->S": boy.turn("left"); break;
  268.         case "E->S": case "N->E": case "W->N": case "S->W": boy.turn("right"); break;
  269.         case "N->N": case "S->S": case "E->E": case "W->W": boy.hit(boy.cell.getNext()); break;
  270.         case "N->S": case "S->N": case "E->W": case "W->E": boy.wait(); break;
  271.     }
  272. }
  273.  
  274. boy.stepForward = () =>
  275. {
  276.     boy.set("state","walking");
  277.     boy.cell=boy.cell.getNext().getNext();
  278. }
  279.  
  280. boy.turn = side =>
  281. {
  282.     boy.set("state","walking");
  283.     switch (boy.dir+"->"+side)
  284.     {
  285.         case "N->right": case "S->left": boy.set("dir","E"); break;
  286.         case "S->right": case "N->left": boy.set("dir","W"); break;
  287.         case "W->right": case "E->left": boy.set("dir","N"); break;
  288.         case "E->right": case "W->left": boy.set("dir","S"); break;
  289.     }
  290.     switch (side) {
  291.         case "left": iLoveCssDegrees -= 90; break;
  292.         case "right": iLoveCssDegrees += 90; break;
  293.     }
  294. }
  295.  
  296. boy.wait = () =>
  297. {
  298.     boy.set("state","waiting");
  299. }
  300.  
  301. boy.hit = cell =>
  302. {
  303.     if(cell.isWall)
  304.         if(cell.checkPassable()) boy.hit(cell.getNext());
  305.         else return;
  306.     else  if (cell.checkPassable()) boy.stepForward();
  307.     else
  308.     {
  309.         boy.set("state","hitting");
  310.         cell.getThing().getHit();
  311.     }
  312. }
  313.  
  314. boy.getXp = xp =>
  315. {
  316.     boy.xp+=xp;
  317.     logs.add(`Я получил ${xp} опыта.`);
  318. }
  319.  
  320. const initWorld = (option) =>
  321. {
  322.     cells.forEach((row,x)=>row.forEach((cell,y)=>
  323.     {
  324.         if ((x===20)&&(y>=20)&&(y<=80)) cell.setType("rock");
  325.         if ((x===80)&&(y>=20)&&(y<=80)) cell.setType("rock");
  326.         if ((y===20)&&(x>=20)&&(x<=80)) cell.setType("rock");
  327.         if ((y===80)&&(x>=20)&&(x<=80)) cell.setType("rock");
  328.         if ((x===42)&&(y>=42)&&(y<=60)) cell.setType("rock");
  329.         if ((x===60)&&(y>=42)&&(y<=60)) cell.setType("rock");
  330.         if ((y===42)&&(((x>=42)&&(x<=48))||((x>=54)&&(x<=60)))) cell.setType("rock");
  331.         if ((y===60)&&(x>=42)&&(x<=60)) cell.setType("rock");
  332.     }));
  333.     let toAdd = [];
  334.     switch (option) {
  335.         case "mixed":
  336.             toAdd.push(AppleTree, RedCherryTree, YellowCherryTree);
  337.             break;
  338.         case "apples":
  339.             toAdd.push(AppleTree);
  340.             break;
  341.         case "red-cherries":
  342.             toAdd.push(RedCherryTree);
  343.             break;
  344.         case "yellow-cherries":
  345.             toAdd.push(YellowCherryTree);
  346.             break;
  347.         default:
  348.  
  349.     }
  350.     for(let i = 0; i<4;cells[dice(21,29)*2+1][43+2*i++].addThing(toAdd[dice(0,toAdd.length-1)]));
  351.     for(let i = 0; i<4;cells[dice(21,29)*2+1][53+2*i++].addThing(toAdd[dice(0,toAdd.length-1)]));
  352. }
  353.  
  354. const redraw = () =>
  355. {
  356.     facts
  357.         .forEach(fact=>fact.evolve());
  358.     cells
  359.         .slice(boy.cell.x-13,boy.cell.x+14)
  360.         .map(el=>el.slice(boy.cell.y-13,boy.cell.y+14))
  361.         .forEach(row=>row.forEach(cell=>cell.updateSelf()));
  362.     things
  363.         .filter(thing=> (thing.cell.x>=boy.cell.x-13)
  364.             &&(thing.cell.x<=boy.cell.x+13)
  365.             &&(thing.cell.y>=boy.cell.y-13)
  366.             &&(thing.cell.y<=boy.cell.y+13))
  367.         .forEach(thing=>thing.updateSelf());
  368.     updateHTML("target-description",boy.cell.getNext().getDescription());
  369.     updateHTML("log",logs.join("\r"));
  370.     updateHTML("hp",boy.hp);
  371.     updateHTML("xp",boy.xp);
  372.     updateHTML("age",++boy.age);
  373. };
  374.  
  375. document.getElementById("fWorldSetup").addEventListener('submit', evt =>
  376. {
  377.     evt.preventDefault();
  378.     initWorld(document.getElementById("inOption").value);
  379.     redraw();
  380.     removeClass(document.getElementById("gameContainer"),"hidden");
  381.     addClass(document.getElementById("setup"),"hidden");
  382.  
  383.     document.addEventListener('keydown',eKey =>
  384.     {
  385.         if (eKey.repeat) {return;}
  386.         if (!boy.checkExistance()) {return;}
  387.         switch (eKey.code)
  388.         {
  389.             case "ArrowUp": case "KeyW":
  390.             boy.move("N");
  391.             break;
  392.             case "ArrowDown": case "KeyS":
  393.             boy.move("S");
  394.             break;
  395.             case "ArrowRight": case "KeyD":
  396.             boy.move("E");
  397.             break;
  398.             case "ArrowLeft": case "KeyA":
  399.             boy.move("W");
  400.             break;
  401.             default:
  402.                 return;
  403.         }
  404.         eKey.preventDefault();
  405.         redraw();
  406.     });
  407. });
  408.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement