File: first_blood.lua

package info (click to toggle)
hedgewars 0.9.25-5
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 216,312 kB
  • sloc: pascal: 52,731; ansic: 26,845; cpp: 25,427; java: 8,210; haskell: 6,753; xml: 2,950; sh: 580; objc: 113; python: 105; makefile: 26
file content (892 lines) | stat: -rw-r--r-- 35,161 bytes parent folder | download
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
--[[
A Classic Fairytale: First Blood

= SUMMARY =
Simple introduction to the most basic aspects of gameplay.
Basically a story-driven mini-tutorial. Does not replace
a real tutorial, however.

= GOAL =
To complete the various tasks the chief gives to the player.

= FLOW CHART =
This section explains how this mission is (roughly)
*supposed* to work, with a step-to-step list.
Use this to hunt down bugs or for testing.

All other missions in ACF will have the same section.

These symbols are used:
- Event
| Choice (only one of these can happen)
> End of mission
: Go to another event in the flow chart

“TBS” stands for “Turn-Based Stragegy”. It is used when the game switches from
heavily scripted events to the default turn-based stragegy gameplay. This
is not used in the first mission, however.

== Linear events ==
This is the expected course of events in chronological order.

- Introduction; movement (left/right/jump) instructions
- Player moves to mushroom
- Double jump instructions, move to flower
- Collect first crate (rope)
- Rope instructions
- Parachute crate appears in the right pit
- Player collects parachute
- Instruct player to move to mole head
| If player stopped on mole head:
    - Cut scene
    - Place girder to block off right pit
    - Spawn rope crate in left pit
    - Player must collect crate safely
    - If hurt: Reset player to mole head
| If player skipped the mole (e.g. by roping) and instead went down the pit left from the mole:
    - Different cut scene
    - Place girder to block off right pit
    - Spawn rope crate in left pit
    - Player must collect this crate
- Shoryuken crate spawns
- Player destroys all targets
- Rope challenge
    - Player chooses rope challenge difficulty
    - Crates spawn, one-by-one, while player collects them
    | If player collects all crates in time:
        - Proceed
    | If player fails to collect all crates in time:
        : Rope challenge restarts
- Deagle crate spawns
- Player collects deagle crate
- Deagle targets spawn
- Deagle targets destroyd
- Cannibal and lots of ammo crates appear
| Player kills cannibal
    > Victory
| Player moves close to cannibal
    - Many weapon crates with melee weapons spawn
    - Cut scene
    - Player kills cannibal
    > Victory

== Non-linear events ==
These events can be triggered at (theoretically) any time and interrupt
the normal flow. Obvious events like “all player hogs dead” are omitted here.

- Player hog damages princess:
    - Princess complains
- Player hog damages chief
    - Chief complains
- Player hog, Princess or Chief dead:
    > Game over
- Player hurt itself without dying:
    - Chief mocks player

]]

HedgewarsScriptLoad("/Scripts/Locale.lua")
HedgewarsScriptLoad("/Scripts/Animate.lua")

-----------------------------Variables---------------------------------
startDialogue = {}
damageAnim = {}
onShroomAnim = {}
onFlowerAnim = {}
tookParaAnim = {}
tookPunchAnim = {}
onMoleHeadAnim = {}
tookRope2Anim = {}
challengeAnim = {}
challengeFailedAnim = {}
challengeCompletedAnim = {}
beforeKillAnim = {}
closeCannim = {}
cannKilledAnim = {}
cannKilledEarlyAnim = {}
princessDamagedAnim = {}
elderDamagedAnim = {}
pastMoleHeadAnim = {}


targets = {}
crates = {}
targXdif2 = {2755, 2638, 2921, 2973, 3162, 3067, 3062, 1300}
targYdif2 = {1197, 1537, 1646, 1857, 1804, 1173, 1167, 1183}
targXdif1 = {2749, 2909, 2770, 2836, 1558, 1305}
targYdif1 = {1179, 1313, 1734, 1441, 1152, 1259}
targetPosX = {{821, 866, 789}, {614, 656, 638}, {1238, 1237, 1200}}
targetPosY = {{1342, 1347, 1326}, {1112, 1121, 1061}, {1152, 1111, 1111}}
crateNum = {6, 8}
rope2GirderX = 3245
rope2GirderY = 1190

stage = 1
cratesCollected = 0
chalTries = 0
targetsDestroyed = 0
targsWave = 1
tTime = -1
difficulty = 1

cannibalVisible = false
cannibalKilles = false
youngdamaged = false
youngKilled = false
elderDamaged = false
princessDamaged = false
elderKilled = false
princessKilled = false
rope1Taken = false
paraTaken = false
rope2Taken = false
rope2InProgress = false
punchTaken = false
canKilled = false
desertTaken = false
challengeFailed = false
deleteCrate = false
difficultyChoice = false
princessFace = "Left"
elderFace = "Left"

