-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathfunction.js
5276 lines (5264 loc) · 212 KB
/
function.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"use strict";
//囧姨原版中写的一些关卡逻辑函数
//此处不用let!!!
var asyncInnerHTML=function(HTML, callBack, arg) { //异步插入HTML函数,拼接大量HTML并且执行回调函数
let temp = $n('template'),
content = temp.content,
frag = document.createDocumentFragment();
temp.innerHTML=HTML; //要加入的内容先放到这里
(function fun(Num){
Num-- ? (
frag.appendChild(content.firstChild),
setTimeout(_=>fun(Num), 0)
) : callBack(frag, arg);
})(content.childNodes.length);
};
var syncInnerHTML=function(HTML, callBack, arg) { //同步插入HTML函数,拼接大量HTML并且执行回调函数
let temp = $n('template'),
content = temp.content,
frag = document.createDocumentFragment();
temp.innerHTML=HTML; //要加入的内容先放到这里
(function fun(Num){
Num-- ? (
frag.appendChild(content.firstChild),
fun(Num)
) : callBack(frag, arg);
})(content.childNodes.length);
};
var WhichMouseButton = e=>$SEql(e.which, {
1: 1, //左键
3: 2, //右键
"default": 1,
});
var DisplayZombie = function(left=50,top=150,width=201,height=444) {
if (isNullish(oP.AZ)) return;
let AZ = Array.from(oP.AZ); //拷贝一份僵尸配置的原始数据
//过滤所有不予以预览的僵尸并予以重排
AZ = AZ.filter(data => data[0].prototype.CanDiaplay);
for(let index = AZ.length-1;index>=0;index--){
let z = AZ[index];
for(let i = oP.ZombieCurrentWeight[z[0].prototype.EName]-1;i>0;i--){
AZ.push(z);
}
}
AZ.shuffle();
//生成垂直坐标随机数
let len = AZ.length;
let randoms = [];
while(len--) randoms.push(Math.floor(top + Math.random() * height));
randoms.sort((a, b) => a - b); //从小到大排序
//生成html代码
let htmls = [];
AZ.forEach((zombie, index) => {
const proto = zombie[0].prototype;
htmls.push(proto.getDisplayHTML("", Math.floor(left + Math.random() * width) - proto.width * 0.5, randoms[index] - (proto.displayHeight ?? proto.height), 1, "block", "auto", proto.GetDTop, proto.PicArr[proto.StandGif]));
});
//渲染dom
asyncInnerHTML(htmls.join(""), frag => $("dZombie").appendChild(frag));
};
var oSelectCardGUI = {
Init() {
this.wrapDom = $("dSelectCard");
this.cardListDom = $("dPCard");
this.render();
this.initEventListeners();
this.__needCheckList__ = new Set([0, 1]);
return this;
},
render() {
let html = '';
oS.PName.forEach(plant => {
let proto = plant.prototype;
let EName = proto.EName;
let cardType = oS.CardsType[EName] ?? "0";
ArPCard.$[EName] = {
Select: 0,
PName: plant
};
html += `<div class="aCard" id="aCard_${EName}" data-jng-ename="${EName}"><img src="${proto.PicArr[0]}" class="CardType_${cardType}"><span class="cardSunNum">${proto.SunNum}</span></div>`;
});
this.cardListDom.innerHTML = html;
return this;
},
initEventListeners() {
const self = this;
const fn = {
mouseout(evt, EName) {
SetHidden($('dTitle'));
},
mousemove(evt, EName) {
self.viewCardTitle(window[EName], evt);
},
mousedown(evt, EName, ele) {
const cardType = ele.childNodes[0].className;
switch (cardType) {
//卡牌状态码0:正常卡牌,可以选择,可以撤销
case "CardType_0":
self.selectOneCard(EName);
break;
//卡牌状态码1:该卡牌禁止被选择
case "CardType_1":
oAudioManager.playAudio('UnlockLimit');
break;
//卡牌状态码2:该卡牌在选卡界面显示后强制选择,禁止被撤销
case "CardType_2":
oAudioManager.playAudio('UnlockLimit');
break;
//卡牌状态码3:该卡牌在当前关卡不推荐使用
case "CardType_3":
case "CardType_3Force": {
if (!ArPCard.$[EName].Select && cardType === "CardType_3Force") {
jngAlert.open({
'text': "携带当前植物将会提升难度,确认携带?",
'nextHandler': _ => {
self.selectOneCard(EName);
oAudioManager.playAudio("bottom");
},
'shade': 1,
});
} else {
self.selectOneCard(EName);
}
break;
}
//卡牌状态码4:推荐使用的正常卡牌,可以选择,可以撤销
case "CardType_4":
self.selectOneCard(EName);
break;
}
},
};
for (let key in fn) {
this.cardListDom.addEventListener(key, (evt) => {
const ele = evt.target;
if (ele.className === "aCard") {
fn[key](evt, ele.dataset['jngEname'], ele);
}
});
}
},
viewCardTitle(plant, event) { //选卡界面标签绘制
let ele = $("dTitle");
let proto = plant.prototype;
let cardType = oS.CardsType[proto.EName];
let str = `${proto.CName}<br>冷却时间:${proto.coolTime}秒<br>${proto.Tooltip}`;
if (cardType) {
let str2 = {
1: "不可被选择",
2: "不可撤销",
3: "不推荐使用",
"3Force": "不推荐使用",
4: "推荐使用",
} [cardType];
str += `<br><span style="color:#F00">植物${str2}!</span>`;
}
ele.innerHTML = str;
SetStyle(ele, {
left: event.clientX - EDAlloffsetLeft + 385 - 3 + "px",
top: event.clientY + 18 + "px",
visibility: "visible",
});
},
show(callback) {
const self = this;
const SelectCard = self.wrapDom;
const CardList = $("dCardList");
SetVisible(SelectCard, CardList);
oEffects.Animate(SelectCard, {
top: '0px'
}, 0.225, 'cubic-bezier(0.0, 0.0, 0.2, 1)', _ => {
SelectCard.style['pointer-events'] = 'auto';
for (let ename in oS.CardsType) {
switch (oS.CardsType[ename]) {
case 2:
self.selectOneCard(ename);
break;
case 4:
self.selectOneCard(ename);
break;
}
}
callback && callback();
}, 0.3);
return this;
},
hide(callback) {
const SelectCard = this.wrapDom;
SelectCard.style['pointer-events'] = 'none';
oEffects.Animate(SelectCard, {
top: '600px'
}, 0.195, 'cubic-bezier(0.4, 0.0, 1, 1)', () => {
SetHidden(SelectCard);
callback && callback();
});
return this;
},
/*
selectOneCard用于控制卡牌的选择或取消
如果canRemove设置为false,则当植物卡牌处于被选择状态时,调用SelectCard时不会被取消
*/
selectOneCard(EName, canRemove = true, useAudio = true) {
const CardDiv = $("aCard_" + EName);
if (!CardDiv) {
return;
}
const CardImg = CardDiv.childNodes[0];
const CardType = CardImg.className;
const CardObj = ArPCard.$[EName];
//如果卡牌当前处于未选择状态,则执行选择操作
if (!CardObj.Select) {
useAudio && oAudioManager.playAudio('tap');
//如果卡槽已经选满,则直接终止操作
if (ArPCard.SelNum > 9) return;
++ArPCard.SelNum;
CardObj.Select = 1;
if (oS.StaticCard) {
let src = CardImg.src;
//创建dCard容器
let dCard = NewEle("dCard" + EName, "div", "", {
onmousedown: () => oSelectCardGUI.selectOneCard(EName)
}, $("dCardList"));
//创建被选卡牌的图像
NewImg("", src, "width:100px;height:120px", dCard);
//创建被选卡牌阳光数值标签
NewEle("", "span", "", {
className: "cardSunNum2",
innerText: CardObj.PName.prototype.SunNum
}, dCard);
if (oS.CanSelectCard) { //过渡特效
dCard.style.visibility = 'hidden';
let rect = CardDiv.getBoundingClientRect();
let transitionDiv = NewEle("", "div", `top:${rect.top}px;left:${rect.left - EDAll.getBoundingClientRect().left + 500}px;`, {
className: 'TransitionCard'
}, EDAll);
let img = NewImg("", src, `width:100%;position:absolute;`, transitionDiv, {});
let text = NewEle("", "span", "", {
className: "cardSunNum",
innerText: CardObj.PName.prototype.SunNum
}, transitionDiv);
let time = 0.3;
let fontSize = 16;
let deltaFontSize = 18 - fontSize;
oEffects.Animate(text, {
height: "28px",
bottom: GetStyle(text, 'bottom', true) + 2 + "px",
right: "9px",
}, time, 'ease-in');
for (let i = 0; i < time; i += 0.016) {
setTimeout(function() {
text.style.fontSize = (fontSize += deltaFontSize / (time / 0.016)) + "pt";
}, i * 1000);
}
oEffects.Animate(transitionDiv, {
clip: 'rect(auto, auto, 60px, auto)',
left: '500px',
top: `${dCard.getBoundingClientRect().top}px`,
width: '100px',
height: '60px',
}, time, 'ease-in', () => {
ClearChild(transitionDiv);
dCard.style.visibility = ''; //如果设置visit的话,在游戏开始后隐藏CardList会无效
});
}
CardImg.style.top = "-42px";
}
}
//如果卡牌处于选择状态,则执行取消操作
else if (canRemove) {
oSelectCardGUI.removeOneCard(EName, useAudio);
}
},
removeOneCard(EName, useAudio = true) {
const CardDiv = $("aCard_" + EName);
if (!CardDiv) return;
const CardImg = CardDiv.childNodes[0];
const CardType = CardImg.className;
const CardObj = ArPCard.$[EName];
const func = () => {
useAudio && oAudioManager.playAudio('tap');
CardObj.Select = 0;
--ArPCard.SelNum;
ClearChild($("dCard" + EName));
CardImg.style.top = 0; //恢复选择栏的卡牌状态
};
if (CardType === "CardType_2") {
useAudio && oAudioManager.playAudio('UnlockLimit');
} else if (CardType === "CardType_4") {
jngAlert.open({
'text': "这关如果不带该植物会有点难,确认继续?",
'nextHandler': _ => {
func();
oAudioManager.playAudio("bottom");
},
'shade': 1,
});
} else {
func();
}
},
selectSeveralCards(cardArr) {
cardArr.forEach(plant => {
this.selectOneCard(plant.prototype.EName, false, false);
});
},
resetSelectedCards() {
for (let key in ArPCard.$) {
ArPCard.$[key].Select && this.selectOneCard(key);
}
oAudioManager.playAudio("Close");
},
ReadyGO() {
if (ArPCard.SelNum <= 0) {
jngAlert.open({
text: '请至少携带一株植物!',
type: 0
});
return;
}
//checkCard用于检测特定植物卡牌在当前关卡中的状态
//函数返回1:该关卡提供该卡牌,且玩家已选择该卡牌
//函数返回2:该关卡提供该卡牌,且玩家未选择该卡牌
//函数返回3:该关卡不提供该卡牌
const checkCard = (ename) => ArPCard.$[ename] ? (ArPCard.$[ename].Select ? 1 : 2) : 3;
if (this.__needCheckList__.has(0)) {
if (ArPCard.SelNum < 2 && checkCard('oImitater') === 1) {
jngAlert.open({
text: '您确定只 携带模仿者?这将不会有任何效果!',
nextHandler: _ => (this.__needCheckList__.delete(0), this.ReadyGO()),
canBtn1CloseWindow: false
});
return;
}
}
if (this.__needCheckList__.has(1)) {
let isAvailable = false;
let isSelected = false;
for (let card of ArPCard.$) {
let {
EName,
CanSpawnSun
} = card.PName.prototype;
if (CanSpawnSun) {
oS.CardsType[EName] !== 1 && (isAvailable = true);
if (card.Select) {
isSelected = true;
break;
}
}
}
if (isAvailable && !isSelected) {
jngAlert.open({
text: '您确定不携带任何生产类植物进行游戏?',
nextHandler: _ => (this.__needCheckList__.delete(1), this.ReadyGO()),
canBtn1CloseWindow: false
});
return;
}
}
jngAlert.close();
oSelectCardGUI.hide(_ => oSym.addTask(20, oS.ScrollBack, [LetsGO]));
oPropSelectGUI.hide();
$("dCardList").childNodes.forEach((ele) => {
ele.onmousedown = null;
});
},
};
var GetAP = (evtX, evtY, R, C) => { //返回鼠标所在位置的植物数据组,和鼠标指向的植物
let datas = oGd.$;
let data = [];
let pointPlant;
for(let Z = 0; Z <= PKindUpperLimit; Z++) {
let plant = datas[`${R}_${C}_${PKindTraverseOrder[Z]}`];
data[PKindTraverseOrder[Z]]=plant;
if(plant && evtX > plant.pixelLeft && evtX < plant.pixelRight && evtY > plant.pixelTop && evtY < plant.pixelBottom) {
pointPlant = plant;
}
};
return [data, pointPlant];
},
LetsGO = function() { //oS.StartGame调用前的预备代码
let CardList = $("dCardList");
let Title = $("dTitle");
SetVisible(CardList);
//初始化所有玩家选择的植物卡牌
$User._tmpARCARD[oS.Lvl] = [];
CardList.childNodes.forEach((cardEle, index) => {
let DID = cardEle.id;
let PName = ArPCard.$[DID.substring(5)].PName;
cardEle.onmousedown = event => {ChosePlant(event, index);event.stopPropagation();event.preventDefault();};
cardEle.onmouseover = _ => {
!IsMobile && SetVisible(Title);
ViewPlantTitle(oS.MCID = index);
};
cardEle.onmouseout = _ => SetHidden(Title);
cardEle.firstChild.style.top = "-60px";
ArCard.push({
DID,
PName, //构造函数
CDReady: 0,
SunReady: 0,
NeedToMonitor:true,
});
$User._tmpARCARD[oS.Lvl].push(PName);
});
EBody.onmousedown = event => GroundOnmousedown(event); //代理鼠标点击
EBody.onmousemove = event => GroundOnmousemove(event); //代理鼠标移动
for(let R = 1; R <= oS.R; R++) CustomSpecial(oBrains, R, -2); //放置大脑检测器
oPropUseGUI.Init(); //载入道具
(oS.StartGame || oS.DefaultStartGame)();
},
GroundOnmousedown = function(event) {
let [evtX, evtY] = [$User.clientX, $User.clientY];
let [[X, C], [Y, R]] = [ChosePlantX(evtX), ChosePlantY(evtY)];
let data = GetAP(evtX, evtY, R, C);
switch(oS.Chose) {
case 1:
WhichMouseButton(event) < 2 ? GrowPlant(data[0], X, Y, R, C) : CancelPlant();
break;
case -1 :
WhichMouseButton(event) < 2 ? ShovelPlant(data) : CancelShovel();
break;
}
},
GroundOnmousemove = function() {}, //鼠标移动代理,默认为空
GroundOnmousemove1 = (event, plant = ArCard[oS.ChoseCard].PName) => { //选择了植物的鼠标移动
let [evtX, evtY] = [$User.clientX, $User.clientY];
let [[X, C], [Y, R]] = [ChosePlantX(evtX), ChosePlantY(evtY)];
let [data] = GetAP(evtX, evtY, R, C);
let proto = plant.prototype;
let imgAlpha = $("MovePlantAlpha");
SetStyle($("MovePlant"), {
left: `${evtX}px`,
top: `${evtY + 20 - proto.height}px`,
});
if(proto.CanGrow(data, R, C)) {
SetStyle(imgAlpha, {
visibility: "visible",
left: X + proto.GetDX(proto) + "px",
top: Y - proto.height + proto.GetDY(R, C, data) + "px",
});
} else {
SetHidden(imgAlpha);
}
},
GroundOnmousemove2 = function() { //选择了铲子的鼠标移动
let [evtX, evtY] = [$User.clientX, $User.clientY];
let [[, C], [, R]] = [ChosePlantX(evtX), ChosePlantY(evtY)];
let [,P] = GetAP(evtX, evtY, R, C);
let ID = P ? P.id: ''; //现在鼠标所指植物id
let MPID = oS.MPID; //原先鼠标所指植物id
if(MPID !== ID) { //如果鼠标指向发生变化
let oldPointedEle = $(MPID);
let newPointedEle = $(ID);
MPID && oldPointedEle && SetAlpha(oldPointedEle.childNodes[1], 1); //恢复前一植物的透明度
(oS.MPID = ID) && $P[ID].isPlant && $P[ID].canShovel && newPointedEle && SetAlpha(newPointedEle.childNodes[1], 0.6); //改变后一植物的透明度
}
SetStyle($('tShovel'), { //移动铲子
left: evtX - 20 + 'px',
top: evtY - 38 + 'px',
});
},
ChoseShovel = function(event) {
if(oS.Chose===1||$("MovePlant")){
CancelPlant();
}
if(oS.Chose===-1){
CancelShovel();
return;
}
oAudioManager.playAudio('shovel');
oS.Chose = -1;
ClearChild($("tShovel"));
SetHidden($('imgShovel'));
// 铲子元素需要放在EDAll中,原因与MovePlant相同!
NewImg('tShovel','images/interface/Shovel.png',`left:${$User.clientX - 20}px;top:${$User.clientY - 38}px;z-index:258;`, EDAll);
GroundOnmousemove = GroundOnmousemove2;
event.preventDefault();
event.stopPropagation();
},
ShovelPlant = function(data) {
oAudioManager.playAudio("plant2");
let [plantsArg, pointedPlant] = data;
if(pointedPlant && pointedPlant.isPlant && pointedPlant.canShovel) { //鼠标有指向非障碍物的普通植物,且植物允许被铲除
//如果指向的是普通植物,或者是没有搭载其他植物的植物容器,则允许铲除
if(pointedPlant.PKind || !(plantsArg[1] || plantsArg[2])) {
pointedPlant.Die('JNG_TICKET_ShovelPlant');
oS.MPID = ""; //注销鼠标指向植物
}
}
CancelShovel();
},
CancelShovel = function() {
let MPID = oS.MPID;
oS.Chose = 0;
ClearChild($("tShovel"));
SetVisible($("imgShovel"));
MPID && $P[MPID] && SetAlpha($(MPID).childNodes[1], 1); //如果是右键取消,还需要恢复原指向植物之透明度
GroundOnmousemove = function() {};
},
ViewPlantTitle = function(index) { //战斗界面植物标签绘制
if(index === null) return;
let ele = $("dTitle");
let card = ArCard[index];
let plant = card.PName.prototype;
let str = `${plant.CName}<br>冷却时间:${plant.coolTime}秒<br>${plant.Tooltip}`;
!card.CDReady && (str += '<br><span style="color:#F00">植物正在冷却中...</span>');
!card.SunReady && (str += '<br><span style="color:#F00">你的阳光不足!</span>');
ele.innerHTML = str;
SetStyle(ele, {
top: Math.min(512, 60 * index),
left: "215px",
})
},
MonitorCard = function() { //更新植物卡牌,在种植植物、冷却完成及搜集阳光后被调用
if(oS.Chose < 1) { //如果鼠标没有拖放植物
ArCard.forEach(card => {
if(!card.NeedToMonitor){
return;
}
if(card.PName.prototype.SunNum > oS.SunNum) { //如果当前阳光不足以种植卡牌
card.SunReady = 0;
$(card.DID).childNodes[0].style.top = "-60px";
card.Readyed = false;
} else {
card.SunReady = 1;
if(card.CDReady){
$(card.DID).childNodes[0].style.top = 0;
if(!card.Readyed){
let maskFather = $(`dCDFather${card.DID}`),mask = $(`dCDMask${card.DID}`);
SetStyle(mask,{backgroundColor:"white",opacity:"1"});
SetStyle(maskFather,{transition:"",height:"auto",opacity:"0.4"});
oEffects.fadeOut(maskFather, 0.5/oSym.NowSpeed);
card.Readyed=true;
}
} //若植物的阳光和冷却都满足,则显示正常卡牌
}
});
} else { //如果鼠标正在拖放植物,则只更新数据不更新dom
ArCard.forEach(card => {
if(!card.NeedToMonitor){
return;
}
card.SunReady = Number(card.PName.prototype.SunNum < oS.SunNum);
});
}
//考虑到若玩家可能一直把鼠标放在某植物卡牌上,所以还要更新植物介绍牌
oS.MCID && ViewPlantTitle(oS.MCID);
},
BeginCool = function() { //开局首次冷却
ArCard.forEach((card, index)=>{
let proto = card.PName.prototype,
coolTime = proto.coolTime,
firstCoolTime = coolTime;
//创建冷却框
let maskFather = NewEle(`dCDFather${card.DID}`,"div","pointer-events:none;position:relative;",null,$(card.DID));
let borderStr = "20px";
if(/(oLSP|oLight)/.test(card.DID)){
borderStr = "20px 0px";//特殊边框
}
let mask = NewEle(`dCDMask${card.DID}`,"div",`background-color:black;border-radius:${borderStr};position:relative;opacity:0;`,null,maskFather);
if(proto.hasOwnProperty('firstCoolTime')) firstCoolTime = proto.firstCoolTime; //如果有默认首次冷却的,取默认值
else if(coolTime <= 7.5) firstCoolTime = 0; //如果冷却时间小于等于5s,开局0冷却
else if(coolTime >= 15 && coolTime <=25) firstCoolTime -= 5; //如果冷却在15~25s之间,开局减去5s
DoCoolTimer(index, firstCoolTime); //注册计时器
});
},
DoCoolTimer = function(index, coolTime) { //卡片冷却计时器
let card = ArCard[index];
let ele = $(card.DID);
let spanCD = NewEle(`dCD${index}`, "span", null, {className: 'spanCD'}, ele); //创建倒计时span
let maskFather = $(`dCDFather${card.DID}`),mask = $(`dCDMask${card.DID}`);
card.Readyed = false;
//重置冷却框样式
if(localStorage.JNG_TR_COOLTEXT!=="1"){
SetStyle(maskFather,{transition:"",height:"auto",opacity:"1"});
SetStyle(mask,{backgroundColor:"black",opacity:"0.4"});
}
(function fun(currentCoolTime) {
if(currentCoolTime > 0&&card.CDReady!=1) {
if(localStorage.JNG_TR_COOLTEXT==="1"){
spanCD.innerText = currentCoolTime;
}else{
$User.LowPerformanceMode?SetStyle(maskFather,{height:`${currentCoolTime/coolTime*100}%`}):SetStyle(maskFather,{transition:`height ${0.5/oSym.NowSpeed}s linear`,height:`${currentCoolTime/coolTime*100}%`});
}
//每隔0.5s字幕变化一次
//作减法时仅保留一位小数
oSym.addTask(50, fun, [(currentCoolTime - 0.5).toFixed(1)]);
} else {
SetStyle(maskFather, {transition: `height ${0.5/oSym.NowSpeed}s linear`, height: 0});
ClearChild(spanCD);
card.CDReady = 1; //标记冷却完成
MonitorCard();
}
})(coolTime);
},
ChosePlant = function(evt, index) {
index === -1 && (index = 9); //按0键可以选取第10个植物
if(index + 1 > ArCard.length) {
return;
}
if(oS.Chose===-1){
CancelShovel();
}
if(oS.Chose===1||$("MovePlant")){
CancelPlant();
return;
}
$("MovePlant") && ClearChild($("MovePlant"));
let AC = ArCard[oS.ChoseCard = index]; //当前所选卡牌数据
if (!AC.CDReady) { //冷却不达标则无法种植
oAudioManager.playAudio("buzzer");
return;
}
if (!AC.SunReady) { //阳光不达标则无法种植
SunNumWarn();
return;
}
oAudioManager.playAudio("seedlift");
let evtX = evt.clientX - EDAlloffsetLeft,
evtY = evt.clientY,
Pro = AC.PName.prototype,
len = ArCard.length,
PicArr = Pro.PicArr;
oS.Chose = 1;
if(!oS.CardKind) { //选择的是植物卡片
/*
给FightScene设置-webkit-mask属性,会导致该容器形成独立叠层上下文。
在独立叠层上下文中,元素设置的z-index只在其中有效,故会出现MovePlant元素被
迷雾等图层遮盖,而修改z-index无效的情况。
借鉴PvZ1中MovePlant元素=铲子元素>UI元素>迷雾>MovePlantAlpha>场景的顺序,
现将MovePlant元素移动为EDAll的子元素, MovePlantAlpha保持不变!
*/
let MovePlant = NewImg("MovePlant", PicArr[Pro.StaticGif], `left:${evtX}px;top:${evtY + 20 - Pro.height}px;z-index:258;`,EDAll);
SetStyle(MovePlant, Pro.ImgStyle);
EditImg(MovePlant.cloneNode(false), "MovePlantAlpha", "", { //克隆一份作为半透图
visibility: "hidden",
opacity: 0.4,
zIndex: 30,
}, FightingScene);
EditCompositeStyle({
ele: MovePlant,
addFuncs: [["translateX", 115 - Pro.width / 2 + "px"]],
option: 2,
});
} else { //选择的是僵尸卡片
NewImg("MovePlant", Pro.PicArr[Pro.StandGif], "left:" + (evtX - 0.5 * (Pro.beAttackedPointL + Pro.beAttackedPointR)) + "px;top:" + (evtY + 20 - Pro.height) + "px;z-index:258", FightingScene);
NewImg("MovePlantAlpha", Pro.PicArr[Pro.StandGif], "visibility:hidden;opacity:0.4;z-index:30", FightingScene);
}
while (len--) {
$(ArCard[len].DID).childNodes[0].style.top = "-60px"; //强制所有卡牌置灰
}
SetHidden($("dTitle"));
GroundOnmousemove = GroundOnmousemove1;
},
GrowPlant = function(data, X, Y, R, C) {
let index = oS.ChoseCard;
let card = ArCard[index];
let plant = card.PName;
let proto = plant.prototype;
let coolTime = proto.coolTime;
if (proto.CanGrow(data, R, C)) {
oAudioManager.playAudio(
oGd.$GdType[R][C] === 2 ? "plant_water" : `plant${Math.floor(1+Math.random()*2)}`
);
new plant().Birth(X, Y, R, C, data);
oS.SunNum -= proto.SunNum; //更新阳光
coolTime && (card.CDReady = 0, DoCoolTimer(index, coolTime)); //重置植物卡牌冷却
// 显示泥土动画
const effectElement = $("imgGrowSoil");
effectElement.src = GrowSoilImg;
SetStyle(effectElement, {
left: X - 30 + "px",
top: Y - 45 + "px",
zIndex: 3 * R + 1,
visibility: "visible",
});
oSym.addTask(100, SetHidden, [effectElement]);
// 种完植物后需要取消掉选中植物的状态
CancelPlant();
} else if(IsMobile||R<1||C<1||C>9){
CancelPlant();
}
},
CancelPlant = function() {
ClearChild($("MovePlant"), $("MovePlantAlpha"));
oS.Chose = 0; //标记为无植物无铲子
MonitorCard(); //更新植物卡牌
GroundOnmousemove = function() {}; //重置鼠标移动事件
},
SunNumWarn = function() {
oAudioManager.playAudio("buzzer");
oEffects.Animate(ESSunNum, 'SunNumWarn');
},
AutoProduceSun = function(num) { //这是关卡自动掉落阳光的函数
oS.DKind && AppearSun(GetX(Math.floor(1 + Math.random() * oS.C)), GetY(Math.floor(1 + Math.random() * oS.R)), num, 1);
oSym.addTask(Math.floor(9 + Math.random() * 3) * 200, AutoProduceSun, [num]);
},
AppearSun = function(X, Y, N, isDrop,...options) {
let [targetDeltaY=0,power=0,totalTime=64,XMove=24] = options;
let height, top, id = "Sun" + Math.random(),
cssText = `left:${X}px;`;
let transformScale=Math.Clamp((N-7.5)/85*1.35+0.125,0.2,1.5);
height = 39+(transformScale-0.8)*2;
//阳光为自动落下还是抛物线跳出
if(isDrop) {
cssText += `transform: scale(${transformScale})`; //阳光缩放大小
top = 0;
oSym.addTask(10, MoveDropSun, [id, Y]); //此处异步!
} else {
cssText += `transform: scale(${transformScale/2})`; //阳光缩放大小
top = Y - height - 20;
}
ArSun[id] = {id: id, N: N, C: 1, left: X, top: top, drop: isDrop};
let sunEle = NewEle(id, 'div', cssText, {onmouseover: _=>ClickSun(id), className: 'SunPic'}, EDAll);
if(!isDrop){
let maxH = 120-Math.min(30,10*Math.pow((transformScale-0.8),2))+power;
let halfTime = totalTime/2;
let vy = maxH/halfTime*2;
let a = -vy/halfTime;
let endX = Math.random()*XMove*2-XMove;
let vx = endX/(halfTime*2);
let k = 0.025;//阻尼系数
let deltaTime = $User.LowPerformanceMode?4:2;
X = X+height/2;
cssText += `;top:${top}px`;
let targetTop = top+targetDeltaY;
let effected = false;
(function fun(){
if(ArSun[id] && ArSun[id].C) {
if(!effected){
effected = true;
oEffects.Animate(sunEle,{
transform:`scale(${transformScale})`
},0.2*1/oSym.NowSpeed);
}
SetStyle(sunEle, {
left: (X = X + vx*deltaTime)+ "px",
top: (top = top - vy*deltaTime) + "px",
});
if(top<targetTop){
vy+=a*deltaTime;
if(vy<0){
vy-=k*vy*deltaTime;
}
oSym.addTask(deltaTime,fun);
}else{
SetStyle(sunEle, {
left: X + "px",
top: targetTop + "px",
});
}
}
})();
oSym.addTask(800+(halfTime*2-36), DisappearSun, [id], 3); //阳光消失
}
$User.AutoSun && oSym.addTask(100, ClickSun, [id]); //如果用户开启了自动搜集则自动搜集
return ArSun[id];
},
MoveDropSun = function(id, Y) { //正常掉落阳光
let sun = ArSun[id];
if(sun && sun.C) {
if(sun.top < Y - 53) {
$(id).style.top = (sun.top += 3) + "px";
oSym.addTask(5, MoveDropSun, [id, Y]);
} else {
oSym.addTask(800, DisappearSun, [id]);
}
}
},
DisappearSun = function(id) {
const sun = ArSun[id], ele = $(id);
sun && sun.C && (
ele.onmouseover = null,
oEffects.fadeOut(ele, undefined, _=>{
delete ArSun[id];
ClearChild(ele);
})
);
},
ClickSun = function(id) {
let dom = $(id);
if(!dom||dom.dataset.clicked){
return;
}
dom.dataset.clicked="1";
oAudioManager.playAudio("points");
let sun = ArSun[id];
sun && sun.C && (sun.C = 0, MoveClickSun(id));
},
//移动拾取的阳光到左上角
MoveClickSun = function(id) {
let obj = ArSun[id], ele = $(id),
currentX = obj.left, currentY = obj.top,
targetX = 196, targetY = -39,
distance = Math.sqrt((currentX-targetX)**2 + (currentY-targetY)**2),
time=(distance/743)/oSym.NowSpeed;
SetStyle($(id), {
transition: `left ${time}s ease,top ${time}s ease,transform ${time}s cubic-bezier(1,1,0.5,0),opacity ${time}s cubic-bezier(0,0,0.2,1)`,
left: targetX + "px", top: targetY + "px",
transform : `scale(0.25)`, opacity : 0.75,
})
.addEventListener('transitionend', _=>ArSun[id] && (oS.SunNum += obj.N, MonitorCard(), delete ArSun[id], ClearChild(ele)));
},
AutoClickSun = function() { //批量强制搜集场地上的阳光
for(let key in ArSun) {
ArSun[key].C && ClickSun(key);
}
},
AutoClickCoins = function(){
let doms = Array.from(document.getElementsByClassName("coins_collect"));
for(let key in doms){
doms[key].click();
}
},
PrepareGrowPlants = function(fun,anim=true,text=[["准备...",60,"80px"],["放置...",40,"60px"],["植物!",100,"90px"]]) {
$("dZombie").innerHTML = '';
if(!anim){
oS.isStartGame = 1;
dispatchEvent(EVENT_STARTGAME);
fun();
oS.HaveFog && oS.HaveFog.Immediate !== false && oFog.moveLeft(_=>{});
return;
}
let dom = NewEle("dReadySetPlant","div","left: 507.5px; top: 300px; transform: translateX(115px) translate(-50%, -50%);color:red;font-size:80px;opacity:0;",{
innerText:text[0][0],
className:"2px_shadow_with_shadow"
}, EDAll);
const callback = function(){
let time = 0;
oAudioManager.playAudio("readysetplant");
for(let i = 0;i<text.length;i++){
oSym.addTask(time,()=>{
dom.innerText = text[i][0];
dom.style.opacity = "";
dom.style.fontSize =text[i][2];
EditCompositeStyle({
ele: dom,
delFuncs: ['scale'],
addFuncs: [["scale", 0.95]],
option: 2,
});
oSym.addTask(1,()=>{
oEffects.Animate(dom,{
transform: EditCompositeStyle({ele: dom, delFuncs: ['scale'], addFuncs: [["scale", 1.1]]})
},0.3/oSym.NowSpeed,"ease-out");
});
});
time+=text[i][1];
}
oSym.addTask(time,()=>{
ClearChild(dom);
oS.isStartGame = 1;
dispatchEvent(EVENT_STARTGAME);
fun();
});
};
oS.HaveFog && oS.HaveFog.Immediate !== false ? oFog.moveLeft(callback) : callback();
},
CustomSpecial = (constructor, R, C) => {
return new constructor().Birth(GetX(C), GetY(R), R, C, []);
},
CustomBullet = (constructor,...arr) => {
return new constructor().Birth(...arr);
},
CheckAutoSun = function(ele) { //修改是否自动拾取阳光
//注意:这里只是修改$User.AutoSun,真正实现拾取阳光的代码在AppearSun函数里
var shifouKaiqi = ele.checked ? 1 : 0;
shifouKaiqi != $User.AutoSun && ($User.AutoSun = localStorage['JNG_TR_AUTOSUN'] = shifouKaiqi, shifouKaiqi && AutoClickSun());
},
CheckSilence = function(ele) { //修改是否静音
(oS.Silence = ele.checked) ? oAudioManager.allResMuted() : oAudioManager.allResMutedCanceled();
},
CheckCursor = function(ele={"checked":localStorage.JNG_TR_BIGCURSOR}){//游戏鼠标设置 启动游戏时的设置在index.js里
if(ele.checked){
localStorage.JNG_TR_BIGCURSOR = "1";
EBody.className = "bigCursor";
}else{
localStorage.JNG_TR_BIGCURSOR = "0";
EBody.className = "";
}
};
/* 游戏特殊地形相关 */
const oFog = {
isAttacking:false,
locked: false,
canvasVersion:false,
canvasCtx:null,
canvasFogNodes:{},
canvasRatio:1/4,
init() {
this.locked = false;
this.isAttacking = false;
this.canvasVersion = $User.LowPerformanceMode;
this.canvasFogNodes = {};
return Object.assign(this, oS.HaveFog);
},
render() {
let innerHTML = "";
let imgY = 0;
let MaxFogCId = 2 * this.leftBorder + 3;
let fogType = this.type;
function getFogPicture(){
if(fogType==="strongFog"){
return `images/interface/haze${Math.floor(Math.random() * 4)}.png`;
}
return `images/interface/fog${Math.floor(Math.random() * 4)}.png`;
}
let createImg = (id, x, y) => `<img id='Fog${id}' class='${fogType} show' src='${getFogPicture()}' style='will-change: opacity; position:absolute;left:0px;top:${y}px;pointer-events:none;transform:translateX(${x}px) rotate(${Math.random()}turn)'>`;
let ImgObjects = new Map();
let imgArrToLoad = [];
//从上至下,从左至右绘制迷雾
for(let idY = 1; idY < oS.R+1; idY++) {
for(let idX = 0, imgX = 0; idX <= MaxFogCId; idX++, imgX += 35) {
if(this.canvasVersion){
let src = getFogPicture();
let tmp;
this.canvasFogNodes[`Fog${idY}_${idX}`] = {
img:ImgObjects.get(src)??(ImgObjects.set(src,(tmp=new Image(),tmp.src=src,imgArrToLoad.push(tmp),tmp)),tmp),
x:Math.round(imgX*this.canvasRatio),
y:Math.round(imgY*this.canvasRatio),
show:true,
};
}else{
innerHTML += createImg(idY + "_" + idX, imgX, imgY);
}
}
imgY += 540/oS.R;
}
let ele = NewEle("dFog", this.canvasVersion?"canvas":"div", "will-change: left;", {innerHTML}, EDAll);
ele.className=fogType+"Div";
if(this.canvasVersion){
ele.width = 1290*this.canvasRatio;
ele.height = 600*this.canvasRatio;
ele.style.width = (MaxFogCId+2)*35;
this.canvasCtx = ele.getContext("2d");
this.canvasCtx.imageSmoothingEnabled = false;
this.renderCanvas(imgArrToLoad);
}
},
async renderCanvas(loadImages){
let ctx = this.canvasCtx;
await oLoadRes.loadElement(loadImages);
ctx.clearRect(0,0,1200,600);
let lstAlpha = ctx.globalAlpha;
let targetAlpha = this.type==="strongFog"?0.7:0.8;
for(let i of this.canvasFogNodes){
if(!i.width){
i.width = Math.round(i.img.width*this.canvasRatio);
i.height = Math.round(i.img.height*this.canvasRatio);
}
if(i.show){
if(lstAlpha != targetAlpha){
lstAlpha = ctx.globalAlpha = targetAlpha;
}
ctx.drawImage(i.img,i.x,i.y,i.width,i.height);
}else if(this.type==="strongFog"){
if(lstAlpha != 0.4){
lstAlpha = ctx.globalAlpha = 0.4;
}
ctx.drawImage(i.img,i.x,i.y,i.width,i.height);
}
}
},
moveLeft(callback) { //迷雾进入场地
// 如果迷雾被锁定则无法进行任何形式的移动
if (this.locked === true) {
return;
}
this.hasLeftStage = false;
oEffects.Animate($("dFog"), {left: GetX(oS.C - this.leftBorder) + 60 + 'px'}, 1, 'cubic-bezier(0.0, 0.0, 0.2, 1)', _ => {
callback && callback();
this.refreshTP();
this.type === 'strongFog' && this.attackPlants();
});
},
moveRight() { //迷雾被三叶草退去
let left, callback, wrap = $("dFog");
// 如果迷雾被锁定则无法进行任何形式的移动
if (this.locked === true) {
return;
}
if(this.type === 'Fog') {
left = '1290px';
this.hasLeftStage = true;
oSym.addTask(2500, this.moveLeft.bind(this));
} else {
if((this.leftBorder -= 3) > 0) {
left = GetX(oS.C - this.leftBorder) + 100 + 'px';
callback = this.refreshTP.bind(this);
} else {
left = '1290px';
this.hasLeftStage = true;
this.leftBorder = oS.HaveFog.leftBorder;
oSym.addTask(1250, this.moveLeft.bind(this));
}
}
if(this.canvasVersion){
for(let ele of this.canvasFogNodes){
ele.show=true;
}