goals = {
  [startDialogue] = {loc("First Blood"), loc("First Steps"), loc("Press [Left] or [Right] to move around, [Enter] to jump"), 1, 4000},
  [onShroomAnim] = {loc("First Blood"), loc("A leap in a leap"), loc("Go on top of the flower") .. "|" .. loc("Hint: Hold down [M] to review the mission texts."), 1, 7000},
  [onFlowerAnim] = {loc("First Blood"), loc("Hightime"), loc("Collect the crate on the right.|Hint: Select the rope, [Up] or [Down] to aim, [Space] to fire, directional keys to move.|Ropes can be fired again in the air!"), 1, 7000},
  [tookParaAnim] = {loc("First Blood"), loc("Omnivore"), loc("Get on the head of the mole"), 1, 4000},
  [onMoleHeadAnim] = {loc("First Blood"), loc("The Leap of Faith"), loc("Use the parachute ([Space] while in air) to get the next crate"), 1, 4000},
  [tookRope2Anim] = {loc("First Blood"), loc("The Rising"), loc("Get that crate!"), 1, 4000},
  [tookPunchAnim] = {loc("First Blood"), loc("The Slaughter"), loc("Destroy the targets!|Hint: Select the Shoryuken and hit [Space]|P.S. You can use it mid-air."), 1, 5000},
  [challengeAnim] = {loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000},
  [challengeFailedAnim] = {loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000},
  [challengeCompletedAnim] = {loc("First Blood"), loc("The Ultimate Weapon"), loc("Get that crate!"), 1, 5000},
  [beforeKillAnim] = {loc("First Blood"), loc("The First Blood"), loc("Kill the cannibal!"), 1, 5000},
  [closeCannim] = {loc("First Blood"), loc("The First Blood"), loc("KILL IT!"), 1, 5000}
}
-----------------------------Animations--------------------------------
function Skipanim(anim)
  AnimSwitchHog(youngh)
  if goals[anim] ~= nil then
    ShowMission(unpack(goals[anim]))
  end
  if anim == startDialogue then
    AnimSetGearPosition(youngh, 1952, 1365)
    HogTurnLeft(princess, false)
  end
end

function SkipDamageAnim(anim)
  SwitchHog(youngh)
  AnimSetInputMask(0xFFFFFFFF)
end

function SkipOnShroom()
  Skipanim(onShroomAnim)
  AnimSetGearPosition(elderh, 2700, 1278)
end

function AnimationSetup()
  AddSkipFunction(damageAnim, SkipDamageAnim, {damageAnim})
  table.insert(damageAnim, {func = AnimWait, args = {youngh, 500}, skipFunc = Skipanim, skipArgs = damageAnim})
  table.insert(damageAnim, {func = AnimSay, args = {elderh, loc("Watch your steps, young one!"), SAY_SAY, 2000}})
  table.insert(damageAnim, {func = AnimGearWait, args = {youngh, 500}})

  AddSkipFunction(princessDamagedAnim, SkipDamageAnim, {princessDamagedAnim})
  table.insert(princessDamagedAnim, {func = AnimWait, args = {princess, 500}, skipFunc = Skipanim, skipArgs = princessDamagedAnim})
  table.insert(princessDamagedAnim, {func = AnimSay, args = {princess, loc("Why do men keep hurting me?"), SAY_THINK, 3000}})
  table.insert(princessDamagedAnim, {func = AnimGearWait, args = {youngh, 500}})

  AddSkipFunction(elderDamagedAnim, SkipDamageAnim, {elderDamagedAnim})
  table.insert(elderDamagedAnim, {func = AnimWait, args = {elderh, 500}, skipFunc = Skipanim, skipArgs = elderDamagedAnim})
  table.insert(elderDamagedAnim, {func = AnimSay, args = {elderh, loc("Violence is not the answer to your problems!"), SAY_SAY, 3000}})
  table.insert(elderDamagedAnim, {func = AnimGearWait, args = {youngh, 500}})

  AddSkipFunction(startDialogue, Skipanim, {startDialogue})
  table.insert(startDialogue, {func = AnimWait, args = {youngh, 3500}, skipFunc = Skipanim, skipArgs = startDialogue})
  table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("Once upon a time, on an island with great natural resources, lived two tribes in heated conflict..."),  5000}})
  table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("One tribe was peaceful, spending their time hunting and training, enjoying the small pleasures of life..."), 5000}})
  table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("The other one were all cannibals, spending their time eating the organs of fellow hedgehogs..."), 5000}})
  table.insert(startDialogue, {func = AnimCaption, args = {youngh, loc("And so it began..."), 1000}})
  table.insert(startDialogue, {func = AnimSay, args = {elderh, loc("What are you doing at a distance so great, young one?"), SAY_SHOUT, 4000}})
  table.insert(startDialogue, {func = AnimSay, args = {elderh, loc("Come closer, so that your training may continue!"), SAY_SHOUT, 6000}})
  table.insert(startDialogue, {func = AnimSay, args = {youngh, loc("This is it! It's time to make Fell From Heaven fall for me..."), SAY_THINK, 6000}})
  table.insert(startDialogue, {func = AnimJump, args = {youngh, "long"}})
  table.insert(startDialogue, {func = AnimTurn, args = {princess, "Right"}})
  table.insert(startDialogue, {func = AnimSwitchHog, args = {youngh}})
  table.insert(startDialogue, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("First Steps"), loc("Press [Left] or [Right] to move around, [Enter] to jump"), 1, 4000}})

  AddSkipFunction(onShroomAnim, SkipOnShroom, {onShroomAnim})
  table.insert(onShroomAnim, {func = AnimSay, args = {elderh, loc("I can see you have been training diligently."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = onShroomAnim})
  table.insert(onShroomAnim, {func = AnimSay, args = {elderh, loc("The wind whispers that you are ready to become familiar with tools, now..."), SAY_SAY, 4000}})
  table.insert(onShroomAnim, {func = AnimSay, args = {elderh, loc("Open that crate and we will continue!"), SAY_SAY, 5000}})
  table.insert(onShroomAnim, {func = AnimMove, args = {elderh, "Right", 2700, 0}})
  table.insert(onShroomAnim, {func = AnimTurn, args = {elderh, "Left"}})
  table.insert(onShroomAnim, {func = AnimSay, args = {princess, loc("He moves like an eagle in the sky."), SAY_THINK, 4000}})
  table.insert(onShroomAnim, {func = AnimSwitchHog, args = {youngh}})
  table.insert(onShroomAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("A leap in a leap"), loc("Go on top of the flower") .. "|" .. loc("Hint: Press [Esc] to review the mission texts."), 1, 7000}})

  AddSkipFunction(onFlowerAnim, Skipanim, {onFlowerAnim})
  table.insert(onFlowerAnim, {func = AnimSay, args = {elderh, loc("See that crate farther on the right?"), SAY_SAY, 4000}})
  table.insert(onFlowerAnim, {func = AnimSay, args = {elderh, loc("Swing, Leaks A Lot, on the wings of the wind!"), SAY_SAY, 6000}})
  table.insert(onFlowerAnim, {func = AnimSay, args = {princess, loc("His arms are so strong!"), SAY_THINK, 4000}})
  table.insert(onFlowerAnim, {func = AnimSwitchHog, args = {youngh}})
  table.insert(onFlowerAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("Hightime"), loc("Collect the crate on the right.|Hint: Select the rope, [Up] or [Down] to aim, [Space] to fire, directional keys to move.|Ropes can be fired again in the air!"), 1, 7000}})

  AddSkipFunction(tookParaAnim, Skipanim, {tookParaAnim})
  table.insert(tookParaAnim, {func = AnimGearWait, args = {youngh, 1000}, skipFunc = Skipanim, skipArgs = tookParaAnim})
  table.insert(tookParaAnim, {func = AnimSay, args = {elderh, loc("Use the rope to get on the head of the mole, young one!"), SAY_SHOUT, 4000}})
  table.insert(tookParaAnim, {func = AnimSay, args = {elderh, loc("Worry not, for it is a peaceful animal! There is no reason to be afraid..."), SAY_SHOUT, 5000}})
  table.insert(tookParaAnim, {func = AnimSay, args = {elderh, loc("We all know what happens when you get frightened..."), SAY_SAY, 4000}})
  table.insert(tookParaAnim, {func = AnimSay, args = {youngh, loc("So humiliating..."), SAY_SAY, 4000}})
  table.insert(tookParaAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("Omnivore"), loc("Get on the head of the mole"), 1, 4000}})
  table.insert(tookParaAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(onMoleHeadAnim, Skipanim, {onMoleHeadAnim})
  table.insert(onMoleHeadAnim, {func = AnimSay, args = {elderh, loc("Perfect! Now try to get the next crate without hurting yourself!"), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = onMoleHeadAnim})
  table.insert(onMoleHeadAnim, {func = AnimSay, args = {elderh, loc("The giant umbrella from the last crate should help break the fall."), SAY_SAY, 4000}})
  table.insert(onMoleHeadAnim, {func = AnimSay, args = {princess, loc("He's so brave..."), SAY_THINK, 4000}})
  table.insert(onMoleHeadAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Leap of Faith"), loc("Use the parachute ([Space] while in air) to get the next crate"), 1, 4000}})
  table.insert(onMoleHeadAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(pastMoleHeadAnim, Skipanim, {pastMoleHeadAnim})
  table.insert(pastMoleHeadAnim, {func = AnimSay, args = {elderh, loc("I see you have already taken the leap of faith."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = pastMoleHeadAnim})
  table.insert(pastMoleHeadAnim, {func = AnimSay, args = {elderh, loc("Get that crate!"), SAY_SAY, 4000}})
  table.insert(pastMoleHeadAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(tookRope2Anim, Skipanim, {tookRope2Anim})
  table.insert(tookRope2Anim, {func = AnimSay, args = {elderh, loc("Impressive...you are still dry as the corpse of a hawk after a week in the desert..."), SAY_SAY, 5000}, skipFunc = Skipanim, skipArgs = tookRope2Anim})
  table.insert(tookRope2Anim, {func = AnimSay, args = {elderh, loc("You probably know what to do next..."), SAY_SAY, 4000}})
  table.insert(tookRope2Anim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Rising"), loc("Get that crate!"), 1, 4000}})
  table.insert(tookRope2Anim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(tookPunchAnim, Skipanim, {tookPunchAnim})
  table.insert(tookPunchAnim, {func = AnimSay, args = {elderh, loc("It is time to practice your fighting skills."), SAY_SAY, 4000}})
  table.insert(tookPunchAnim, {func = AnimSay, args = {elderh, loc("Imagine those targets are the wolves that killed your parents! Take your anger out on them!"), SAY_SAY, 5000}})
  table.insert(tookPunchAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Slaughter"), loc("Destroy the targets!|Hint: Select the Shoryuken and hit [Space]|P.S. You can use it mid-air."), 1, 5000}})
  table.insert(tookPunchAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(challengeAnim, Skipanim, {challengeAnim})
  table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("I hope you are prepared for a small challenge, young one."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = challengeAnim})
  table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("Your movement skills will be evaluated now."), SAY_SAY, 4000}})
  table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("Collect all the crates, but remember, our time in this life is limited!"), SAY_SAY, 4000}})
  table.insert(challengeAnim, {func = AnimSay, args = {elderh, loc("How difficult would you like it to be?")}})
  table.insert(challengeAnim, {func = AnimSwitchHog, args = {youngh}})
  table.insert(challengeAnim, {func = AnimWait, args = {youngh, 500}})

  AddSkipFunction(challengeFailedAnim, Skipanim, {challengeFailedAnim})
  table.insert(challengeFailedAnim, {func = AnimSay, args = {elderh, loc("Hmmm...perhaps a little more time will help."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = challengeFailedAnim})
  table.insert(challengeFailedAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000}})
  table.insert(challengeFailedAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(challengeCompletedAnim, Skipanim, {challengeCompletedAnim})
  table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("The spirits of the ancestors are surely pleased, Leaks A Lot."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = challengeCompletedAnim})
  table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("You have proven yourself worthy to see our most ancient secret!"), SAY_SAY, 4000}})
  table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("The weapon in that last crate was bestowed upon us by the ancients!"), SAY_SAY, 4000}})
  table.insert(challengeCompletedAnim, {func = AnimSay, args = {elderh, loc("Use it with precaution!"), SAY_SAY, 4000}})
  table.insert(challengeCompletedAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The Ultimate Weapon"), loc("Get that crate!"), 1, 5000}})
  table.insert(challengeCompletedAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(beforeKillAnim, Skipanim, {beforeKillAnim})
  table.insert(beforeKillAnim, {func = AnimWait, args = {elderh, 100}})
  table.insert(beforeKillAnim, {func = AnimSay, args = {elderh, loc("What do my faulty eyes observe? A spy!"), SAY_SHOUT, 4000}, skipFunc = Skipanim, skipArgs = beforeKillAnim})
  table.insert(beforeKillAnim, {func = AnimFollowGear, args = {cannibal}})
  table.insert(beforeKillAnim, {func = AnimWait, args = {cannibal, 1000}})
  table.insert(beforeKillAnim, {func = AnimSay, args = {elderh, loc("Destroy him, Leaks A Lot! He is responsible for the deaths of many of us!"), SAY_SHOUT, 4000}})
  table.insert(beforeKillAnim, {func = AnimSay, args = {cannibal, loc("Oh, my!"), SAY_THINK, 4000}})
  table.insert(beforeKillAnim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The First Blood"), loc("Kill the cannibal!"), 1, 5000}})
  table.insert(beforeKillAnim, {func = AnimSwitchHog, args = {youngh}})

  AddSkipFunction(closeCannim, Skipanim, {closeCannim})
  table.insert(closeCannim, {func = AnimSay, args = {elderh, loc("I see you would like his punishment to be more...personal..."), SAY_SAY, 4000}, skipFunc = Skipanim, skipArgs = closeCannim})
  table.insert(closeCannim, {func = AnimSay, args = {cannibal, loc("I'm certain that this is a misunderstanding, fellow hedgehogs!"), SAY_SAY, 4000}})
  table.insert(closeCannim, {func = AnimSay, args = {cannibal, loc("If only I were given a chance to explain my being here..."), SAY_SAY, 4000}})
  table.insert(closeCannim, {func = AnimSay, args = {elderh, loc("Do not let his words fool you, young one! He will stab you in the back as soon as you turn away!"), SAY_SAY, 6000}})
  table.insert(closeCannim, {func = AnimSay, args = {elderh, loc("Here...pick your weapon!"), SAY_SAY, 5000}})
  table.insert(closeCannim, {func = AnimShowMission, args = {youngh, loc("First Blood"), loc("The First Blood"), loc("KILL IT!"), 1, 5000}})
  table.insert(closeCannim, {func = AnimSwitchHog, args = {youngh}})

  table.insert(cannKilledAnim, {func = AnimSay, args = {elderh, loc("Yes, yeees! You are now ready to enter the real world!"), SAY_SHOUT, 6000}})

  table.insert(cannKilledEarlyAnim, {func = AnimSay, args = {elderh, loc("What?! A cannibal? Here? There is no time to waste! Come, you are prepared."), SAY_SHOUT, 4000}})
end
-----------------------------Events------------------------------------
function CheckNeedToTurn(gear)
  if youngKilled then
    return false
  end
  if gear == princess then
    if princessKilled ~= true then
      if (GetX(princess) > GetX(youngh) and princessFace == "Right")
        or (GetX(princess) < GetX(youngh) and princessFace == "Left") then
      --if (GetX(princess) > GetX(youngh))
       -- or (GetX(princess) < GetX(youngh)) then
        return true
      end
    end
  else
    if elderKilled ~= true then
      if (GetX(elderh) > GetX(youngh) and elderFace == "Right")
        or (GetX(elderh) < GetX(youngh) and elderFace == "Left") then
        return true
      end
    end
  end
  return false
end

function DoNeedToTurn(gear)
  if gear == princess and not princessDamaged then
    if GetX(princess) > GetX(youngh) then
      HogTurnLeft(princess, true)
      princessFace = "Left"
    elseif GetX(princess) < GetX(youngh) then
      HogTurnLeft(princess, false)
      princessFace = "Right"
    end
  elseif gear == elderh and not elderDamaged then
    if GetX(elderh) > GetX(youngh) then
      HogTurnLeft(elderh, true)
      elderFace = "Left"
    elseif GetX(elderh) < GetX(youngh) then
      HogTurnLeft(elderh, false)
      elderFace = "Right"
    end
  end
end

function CheckDamage()
  return youngdamaged and StoppedGear(youngh)
end

function DoOnDamage()
  AddAnim(damageAnim)
  if rope2InProgress and not rope2Taken then
    AnimSetGearPosition(youngh, 3040, 1221)
  end
  youngdamaged = false
  AddFunction({func = ResetTurnTime, args = {}})
end

function CheckDeath()
  return youngKilled
end

function DoDeath()
  RemoveEventFunc(CheckKilledOthers)
  RemoveEventFunc(CheckDamage)
  RemoveEventFunc(CheckDamagedOthers)
  FinishThem()
  ShowMission(loc("First Blood"), loc("The wasted youth"), loc("Leaks A Lot gave his life for his tribe! He should have survived!"), 2, 4000)
end

function CheckDamagedOthers()
  return (princessDamaged and StoppedGear(princess)) or (elderDamaged and StoppedGear(elderh))
end

function CheckKilledOthers()
  return princessKilled or elderKilled
end

function DoOnDamagedOthers()
  if princessDamaged then
    AddAnim(princessDamagedAnim)
  end
  if elderDamaged then
    AddAnim(elderDamagedAnim)
  end
  elderDamaged = false
  princessDamaged = false
  AddFunction({func = ResetTurnTime, args = {}})
end

function DoKilledOthers()
  AddCaption(loc("After Leaks A Lot betrayed his tribe, he joined the cannibals..."))
  FinishThem()
end

function CheckMovedUntilJump()
   return GetX(youngh) >= 2343
end

function DoMovedUntilJump()
  ShowMission(loc("First Blood"), loc("Step By Step"), loc("Hint: Double Jump - Press [Backspace] twice"), -amSkip, 0)
  AddEvent(CheckOnShroom, {}, DoOnShroom, {}, 0)
end

function CheckOnShroom()
  return GetX(youngh) >= 2461 and StoppedGear(youngh)
end

function DoOnShroom()
  ropeCrate1 = SpawnSupplyCrate(2751, 1194, amRope, 100)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(onShroomAnim)
  AddEvent(CheckOnFlower, {}, DoOnFlower, {}, 0)
end

function CheckOnFlower()
  return rope1Taken and StoppedGear(youngh)
end

function DoOnFlower()
  AddAmmo(youngh, amRope, 100)
  paraCrate = SpawnSupplyCrate(3245, 1758, amParachute, 100)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(onFlowerAnim)
  AddEvent(CheckTookParaCrate, {}, DoTookParaCrate, {}, 0)
end

function CheckTookParaCrate()
  return paraTaken and StoppedGear(youngh)
end

function DoTookParaCrate()
  AddAmmo(youngh, amParachute, 100)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(tookParaAnim)
  AddEvent(CheckOnMoleHead, {}, DoOnMoleHead, {}, 0)
  AddEvent(CheckPastMoleHead, {}, DoPastMoleHead, {}, 0)
end

function CheckOnMoleHead()
  x = GetX(youngh)
  return x >= 3005 and x <= 3126 and StoppedGear(youngh)
end

function CheckPastMoleHead()
  x = GetX(youngh)
  y = GetY(youngh)
  return x < 3005 and y > 1500 and StoppedGear(youngh)
end

function DoPastMoleHead()
  -- Initiate parachute challenge
  RemoveEventFunc(CheckOnMoleHead)
  ropeCrate2 = SpawnSupplyCrate(2782, 1720, amRope, 100)
  rope2InProgress = true
  AddAmmo(youngh, amRope, 0)
  SetGearMessage(CurrentHedgehog, 0)
  -- Block the way to the hole to the right, since the player loses the rope for this section
  PlaceGirder(rope2GirderX, rope2GirderY, 6)
  AddAnim(pastMoleHeadAnim)
  AddEvent(CheckTookRope2, {}, DoTookRope2, {}, 0)
end

function DoOnMoleHead()
  -- Initiate parachute challenge
  RemoveEventFunc(CheckPastMoleHead)
  ropeCrate2 = SpawnSupplyCrate(2782, 1720, amRope, 100)
  rope2InProgress = true
  AddAmmo(youngh, amRope, 0)
  SetGearMessage(CurrentHedgehog, 0)
  -- Block the way to the hole to the right, since the player loses the rope for this section
  PlaceGirder(rope2GirderX, rope2GirderY, 6)
  AddAnim(onMoleHeadAnim)
  AddEvent(CheckTookRope2, {}, DoTookRope2, {}, 0)
end

function CheckTookRope2()
  return rope2Taken and StoppedGear(youngh)
end

function DoTookRope2()
  AddAmmo(youngh, amRope, 100)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(tookRope2Anim)
  punchCrate = SpawnSupplyCrate(2460, 1321, amFirePunch, 100)
  AddEvent(CheckTookPunch, {}, DoTookPunch, {})
end

function CheckTookPunch()
  return punchTaken and StoppedGear(youngh)
end

function DoTookPunch()
  AddAmmo(youngh, amFirePunch, 100)
  AddAmmo(youngh, amRope, 0)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(tookPunchAnim)
  targets[1] = AddGear(1594, 1185, gtTarget, 0, 0, 0, 0)
  targets[2] = AddGear(2188, 1314, gtTarget, 0, 0, 0, 0)
  targets[3] = AddGear(1961, 1318, gtTarget, 0, 0, 0, 0)
  targets[4] = AddGear(1961, 1200, gtTarget, 0, 0, 0, 0)
  targets[5] = AddGear(1800, 900, gtTarget, 0, 0, 0, 0)
  AddEvent(CheckTargDestroyed, {}, DoTargDestroyed, {}, 0)
end

function CheckTargDestroyed()
  return targetsDestroyed == 5 and StoppedGear(youngh)
end

function DoTargDestroyed()
  AddAmmo(youngh, amFirePunch, 0)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(challengeAnim)
  targetsDestroyed = 0
  AddFunction({func = SetChoice, args = {}})
  ropeCrate3 = SpawnSupplyCrate(2000, 1200, amRope, 100)
  AddEvent(CheckTookRope3, {}, AddAmmo, {youngh, amRope, 100}, 0)
  AddEvent(CheckCratesColled, {}, DoCratesColled, {}, 0)
  AddEvent(CheckChallengeWon, {}, DoChallengeWon, {}, 0)
  AddEvent(CheckTimesUp, {}, DoTimesUp, {}, 1)
  -- Remove up the old mole blockade from the parachute challenge
  EraseSprite(rope2GirderX, rope2GirderY, sprAmGirder, 6)
end

function DoChoice()
  PlaySound(sndPlaced)
  difficultyChoice = false
  AnimSetInputMask(0xFFFFFFFF)
  StartChallenge(120000 + chalTries * 20000)
end

function CheckCratesColled()
  return cratesCollected == crateNum[difficulty]
end

function DoCratesColled()
  RemoveEventFunc(CheckTimesUp)
  SetTurnTimeLeft(MAX_TURN_TIME)
  AddCaption(loc("As the challenge was completed, Leaks A Lot set foot on the ground..."))
end

function CheckChallengeWon()
  return cratesCollected == crateNum[difficulty] and StoppedGear(youngh)
end

function DoChallengeWon()
  desertCrate = SpawnSupplyCrate(1240, 1212, amDEagle, 100)
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(challengeCompletedAnim)
  AddEvent(CheckDesertColled, {}, DoDesertColled, {}, 0)
end

function CheckTookRope3()
  return rope3Taken
end

function CheckTimesUp()
  return TurnTimeLeft == 100
end

function DoTimesUp()
  challengeFailed = true
  deleteCrate = true
  DeleteGear(crates[1])
  SetTurnTimeLeft(MAX_TURN_TIME)
  AddCaption(loc("And so happened that Leaks A Lot failed to complete the challenge! He landed, pressured by shame ..."))
  AddEvent(CheckChallengeFailed, {}, DoChallengeFailed, {}, 0)
end

function CheckChallengeFailed()
  return challengeFailed and StoppedGear(youngh)
end

function DoChallengeFailed()
  challengeFailed = false
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(challengeFailedAnim)
  chalTries = chalTries + 1
  difficulty = 1
  AddFunction({func = SetChoice, args = {}})
end

function CheckDesertColled()
  return desertTaken and StoppedGear(youngh)
end

function DoDesertColled()
  AddAmmo(youngh, amDEagle, 100)
  PutTargets(1)
  AddEvent(CheckTargetsKilled, {}, DoTargetsKilled, {}, 1)
  AddEvent(CheckCannibalKilled, {}, DoCannibalKilledEarly, {}, 0)
  ShowMission(loc("First Blood"), loc("The Bull's Eye"), loc("Destroy the targets!|Hint: [Up], [Down] to aim, [Space] to shoot"), 1, 5000)
end

function CheckTargetsKilled()
  return targetsDestroyed == 3 and StoppedGear(youngh)
end

function DoTargetsKilled()
  targetsDestroyed = 0
  targsWave = targsWave + 1
  if targsWave > 3 then
    RemoveEventFunc(CheckTargetsKilled)
    RestoreHog(cannibal)
    cannibalVisible = true
    SetGearMessage(CurrentHedgehog, 0)
    AddAnim(beforeKillAnim)
    AddEvent(CheckCloseToCannibal, {}, DoCloseToCannibal, {}, 0)
    AddEvent(CheckCannibalKilled, {}, DoCannibalKilled, {}, 0)
  else
    PutTargets(targsWave)
  end
end

function CheckCloseToCannibal()
  if CheckCannibalKilled() then
    return false
  end
  return math.abs(GetX(cannibal) - GetX(youngh)) <= 400 and StoppedGear(youngh)
end

function DoCloseToCannibal()
  SetGearMessage(CurrentHedgehog, 0)
  AddAnim(closeCannim)
  AddFunction({func = SpawnSupplyCrate, args = {targetPosX[1][1], targetPosY[1][1], amWhip}})
  AddFunction({func = SpawnSupplyCrate, args = {targetPosX[1][2], targetPosY[1][2], amBaseballBat}})
  AddFunction({func = SpawnSupplyCrate, args = {targetPosX[1][3], targetPosY[1][3], amHammer}})
end

function CheckCannibalKilled()
  return cannibalKilled and StoppedGear(youngh)
end

function DoCannibalKilled()
  AddAnim(cannKilledAnim)
  if not progress then
    SaveCampaignVar("Progress", "1")
  end
end

function DoCannibalKilledEarly()
  AddAnim(cannKilledEarlyAnim)
  DoCannibalKilled()
end

-----------------------------Misc--------------------------------------
function StartChallenge(time)
  cratesCollected = 0
  PutCrate(1)
  SetTurnTimeLeft(time)
  ShowMission(loc("First Blood"), loc("The Crate Frenzy"), loc("Collect the crates within the time limit!|If you fail, you'll have to try again."), 1, 5000)
end

function ChoiceDialog()
  local dstr
  if difficulty == 2 then
    dstr = loc("Difficulty: Hard")
  else
    dstr = loc("Difficulty: Easy")
  end
  ShowMission(loc("First Blood"), loc("The Torment"),
    loc("Your next task is to collect some crates by using the rope!") .. "|" ..
    loc("Press [Left] and [Right] to change the difficulty.") .. "| |" ..
    dstr .. "| |" ..
    loc("Press [Attack] to begin."),
    0, 9999000, true)
end

function SetChoice()
  AnimSetInputMask(0)
  difficultyChoice = true
  ChoiceDialog()
end

function SetTime(time)
  SetTurnTimeLeft(time)
end

function ResetTurnTime()
  SetTurnTimeLeft(tTime)
  tTime = -1
end

function PutCrate(i)
  if i > crateNum[difficulty] then
    return
  end
  if difficulty == 1 then
    crates[1] = SpawnFakeAmmoCrate(targXdif1[i], targYdif1[i], false, false)
  else
    crates[1] = SpawnFakeAmmoCrate(targXdif2[i], targYdif2[i], false, false)
  end
end

function PutTargets(i)
  targets[1] = AddGear(targetPosX[i][1], targetPosY[i][1], gtTarget, 0, 0, 0, 0)
  targets[2] = AddGear(targetPosX[i][2], targetPosY[i][2], gtTarget, 0, 0, 0, 0)
  targets[3] = AddGear(targetPosX[i][3], targetPosY[i][3], gtTarget, 0, 0, 0, 0)
end

function FinishThem()
  SetHealth(elderh, 0)
  SetHealth(youngh, 0)
  SetHealth(princess, 0)
end
-----------------------------Main Functions----------------------------

function onGameInit()
	Seed = 69
	GameFlags = gfInfAttack + gfSolidLand + gfDisableWind
	TurnTime = 100000
	CaseFreq = 0
	MinesNum = 0
	MinesTime = 3000
	Explosives = 0
	Delay = 10
	Map = "A_Classic_Fairytale_first_blood"
	Theme = "Nature"


	AddTeam(loc("Natives"), -2, "Bone", "Island", "HillBilly", "cm_birdy")
	youngh = AddHog(loc("Leaks A Lot"), 0, 100, "Rambo")
  elderh = AddHog(loc("Righteous Beard"), 0, 99, "IndianChief")
  princess = AddHog(loc("Fell From Heaven"), 0, 300, "tiara")
  AnimSetGearPosition(princess, 1911, 1361)
  HogTurnLeft(princess, true)
  AnimSetGearPosition(elderh, 2667, 1208)
  HogTurnLeft(elderh, true)
  AnimSetGearPosition(youngh, 1862, 1362)
  HogTurnLeft(youngh, false)

  AddTeam(loc("Cannibals"), -1, "skull", "Island", "Pirate","cm_vampire")
  cannibal = AddHog(loc("Brainiac"), 0, 5, "Zombi")
  AnimSetGearPosition(cannibal, 525, 1256)
  HogTurnLeft(cannibal, false)

  AnimInit()
  AnimationSetup()
end

function onGameStart()
  progress = tonumber(GetCampaignVar("Progress"))
  SetTurnTimeLeft(MAX_TURN_TIME)
  FollowGear(youngh)
	ShowMission(loc("A Classic Fairytale"), loc("First Blood"), loc("Finish your training|Hint: Animations can be skipped with the [Precise] key."), -amSkip, 0)
  HideHog(cannibal)

  AddAnim(startDialogue)
  princessFace = "Right"
  AddEvent(CheckNeedToTurn, {princess}, DoNeedToTurn, {princess}, 1)
  AddEvent(CheckNeedToTurn, {elderh}, DoNeedToTurn, {elderh}, 1)
  AddEvent(CheckDamage, {}, DoOnDamage, {}, 1)
  AddEvent(CheckDeath, {}, DoDeath, {}, 0)
  AddEvent(CheckDamagedOthers, {}, DoOnDamagedOthers, {}, 1)
  AddEvent(CheckKilledOthers, {}, DoKilledOthers, {}, 0)
  AddEvent(CheckMovedUntilJump, {}, DoMovedUntilJump, {}, 0)
end

function onGameTick()
  AnimUnWait()
  if ShowAnimation() == false then
    return
  end
  ExecuteAfterAnimations()
  CheckEvents()
end

local choiceDialogTimer = 0
function onGameTick20()
  -- Make sure the choice dialog never disappears while it is active
  if difficultyChoice then
    choiceDialogTimer = choiceDialogTimer + 20
    if choiceDialogTimer > 9990000 then
      ChoiceDialog()
      choiceDialogTimer = 0
    end
  end
end

function onGearDelete(gear)
  if gear == ropeCrate1 then
    rope1Taken = true
  elseif gear == paraCrate then
    paraTaken = true
  elseif gear == ropeCrate2 then
    rope2Taken = true
    rope2InProgress = false
  elseif gear == ropeCrate3 then
    rope3Taken = true
  elseif gear == crates[1] then
    -- Play sound if challenge crate (fake crate) collected
    if band(GetGearMessage(gear), gmDestroy) ~= 0 then
      PlaySound(sndShotgunReload)
    end

    -- Update crate challenge
    if deleteCrate == true then
      deleteCrate = false
    elseif challengeFailed == false then
      crates[1] = nil
      cratesCollected = cratesCollected + 1
      PutCrate(cratesCollected + 1)
    end
  elseif gear == punchCrate then
    punchTaken = true
  elseif gear == desertCrate then
    desertTaken = true
  elseif GetGearType(gear) == gtTarget then
    i = 1
    while targets[i] ~= gear do
      i = i + 1
    end
    targets[i] = nil
    targetsDestroyed = targetsDestroyed + 1
  elseif gear == cannibal then
    cannibalKilled = true
  elseif gear == princess then
    princessKilled = true
  elseif gear == elderh then
    elderKilled = true
  elseif gear == youngh then
    youngKilled = true
  end
end

function onAmmoStoreInit()
  SetAmmo(amWhip, 0, 0, 0, 8)
  SetAmmo(amBaseballBat, 0, 0, 0, 8)
  SetAmmo(amHammer, 0, 0, 0, 8)
end

function onNewTurn()
  if CurrentHedgehog == cannibal and cannibalVisible == false then
    RestoreHog(cannibal)
  end
  SwitchHog(youngh)
  FollowGear(youngh)
  SetTurnTimeLeft(MAX_TURN_TIME)
end

function onGearDamage(gear, damage)
  if gear == youngh then
    youngdamaged = true
    tTime = TurnTimeLeft
  elseif gear == princess then
    princessDamaged = true
    tTime = TurnTimeLeft
  elseif gear == elderh then
    elderDamaged = true
    tTime = TurnTimeLeft
  elseif gear == cannibal then
    cannibalVisible = true
    cannibalDamaged = true
  end
end

function onPrecise()
  if GameTime > 2000 then
    SetAnimSkip(true)
  end
end

function onLeft()
  if difficultyChoice == true then
    if difficulty ~= 1 then
       difficulty = 1
    else
       difficulty = 2
    end
    PlaySound(sndSwitchHog)
    ChoiceDialog()
  end
end
onRight = onLeft

function onAttack()
  if difficultyChoice == true then
    DoChoice()
  end
end